📄 dma.c
字号:
NULL);
Status = ObCreateObject(
KernelMode,
IoAdapterObjectType,
&ObjectAttributes,
KernelMode,
NULL,
sizeof(ADAPTER_OBJECT),
0,
0,
(PVOID)&AdapterObject);
if (!NT_SUCCESS(Status))
return NULL;
Status = ObReferenceObjectByPointer(
AdapterObject,
FILE_READ_DATA | FILE_WRITE_DATA,
IoAdapterObjectType,
KernelMode);
if (!NT_SUCCESS(Status))
return NULL;
RtlZeroMemory(AdapterObject, sizeof(ADAPTER_OBJECT));
Status = ObInsertObject(
AdapterObject,
NULL,
FILE_READ_DATA | FILE_WRITE_DATA,
0,
NULL,
&Handle);
if (!NT_SUCCESS(Status))
return NULL;
ZwClose(Handle);
AdapterObject->DmaHeader.Version = (USHORT)DeviceDescription->Version;
AdapterObject->DmaHeader.Size = sizeof(ADAPTER_OBJECT);
AdapterObject->DmaHeader.DmaOperations = &HalpDmaOperations;
AdapterObject->MapRegistersPerChannel = 1;
AdapterObject->Dma32BitAddresses = DeviceDescription->Dma32BitAddresses;
AdapterObject->ChannelNumber = 0xFF;
AdapterObject->MasterAdapter = HalpMasterAdapter;
KeInitializeDeviceQueue(&AdapterObject->ChannelWaitQueue);
return AdapterObject;
}
/**
* @name HalpDmaInitializeEisaAdapter
*
* Setup DMA modes and extended modes for (E)ISA DMA adapter object.
*/
BOOLEAN STDCALL
HalpDmaInitializeEisaAdapter(
PADAPTER_OBJECT AdapterObject,
PDEVICE_DESCRIPTION DeviceDescription)
{
UCHAR Controller;
DMA_MODE DmaMode = {{0 }};
DMA_EXTENDED_MODE ExtendedMode = {{ 0 }};
PVOID AdapterBaseVa;
Controller = (DeviceDescription->DmaChannel & 4) ? 2 : 1;
if (Controller == 1)
AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController1);
else
AdapterBaseVa = (PVOID)FIELD_OFFSET(EISA_CONTROL, DmaController2);
AdapterObject->AdapterNumber = Controller;
AdapterObject->ChannelNumber = (UCHAR)(DeviceDescription->DmaChannel & 3);
AdapterObject->PagePort = (PUCHAR)HalpEisaPortPage[DeviceDescription->DmaChannel];
AdapterObject->Width16Bits = FALSE;
AdapterObject->AdapterBaseVa = AdapterBaseVa;
if (HalpEisaDma)
{
ExtendedMode.ChannelNumber = AdapterObject->ChannelNumber;
switch (DeviceDescription->DmaSpeed)
{
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -