dma.c
字号:
{
case Compatible: ExtendedMode.TimingMode = COMPATIBLE_TIMING; break;
case TypeA: ExtendedMode.TimingMode = TYPE_A_TIMING; break;
case TypeB: ExtendedMode.TimingMode = TYPE_B_TIMING; break;
case TypeC: ExtendedMode.TimingMode = BURST_TIMING; break;
default:
return FALSE;
}
switch (DeviceDescription->DmaWidth)
{
case Width8Bits: ExtendedMode.TransferSize = B_8BITS; break;
case Width16Bits: ExtendedMode.TransferSize = B_16BITS; break;
case Width32Bits: ExtendedMode.TransferSize = B_32BITS; break;
default:
return FALSE;
}
if (Controller == 1)
WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode1),
ExtendedMode.Byte);
else
WRITE_PORT_UCHAR((PUCHAR)FIELD_OFFSET(EISA_CONTROL, DmaExtendedMode2),
ExtendedMode.Byte);
}
else
{
/*
* Validate setup for non-busmaster DMA adapter. Secondary controller
* supports only 16-bit transfers and main controller supports only
* 8-bit transfers. Anything else is invalid.
*/
if (!DeviceDescription->Master)
{
if (Controller == 2 && DeviceDescription->DmaWidth == Width16Bits)
AdapterObject->Width16Bits = TRUE;
else if (Controller != 1 || DeviceDescription->DmaWidth != Width8Bits)
return FALSE;
}
}
DmaMode.Channel = AdapterObject->ChannelNumber;
DmaMode.AutoInitialize = DeviceDescription->AutoInitialize;
/*
* Set the DMA request mode.
*
* For (E)ISA bus master devices just unmask (enable) the DMA channel
* and set it to cascade mode. Otherwise just select the right one
* bases on the passed device description.
*/
if (DeviceDescription->Master)
{
DmaMode.RequestMode = CASCADE_REQUEST_MODE;
if (Controller == 1)
{
/* Set the Request Data */
WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->Mode,
DmaMode.Byte);
/* Unmask DMA Channel */
WRITE_PORT_UCHAR(&((PDMA1_CONTROL)AdapterBaseVa)->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
} else {
/* Set the Request Data */
WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->Mode,
DmaMode.Byte);
/* Unmask DMA Channel */
WRITE_PORT_UCHAR(&((PDMA2_CONTROL)AdapterBaseVa)->SingleMask,
AdapterObject->ChannelNumber | DMA_CLEARMASK);
}
}
else
{
if (DeviceDescription->DemandMode)
DmaMode.RequestMode = DEMAND_REQUEST_MODE;
else
DmaMode.RequestMode = SINGLE_REQUEST_MODE;
}
AdapterObject->AdapterMode = DmaMode;
return TRUE;
}
/**
* @name HalGetAdapter
*
* Allocate an adapter object for DMA device.
*
* @param DeviceDescription
* Structure describing the attributes of the device.
* @param NumberOfMapRegisters
* On return filled with the maximum number of map registers the
* device driver can allocate for DMA transfer operations.
*
* @return The DMA adapter on success, NULL otherwise.
*
* @implemented
*/
PADAPTER_OBJECT STDCALL
HalGetAdapter(
PDEVICE_DESCRIPTION DeviceDescription,
PULONG NumberOfMapRegisters)
{
PADAPTER_OBJECT AdapterObject = NULL;
PADAPTER_OBJECT MasterAdapter;
BOOLEAN EisaAdapter;
ULONG MapRegisters;
ULONG MaximumLength;
/* Validate parameters in device description */
if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION2)
return NULL;
/*
* See if we're going to use ISA/EISA DMA adapter. These adapters are
* special since they're reused.
*
* Also note that we check for channel number since there are only 8 DMA
* channels on ISA, so any request above this requires new adapter.
*/
if (DeviceDescription->InterfaceType == Isa || !DeviceDescription->Master)
{
if (DeviceDescription->InterfaceType == Isa &&
DeviceDescription->DmaChannel >= 8)
EisaAdapter = FALSE;
else
EisaAdapter = TRUE;
}
else
{
EisaAdapter = FALSE;
}
/*
* Disallow creating adapter for ISA/EISA DMA channel 4 since it's used
* for cascading the controllers and it's not available for software use.
*/
if (EisaAdapter && DeviceDescription->DmaChannel == 4)
return NULL;
/*
* Calculate the number of map registers.
*
* - For EISA and PCI scatter/gather no map registers are needed.
* - For ISA slave scatter/gather one map register is needed.
* - For all other cases the number of map registers depends on
* DeviceDescription->MaximumLength.
*/
MaximumLength = DeviceDescription->MaximumLength & MAXLONG;
if (DeviceDescription->ScatterGather &&
(DeviceDescription->InterfaceType == Eisa ||
DeviceDescription->InterfaceType == PCIBus))
{
MapRegisters = 0;
}
else if (DeviceDescription->ScatterGather &&
!DeviceDescription->Master)
{
MapRegisters = 1;
}
else
{
/*
* In the equation below the additional map register added by
* the "+1" accounts for the case when a transfer does not start
* at a page-aligned address.
*/
MapRegisters = BYTES_TO_PAGES(MaximumLength) + 1;
if (MapRegisters > 16)
MapRegisters = 16;
}
/*
* Acquire the DMA lock that is used to protect adapter lists and
* EISA adapter array.
*/
KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
FALSE, NULL);
/*
* Now we must get ahold of the adapter object. For first eight ISA/EISA
* channels there are static adapter objects that are reused and updated
* on succesive HalGetAdapter calls. In other cases a new adapter object
* is always created and it's to the DMA adapter list (HalpDmaAdapterList).
*/
if (EisaAdapter)
{
AdapterObject = HalpEisaAdapter[DeviceDescription->DmaChannel];
if (AdapterObject != NULL)
{
if (AdapterObject->NeedsMapRegisters &&
MapRegisters > AdapterObject->MapRegistersPerChannel)
AdapterObject->MapRegistersPerChannel = MapRegisters;
}
}
if (AdapterObject == NULL)
{
AdapterObject = HalpDmaAllocateChildAdapter(
MapRegisters, DeviceDescription);
if (AdapterObject == NULL)
{
KeSetEvent(&HalpDmaLock, 0, 0);
return NULL;
}
if (EisaAdapter)
{
HalpEisaAdapter[DeviceDescription->DmaChannel] = AdapterObject;
}
if (MapRegisters > 0)
{
AdapterObject->NeedsMapRegisters = TRUE;
MasterAdapter = HalpMasterAdapter;
AdapterObject->MapRegistersPerChannel = MapRegisters;
/*
* FIXME: Verify that the following makes sense. Actually
* MasterAdapter->NumberOfMapRegisters contains even the number
* of gaps, so this will not work correctly all the time. It
* doesn't matter much since it's only optimization to avoid
* queuing work items in HalAllocateAdapterChannel.
*/
MasterAdapter->CommittedMapRegisters += MapRegisters;
if (MasterAdapter->CommittedMapRegisters > MasterAdapter->NumberOfMapRegisters)
HalpGrowMapBuffers(MasterAdapter, 0x10000);
}
else
{
AdapterObject->NeedsMapRegisters = FALSE;
if (DeviceDescription->Master)
AdapterObject->MapRegistersPerChannel = BYTES_TO_PAGES(MaximumLength) + 1;
else
AdapterObject->MapRegistersPerChannel = 1;
}
}
if (!EisaAdapter)
InsertTailList(&HalpDmaAdapterList, &AdapterObject->AdapterList);
/*
* Release the DMA lock. HalpDmaAdapterList and HalpEisaAdapter will
* no longer be touched, so we don't need it.
*/
KeSetEvent(&HalpDmaLock, 0, 0);
/*
* Setup the values in the adapter object that are common for all
* types of buses.
*/
if (DeviceDescription->Version >= DEVICE_DESCRIPTION_VERSION1)
AdapterObject->IgnoreCount = DeviceDescription->IgnoreCount;
else
AdapterObject->IgnoreCount = 0;
AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
AdapterObject->Dma64BitAddresses = DeviceDescription->Dma64BitAddresses;
AdapterObject->ScatterGather = DeviceDescription->ScatterGather;
AdapterObject->MasterDevice = DeviceDescription->Master;
*NumberOfMapRegisters = AdapterObject->MapRegistersPerChannel;
/*
* For non-(E)ISA adapters we have already done all the work. On the
* other hand for (E)ISA adapters we must still setup the DMA modes
* and prepare the controller.
*/
if (EisaAdapter)
{
if (!HalpDmaInitializeEisaAdapter(AdapterObject, DeviceDescription))
{
ObfDereferenceObject(AdapterObject);
return NULL;
}
}
return AdapterObject;
}
/**
* @name HalpGetDmaAdapter
*
* Internal routine to allocate PnP DMA adapter object. It's exported through
* HalDispatchTable and used by IoGetDmaAdapter.
*
* @see HalGetAdapter
*/
PDMA_ADAPTER STDCALL
HalpGetDmaAdapter(
IN PVOID Context,
IN PDEVICE_DESCRIPTION DeviceDescription,
OUT PULONG NumberOfMapRegisters)
{
return &HalGetAdapter(DeviceDescription, NumberOfMapRegisters)->DmaHeader;
}
/**
* @name HalPutDmaAdapter
*
* Internal routine to free DMA adapter and resources for reuse. It's exported
* using the DMA_OPERATIONS interface by HalGetAdapter.
*
* @see HalGetAdapter
*/
VOID STDCALL
HalPutDmaAdapter(
PADAPTER_OBJECT AdapterObject)
{
if (AdapterObject->ChannelNumber == 0xFF)
{
KeWaitForSingleObject(&HalpDmaLock, Executive, KernelMode,
FALSE, NULL);
RemoveEntryList(&AdapterObject->AdapterList);
KeSetEvent(&HalpDmaLock, 0, 0);
}
ObfDereferenceObject(AdapterObject);
}
/**
* @name HalAllocateCommonBuffer
*
* Allocates memory that is visible to both the processor(s) and the DMA
* device.
*
* @param AdapterObject
* Adapter object representing the bus master or system dma controller.
* @param Length
* Number of bytes to allocate.
* @param LogicalAddress
* Logical address the driver can use to access the buffer.
* @param CacheEnabled
* Specifies if the memory can be cached.
*
* @return The base virtual address of the memory allocated or NULL on failure.
*
* @remarks
* On real NT x86 systems the CacheEnabled parameter is ignored, we honour
* it. If it proves to cause problems change it.
*
* @see HalFreeCommonBuffer
*
* @implemented
*/
PVOID STDCALL
HalAllocateCommonBuffer(
PADAPTER_OBJECT AdapterObject,
ULONG Length,
PPHYSICAL_ADDRESS LogicalAddress,
BOOLEAN CacheEnabled)
{
PHYSICAL_ADDRESS LowestAcceptableAddress;
PHYSICAL_ADDRESS HighestAcceptableAddress;
PHYSICAL_ADDRESS BoundryAddressMultiple;
PVOID VirtualAddress;
LowestAcceptableAddress.QuadPart = 0;
HighestAcceptableAddress =
HalpGetAdapterMaximumPhysicalAddress(AdapterObject);
BoundryAddressMultiple.QuadPart = 0;
/*
* For bus-master DMA devices the buffer mustn't cross 4Gb boundary. For
* slave DMA devices the 64Kb boundary mustn't be crossed since the
* controller wouldn't be able to handle it.
*/
if (AdapterObject->MasterDevice)
BoundryAddressMultiple.HighPart = 1;
else
BoundryAddressMultiple.LowPart = 0x10000;
VirtualAddress = MmAllocateContiguousMemorySpecifyCache(
Length, LowestAcceptableAddress, HighestAcceptableAddress,
BoundryAddressMultiple, CacheEnabled ? MmCached : MmNonCached);
if (VirtualAddress == NULL)
return NULL;
*LogicalAddress = MmGetPhysicalAddress(VirtualAddress);
return VirtualAddress;
}
/**
* @name HalFreeCommonBuffer
*
* Free common buffer allocated with HalAllocateCommonBuffer.
*
* @see HalAllocateCommonBuffer
*
* @implemented
*/
VOID STDCALL
HalFreeCommonBuffer(
PADAPTER_OBJECT AdapterObject,
ULONG Length,
PHYSICAL_ADDRESS LogicalAddress,
PVOID VirtualAddress,
BOOLEAN CacheEnabled)
{
MmFreeContiguousMemory(VirtualAddress);
}
/**
* @name HalpDmaGetDmaAlignment
*
* Internal routine to return the DMA alignment requirement. It's exported
* using the DMA_OPERATIONS interface by HalGetAdapter.
*
* @see HalGetAdapter
*/
ULONG STDCALL
HalpDmaGetDmaAlignment(
PADAPTER_OBJECT AdapterObject)
{
return 1;
}
/*
* @name HalReadDmaCounter
*
* Read DMA operation progress counter.
*
* @implemented
*/
ULONG STDCALL
HalReadDmaCounter(
PADAPTER_OBJECT AdapterObject)
{
KIRQL OldIrql;
ULONG Count, OldCount;
ASSERT(!AdapterObject->MasterDevice);
/*
* Acquire the master adapter lock since we're going to mess with the
* system DMA controller registers and we really don't want anyone
* to do the same at the same time.
*/
KeAcquireSpinLock(&AdapterObject->MasterAdapter->SpinLock, &OldIrql);
/* Send the request to the specific controller. */
if (AdapterObject->AdapterNumber == 1)
{
PDMA1_CONTROL DmaControl1 = AdapterObject->AdapterBaseVa;
Count = 0xffff00;
do
{
OldCount = Count;
/* Send Reset */
WRITE_PORT_UCHAR(&DmaControl1->ClearBytePointer, 0);
/* Read Count */
Count = READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount);
Count |= READ_PORT_UCHAR(&DmaControl1->DmaAddressCount
[AdapterObject->ChannelNumber].DmaBaseCount) << 8;
}
while (0xffff00 & (OldCount ^ Count));
}
else
{
PDMA2_CONTROL DmaControl2 = AdapterObject->AdapterBaseVa;
Count = 0xffff00;
do
{
OldCount = Count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -