diff options
| author | Adam Shapiro <[email protected]> | 2015-11-17 12:11:14 -0800 |
|---|---|---|
| committer | Adam Shapiro <[email protected]> | 2015-11-17 12:11:14 -0800 |
| commit | 5b815f85ef86b2c2522dbd79e9b1b900f8fb77e4 (patch) | |
| tree | 37a66ba8dadc5ad5d04e49d815cd19907ef8805e /general/HalExtensionSample/HalExtSampleDma | |
| parent | 2c9b5b696dc2c396e6ffc9ec721d8085f279a114 (diff) | |
Add New Sample To Git Hub
Adding the new HAL Extension sample to the online repository in the
"General" Category
Diffstat (limited to 'general/HalExtensionSample/HalExtSampleDma')
6 files changed, 1560 insertions, 0 deletions
diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.c b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.c new file mode 100644 index 00000000..3aade318 --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.c @@ -0,0 +1,1253 @@ +/*++ + +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + HalExtSampleDma.c + +Abstract: + + This file implements a HAL Extension Module for the fictitious chDMA + controller. + +Author: + + Cody Hartwig (chartwig) 9-Jun-2011 + +--*/ + +// +// --------------------------------------------------------------------Includes +// + +#include <nthalext.h> + +// +// ---------------------------------------------------------------- Definitions +// + +// +// Disable warnings of features used by the standard headers +// +// Disable warning C4214: nonstandard extension used : bit field types other than int +// Disable warning C4201: nonstandard extension used : nameless struct/union +// Disable warning C4115: named type definition in parentheses +// Disable warning C4127: conditional expression is constant +// Disable warning C4200: zero-sized array in struct/union +// + +#pragma warning(disable:4214 4201 4115 4127 4200) + +// +// Define register set size. +// + +#define CH_DMA_REGISTER_SIZE (0x210) + +// +// Define maximums. +// + +#define CH_DMA_MAX_REQUEST_LINES (32) +#define CH_DMA_MAX_CHANNELS (32) + +#define CONFIGURE_ADD_REQ_CONFIG (0x80000000) + +// +// Define register offsets. +// + +#define CH_DMA_CONTROL (0x00) +#define CH_DMA_STATUS (0x04) +#define CH_DMA_INTERRUPT_MASK (0x08) + +#define CH_DMA_CHAN_CONTROL (0x00) +#define CH_DMA_CHAN_MEM_PTR (0x04) +#define CH_DMA_CHAN_DEV_PTR (0x08) +#define CH_DMA_CHAN_STATUS (0x1c) + +// +// Define device-side bus widths. +// + +#define CH_DMA_WIDTH_8_BIT (0) +#define CH_DMA_WIDTH_16_BIT (1) +#define CH_DMA_WIDTH_32_BIT (2) + +// +// Define transfer burst sizes. +// + +#define CH_DMA_BURST_1_WORD (0) +#define CH_DMA_BURST_2_WORD (1) +#define CH_DMA_BURST_4_WORD (2) +#define CH_DMA_BURST_8_WORD (3) + +// +// Define transfer directions. +// + +#define CH_DMA_DEVICE_WRITE (0) +#define CH_DMA_DEVICE_READ (1) + +// +// ------------------------------------------------------ Data Type Definitions +// + +#pragma pack(push, 1) + +// +// Register Definitions. +// + +typedef struct _CH_DMA_CONTROL_REGISTER { + union { + struct { + ULONG ControllerEnable:1; + ULONG Reserved:31; + }; + ULONG AsUlong; + }; +} CH_DMA_CONTROL_REGISTER, *PCH_DMA_CONTROL_REGISTER; + +typedef struct _CH_DMA_CHAN_CONTROL_REGISTER { + union { + struct { + ULONG ChannelEnable:1; + ULONG InterruptEnable:1; + ULONG DeviceWidth:2; + ULONG BurstSize:2; + ULONG FlowControl:1; + ULONG Loop:1; + ULONG RequestLine:5; + ULONG ReadFromDevice:1; + ULONG Reserved:2; + ULONG Length:16; + }; + ULONG AsUlong; + }; +} CH_DMA_CHAN_CONTROL_REGISTER, *PCH_DMA_CHAN_CONTROL_REGISTER; + +typedef struct _CH_DMA_CHAN_STATUS_REGISTER { + union { + struct { + ULONG Busy:1; + ULONG Reserved:15; + ULONG BytesTransferred:16; + }; + ULONG AsUlong; + }; +} CH_DMA_CHAN_STATUS_REGISTER, *PCH_DMA_CHAN_STATUS_REGISTER; + +// +// CSRT resource descriptor types for chDMA. +// + +typedef struct _CH_DMA_ADD_REQ_LINE_CONFIG { + ULONG RequestLine; + CH_DMA_CHAN_CONTROL_REGISTER Ctrl; +} CH_DMA_ADD_REQ_LINE_CONFIG, *PCH_DMA_ADD_REQ_LINE_CONFIG; + +typedef struct _RD_DMA_CONTROLLER { + CSRT_RESOURCE_DESCRIPTOR_HEADER Header; + ULONGLONG BasePhysicalAddress; + ULONG ChannelCount; + ULONG MinimumRequestLine; + ULONG MaximumRequestLine; + ULONG InterruptGsi; + BOOLEAN CacheCoherent; + ULONG ReqLineConfigCount; + CH_DMA_ADD_REQ_LINE_CONFIG ReqLineConfigs[ANYSIZE_ARRAY]; +} RD_DMA_CONTROLLER, *PRD_DMA_CONTROLLER; + +// +// Resource description matching chDMA controller described in chdmaReadme.txt: +// +// CH_DMA_CHAN_CONTROL_REGISTER UartControl; +// UartControl.AsUlong = 0; +// UartControl.DeviceWidth = CH_DMA_WIDTH_8_BIT; +// UartControl.BurstSize = CH_DMA_BURST_1_WORD; +// UartControl.FlowControl = 1; +// +// CH_DMA_ADD_REQ_LINE_CONFIG UartConfig = { +// 0x15, +// UartControl +// }; +// +// RD_DMA_CONTROLLER DmaDesc = { +// Header, +// 0x70001000, +// 32, +// 0, +// 31, +// 0x27, +// FALSE, +// 1, +// { UartConfig } +// }; +// + +typedef struct _RD_DMA_CHANNEL { + CSRT_RESOURCE_DESCRIPTOR_HEADER Header; + ULONG ChannelNumber; +} RD_DMA_CHANNEL, *PRD_DMA_CHANNEL; + +// +// Resource description matching chDMA channel described in chdmaReadme.txt: +// +// RD_DMA_CHANNEL DmaDesc = { +// Header, +// 0 +// }; +// + +#pragma pack(pop) + +// +// Extension Request line to configuration mapping. +// + +typedef struct _CH_REQ_LINE_CONFIG { + BOOLEAN Valid; + CH_DMA_CHAN_CONTROL_REGISTER Ctrl; +} CH_REQ_LINE_CONFIG, *PCH_REQ_LINE_CONFIG; + +typedef struct _CH_REQ_LINE_CONFIG_TABLE { + CH_REQ_LINE_CONFIG Entries[CH_DMA_MAX_REQUEST_LINES]; +} CH_DMA_REQ_LINE_CONFIG_TABLE, *PCH_DMA_REQ_LINE_CONFIG_TABLE; + +// +// Define extension internal data for the controller and channel. +// + +typedef struct _CH_DMA_CHANNEL { + BOOLEAN Active; + BOOLEAN AutoInit; +} CH_DMA_CHANNEL, *PCH_DMA_CHANNEL; + +typedef struct _CH_DMA_CONTROLLER { + + // + // Virtual and physical base addresses of the controller. + // + + PULONG ControllerBaseVa; + PHYSICAL_ADDRESS ControllerBasePa; + + ULONG ChannelCount; + ULONG MinimumRequestLine; + ULONG MaximumRequestLine; + + // + // Individual channel extension status. + // + + CH_DMA_CHANNEL Channels[CH_DMA_MAX_CHANNELS]; + + // + // Request line to configuration mapping. + // + + CH_DMA_REQ_LINE_CONFIG_TABLE ReqConfig; +} CH_DMA_CONTROLLER, *PCH_DMA_CONTROLLER; + +// +// ----------------------------------------------------------------- Prototypes +// + +VOID +ChInitializeController ( + __in PVOID ControllerContext + ); + +BOOLEAN +ChValidateRequestLineBinding ( + __in PVOID ControllerContext, + __in PDMA_REQUEST_LINE_BINDING_DESCRIPTION BindingDescription + ); + +ULONG +ChQueryMaxFragments ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG MaxFragmentsRequested + ); + +VOID +ChProgramChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG RequestLine, + __in PDMA_SCATTER_GATHER_LIST MemoryAddresses, + __in PHYSICAL_ADDRESS DeviceAddress, + __in BOOLEAN WriteToDevice, + __in BOOLEAN LoopTransfer + ); + +BOOLEAN +ChCancelTransfer ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ); + +NTSTATUS +ChConfigureChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG FunctionNumber, + __in PVOID Context + ); + +VOID +ChFlushChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ); + +_Success_(return != FALSE) +BOOLEAN +ChHandleInterrupt ( + __in PVOID ControllerContext, + __out PULONG ChannelNumber, + __out PDMA_INTERRUPT_TYPE InterruptType + ); + +ULONG +ChReadDmaCounter ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ); + +// +// -------------------------------------------------------------------- Globals +// + +DMA_FUNCTION_TABLE ChFunctionTable = +{ + ChInitializeController, + ChValidateRequestLineBinding, + ChQueryMaxFragments, + ChProgramChannel, + ChConfigureChannel, + ChFlushChannel, + ChHandleInterrupt, + ChReadDmaCounter, + NULL, /* ReportCommonBuffer */ + ChCancelTransfer +}; + +// +// ------------------------------------------------------------------- Routines +// + +VOID +WriteRegister ( + __in PCH_DMA_CONTROLLER Controller, + __in ULONG RegisterOffset, + __in ULONG Value + ) + +{ + + PULONG Address; + + Address = Controller->ControllerBaseVa; + + // + // Add register offset. Register offset is in bytes. Pointer addition is + // in ULONGs. + // + + Address += (RegisterOffset / 4); + + WRITE_REGISTER_ULONG(Address, Value); +} + +ULONG +ReadRegister ( + __in PCH_DMA_CONTROLLER Controller, + __in ULONG RegisterOffset + ) + +{ + + PULONG Address; + + Address = Controller->ControllerBaseVa; + + // + // Add register offset. Register offset is in bytes. Pointer addition is + // in ULONGs. + // + + Address += (RegisterOffset / 4); + + return READ_REGISTER_ULONG(Address); +} + +VOID +WriteChannelRegister ( + __in PCH_DMA_CONTROLLER Controller, + __in ULONG ChannelNumber, + __in ULONG RegisterOffset, + __in ULONG Value + ) + +{ + PULONG Address; + + Address = Controller->ControllerBaseVa; + + // + // Add channel base offset. + // Register offset is in bytes. Pointer addition is in ULONGs. + // + + Address += (0x10 / 4); + + // + // Add channel number offset. + // + + Address += ((0x10 * ChannelNumber) / 4); + + // + // Add channel register offset. + // + + Address += (RegisterOffset / 4); + + WRITE_REGISTER_ULONG(Address, Value); +} + +ULONG +ReadChannelRegister ( + __in PCH_DMA_CONTROLLER Controller, + __in ULONG ChannelNumber, + __in ULONG RegisterOffset + ) + +{ + + PULONG Address; + + Address = Controller->ControllerBaseVa; + + // + // Add channel base offset. + // Register offset is in bytes. Pointer addition is in ULONGs. + // + + Address += (0x10 / 4); + + // + // Add channel number offset. + // + + Address += ((0x10 * ChannelNumber) / 4); + + // + // Add channel register offset. + // + + Address += (RegisterOffset / 4); + + return READ_REGISTER_ULONG(Address); +} + +VOID +ChInitializeController ( + __in PVOID ControllerContext + ) + +/*++ + +Routine Description: + + This routine provides an opportunity for DMA controllers to initialize. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internel data. + +Return Value: + + None. + +--*/ + +{ + + CH_DMA_CONTROL_REGISTER CtrlRegister; + PCH_DMA_CONTROLLER Controller; + ULONG Index; + ULONG InterruptMask; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + + // + // Map the controller base iff this is the first call to init (and it is + // therefore not already mapped.) + // + + if (Controller->ControllerBaseVa == NULL) { + Controller->ControllerBaseVa = + (PULONG) HalMapIoSpace(Controller->ControllerBasePa, + PAGE_SIZE, + MmNonCached); + + NT_ASSERT(Controller->ControllerBaseVa != NULL); + } + + if (Controller->ControllerBaseVa == NULL) { + return; + } + + // + // Initialize each channel. + // + + for (Index = 0; Index < Controller->ChannelCount; Index += 1) { + WriteChannelRegister(Controller, Index, CH_DMA_CHAN_CONTROL, 0); + Controller->Channels[Index].Active = FALSE; + Controller->Channels[Index].AutoInit = FALSE; + } + + // + // Enable the DMA controller. + // + + CtrlRegister.AsUlong = 0; + CtrlRegister.ControllerEnable = 1; + WriteRegister(Controller, CH_DMA_CONTROL, CtrlRegister.AsUlong); + + // + // Enable all interrupts. + // + + InterruptMask = (1UL << Controller->ChannelCount) - 1; + WriteRegister(Controller, CH_DMA_INTERRUPT_MASK, InterruptMask); + + return; +} + +BOOLEAN +ChValidateRequestLineBinding ( + __in PVOID ControllerContext, + __in PDMA_REQUEST_LINE_BINDING_DESCRIPTION BindingDescription + ) + +/*++ + +Routine Description: + + This routine queries a DMA controller extension to test the validity of a + request line binding. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + DeviceDescription - Supplies a pointer to the request information. + +Return Value: + + TRUE if the request line binding is valid and supported by the controller. + + FALSE if the binding is invalid. + +Environment: + + PASSIVE_LEVEL. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + if (BindingDescription->ChannelNumber > Controller->ChannelCount) { + return FALSE; + } + + if ((BindingDescription->RequestLine > Controller->MaximumRequestLine) || + (BindingDescription->RequestLine < Controller->MinimumRequestLine)) { + + return FALSE; + } + + return TRUE; +} + +ULONG +ChQueryMaxFragments ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG MaxFragmentsRequested + ) + +/*++ + +Routine Description: + + This routine queries the DMA extension to determine the number of + scatter gather fragments that the next transfer can support. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the number of the channel to program. + + MaxFragmentsRequested - Supplies a hint to the maximum fragments useful to + this transfer. + +Return Value: + + Number of fragments the next transfer on this channel can support. + +--*/ + +{ + + UNREFERENCED_PARAMETER(ControllerContext); + UNREFERENCED_PARAMETER(ChannelNumber); + UNREFERENCED_PARAMETER(MaxFragmentsRequested); + + return 1; +} + +VOID +ChProgramChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG RequestLine, + __in PDMA_SCATTER_GATHER_LIST MemoryAddresses, + __in PHYSICAL_ADDRESS DeviceAddress, + __in BOOLEAN WriteToDevice, + __in BOOLEAN LoopTransfer + ) + +/*++ + +Routine Description: + + This routine programs a DMA controller channel for a specific transfer. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the number of the channel to program. + + RequestLine - Supplies the request line number to program. This request + line number is system-unique (as provided to the HAL during + registration) and must be translated by the extension. + + MemoryAddress - Supplies the address to be programmed into the memory + side of the channel configuration. + + DeviceAddress - Supplies the address to be programmed into the device + side of the channel configuration. + + WriteToDevice - Supplies the direction of the transfer. + + LoopTransfer - Supplies whether AutoInitialize has been set in the + adapter making this request. + +Return Value: + + None. + +--*/ + +{ + + CH_DMA_CHAN_CONTROL_REGISTER Ctrl; + PCH_DMA_CONTROLLER Controller; + ULONG DevPtr; + ULONG MemPtr; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + Controller->Channels[ChannelNumber].Active = TRUE; + + // + // If this request line exists in the request line config table, use + // those values. Otherwise, use the reset values. + // + + Ctrl.AsUlong = 0; + if (Controller->ReqConfig.Entries[RequestLine].Valid != 0) { + Ctrl.AsUlong = Controller->ReqConfig.Entries[RequestLine].Ctrl.AsUlong; + } + + Ctrl.ChannelEnable = 1; + Ctrl.InterruptEnable = 1; + Ctrl.Loop = (LoopTransfer == FALSE) ? 0 : 1; + Ctrl.ReadFromDevice = (WriteToDevice == FALSE) ? 1 : 0; + + // + // Request lines numbers reported by BIOS may be offset to make them + // globally unique. Request lines on the controller are based at 0. + // + + Ctrl.RequestLine = RequestLine - Controller->MinimumRequestLine; + Ctrl.Length = MemoryAddresses->Elements[0].Length; + + DevPtr = DeviceAddress.LowPart; + MemPtr = MemoryAddresses->Elements[0].Address.LowPart; + + WriteChannelRegister(Controller, + ChannelNumber, + CH_DMA_CHAN_MEM_PTR, + MemPtr); + + WriteChannelRegister(Controller, + ChannelNumber, + CH_DMA_CHAN_DEV_PTR, + DevPtr); + + // + // Channel control is written last as it will enable the channel. + // + + WriteChannelRegister(Controller, + ChannelNumber, + CH_DMA_CHAN_CONTROL, + Ctrl.AsUlong); +} + +BOOLEAN +ChCancelTransfer ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ) + +/*++ + +Routine Description: + + This routine must disable the selected channel. The channel must not be + capable of interrupting for this transfer after being cleared in this way. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the channel number. + +Return Value: + + FALSE if the channel is already idle or if the channel is already asserting + an interrupt. TRUE is the channel is active and no interrupt is asserted. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + ULONG StatusRegister; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + + // + // If the channel is not active (because the interrupt already fired or + // because the channel was never programmed, return immediately. + // + + if (Controller->Channels[ChannelNumber].Active == FALSE) { + return FALSE; + } + + // + // Disable the channel. + // + + WriteChannelRegister(Controller, ChannelNumber, CH_DMA_CHAN_CONTROL, 0); + + // + // If an interrupt is already pending on the channel, do nothing. The + // normal interrupt path will complete it. If an interrupt is not pending + // then this was successfully cancelled. In that case, mark the channel + // inactive and return TRUE. + // + + StatusRegister = ReadRegister(Controller, CH_DMA_STATUS); + if ((StatusRegister & (1UL << ChannelNumber)) != 0) { + return FALSE; + + } else { + Controller->Channels[ChannelNumber].Active = FALSE; + return TRUE; + } +} + +NTSTATUS +AddReqLineConfig ( + __in PCH_DMA_CONTROLLER Controller, + __in PCH_DMA_ADD_REQ_LINE_CONFIG Config + ) + +/*++ + +Routine Description: + + This routine updates the request line configuration table in the + extension's internal data for this controller. + +Arguments: + + Controller - Supplies a pointer to the internal data for the controller. + + Config - Supplies a pointer to the configuration to modify. + +Return Value: + + STATUS_INVALID_PARAMETER if the request line is invalid. + Else, STATUS_SUCCESS. + +--*/ + +{ + + ULONG RequestLine; + + RequestLine = Config->RequestLine; + if ((RequestLine < Controller->MinimumRequestLine) || + (RequestLine > Controller->MaximumRequestLine)) { + + return STATUS_INVALID_PARAMETER; + } + + Controller->ReqConfig.Entries[RequestLine].Ctrl.AsUlong = + Config->Ctrl.AsUlong; + + return STATUS_SUCCESS; +} + +NTSTATUS +ChConfigureChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber, + __in ULONG FunctionNumber, + __in PVOID Context + ) + +/*++ + +Routine Description: + + This routine configures the channel for a DMA extension specific operation. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the channel to configure. + + FunctionNumber - Supplies the ID of the operation to perform. + + Context - Supplies parameters for this operation. + +Return Value: + + NTSTATUS code. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(ChannelNumber); + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + switch (FunctionNumber) { + case CONFIGURE_ADD_REQ_CONFIG: + Status = AddReqLineConfig(Controller, + (PCH_DMA_ADD_REQ_LINE_CONFIG)Context); + + break; + default: + Status = STATUS_NOT_IMPLEMENTED; + } + + return Status; +} + +VOID +ChFlushChannel ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ) + +/*++ + +Routine Description: + + This routine flushes a previous transfer from a channel and returns the + channel to a state ready for the next ProgramChannel call. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the channel to flush. + +Return Value: + + None. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + WriteChannelRegister(Controller, ChannelNumber, CH_DMA_CHAN_CONTROL, 0); +} + +_Success_(return != FALSE) +BOOLEAN +ChHandleInterrupt ( + __in PVOID ControllerContext, + __out PULONG ChannelNumber, + __out PDMA_INTERRUPT_TYPE InterruptType + ) + +/*++ + +Routine Description: + + This routine probes a controller for interrupts, clears any interrupts + found, fills in channel and interrupt type information. This routine + will be called repeatedly until FALSE is returned. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies a placeholder for the extension to fill in which + channel is interrupting. + + InterruptType - Supplies a placeholder for the extension to fill in the + interrupt type. + +Return Value: + + TRUE if an interrupt was found on this controller. + + FALSE otherwise. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + ULONG Index; + ULONG StatusRegister; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + StatusRegister = ReadRegister(Controller, CH_DMA_STATUS); + for (Index = 0; Index < Controller->ChannelCount; Index += 1) { + if ((StatusRegister & (1UL << Index)) != 0) { + *ChannelNumber = Index; + *InterruptType = InterruptTypeCompletion; + WriteRegister(Controller, CH_DMA_STATUS, (1UL << Index)); + + // + // If the channel is not marked as active, then this interrupt + // is spurious. Probably this is the result of a transfer being + // cancelled. + // + + if (Controller->Channels[Index].Active == FALSE) { + continue; + } + + // + // If the channel is not in autoinitialize mode, is it inactive now. + // If the channel is in autoinitialize, then it will remain active + // until it receives a cancel. + // + + if (Controller->Channels[Index].AutoInit == FALSE) { + Controller->Channels[Index].Active = FALSE; + } + + return TRUE; + } + } + + return FALSE; +} + +ULONG ChReadDmaCounter ( + __in PVOID ControllerContext, + __in ULONG ChannelNumber + ) + +/*++ + +Routine Description: + + This routine determines how many bytes remain to be transferred on the + given channel. If the current transfer is set to loop, this routine + will return the number of bytes remaining in the current iteration. + +Arguments: + + ControllerContext - Supplies a pointer to the controller's internal data. + + ChannelNumber - Supplies the channel number. + +Return Value: + + Returns the number of bytes remaining to be transferred on the given + channel. + +--*/ + +{ + + PCH_DMA_CONTROLLER Controller; + CH_DMA_CHAN_CONTROL_REGISTER Ctrl; + CH_DMA_CHAN_STATUS_REGISTER StatusReg; + + Controller = (PCH_DMA_CONTROLLER)ControllerContext; + Ctrl.AsUlong = ReadChannelRegister(Controller, + ChannelNumber, + CH_DMA_CHAN_CONTROL); + + StatusReg.AsUlong = ReadChannelRegister(Controller, + ChannelNumber, + CH_DMA_CHAN_STATUS); + + return (Ctrl.Length - StatusReg.BytesTransferred); +} + +NTSTATUS +RegisterDmaController ( + __in ULONG Handle, + __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup, + __in PCSRT_RESOURCE_DESCRIPTOR_HEADER ResourceDescriptor, + __out PULONG ControllerId + ) + +/*++ + +Routine Description: + + This routine takes a DMA resource descriptor with subtype controller. + The controller is then registered with the HAL. + +Arguments: + + Handle - Supplies handle passed to extension. + + ResourceGroup - Supplies resource group containing this descriptor. + + ResourceDescrpitor - Supplies the resource descriptor. + + ControllerId - Supplies a placeholder for the controller ID returned from + the HAL after registration. + +Return Value: + + NTSTATUS Value. + +--*/ + +{ + + PCH_REQ_LINE_CONFIG ConfigEntry; + PCH_REQ_LINE_CONFIG ConfigTableDst; + PCH_DMA_ADD_REQ_LINE_CONFIG ConfigTableSrc; + CH_DMA_CONTROLLER Controller; + PRD_DMA_CONTROLLER DmaDesc; + DMA_INITIALIZATION_BLOCK DmaInitBlock; + ULONG Index; + ULONG RequestLine; + NTSTATUS Status; + + RtlZeroMemory(&Controller, sizeof(CH_DMA_CONTROLLER)); + + DmaDesc = (PRD_DMA_CONTROLLER)ResourceDescriptor; + Controller.ControllerBasePa.QuadPart = DmaDesc->BasePhysicalAddress; + Controller.ChannelCount = DmaDesc->ChannelCount; + Controller.MinimumRequestLine = DmaDesc->MinimumRequestLine; + Controller.MaximumRequestLine = DmaDesc->MaximumRequestLine; + + // + // Build request line configuration mapping table. + // + + ConfigTableDst = &Controller.ReqConfig.Entries[0]; + ConfigTableSrc = &DmaDesc->ReqLineConfigs[0]; + + // + // Verify the supplied configuration description will fit within + // the build maximum. + // + + if (DmaDesc->ReqLineConfigCount >= CH_DMA_MAX_REQUEST_LINES) { + Status = STATUS_INVALID_PARAMETER_1; + goto Exit; + } + + for (Index = 0; Index < DmaDesc->ReqLineConfigCount; Index += 1) { + + RequestLine = ConfigTableSrc[Index].RequestLine; + + // + // Keep PreFast happy that we're assigning within memory bounds + // + + if (RequestLine >= CH_DMA_MAX_REQUEST_LINES) { + Status = STATUS_INVALID_PARAMETER_2; + goto Exit; + } + + ConfigEntry = &ConfigTableDst[RequestLine]; + ConfigEntry->Ctrl.AsUlong = ConfigTableSrc[Index].Ctrl.AsUlong; + ConfigEntry->Valid = TRUE; + } + + INITIALIZE_DMA_HEADER(&DmaInitBlock); + DmaInitBlock.ChannelCount = Controller.ChannelCount; + DmaInitBlock.MinimumTransferUnit = 1; + DmaInitBlock.MinimumRequestLine = Controller.MinimumRequestLine; + DmaInitBlock.MaximumRequestLine = Controller.MaximumRequestLine; + DmaInitBlock.CacheCoherent = DmaDesc->CacheCoherent; + DmaInitBlock.GeneratesInterrupt = TRUE; + DmaInitBlock.InternalData = (PVOID)&Controller; + DmaInitBlock.InternalDataSize = sizeof(CH_DMA_CONTROLLER); + DmaInitBlock.DmaAddressWidth = 32; + DmaInitBlock.Gsi = DmaDesc->InterruptGsi; + DmaInitBlock.InterruptPolarity = InterruptActiveHigh; + DmaInitBlock.InterruptMode = LevelSensitive; + DmaInitBlock.Operations = &ChFunctionTable; + + // + // Register physical address space with the HAL. + // + + HalRegisterPermanentAddressUsage(Controller.ControllerBasePa, + CH_DMA_REGISTER_SIZE); + + // + // Register controller. + // + + Status = RegisterResourceDescriptor(Handle, + ResourceGroup, + ResourceDescriptor, + &DmaInitBlock); + + *ControllerId = DmaInitBlock.ControllerId; + +Exit: + return Status; + +} + +NTSTATUS +RegisterDmaChannel ( + __in ULONG Handle, + __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup, + __in PCSRT_RESOURCE_DESCRIPTOR_HEADER ResourceDescriptor, + __in ULONG ControllerId + ) + +/*++ + +Routine Description: + + This routine takes a DMA resource descriptor with subtype channel. + The channel is then registered with the HAL. + +Arguments: + + Handle - Supplies handle passed to extension. + + ResourceGroup - Supplies resource group containing this descriptor. + + ResourceDescrpitor - Supplies the resource descriptor. + + ControllerId - Supplies the controller ID this channel is registered with. + +Return Value: + + NTSTATUS Value. + +--*/ + +{ + + DMA_CHANNEL_INITIALIZATION_BLOCK DmaChannelInitBlock; + PRD_DMA_CHANNEL DmaDesc; + + NT_ASSERT(ControllerId != 0); + + DmaDesc = (PRD_DMA_CHANNEL)ResourceDescriptor; + INITIALIZE_DMA_CHANNEL_HEADER(&DmaChannelInitBlock); + DmaChannelInitBlock.ControllerId = ControllerId; + DmaChannelInitBlock.GeneratesInterrupt = FALSE; + DmaChannelInitBlock.ChannelNumber = DmaDesc->ChannelNumber; + DmaChannelInitBlock.CommonBufferLength = 0; + + return RegisterResourceDescriptor(Handle, + ResourceGroup, + ResourceDescriptor, + &DmaChannelInitBlock); +} + +NTSTATUS +AddResourceGroup ( + __in ULONG Handle, + __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup + ) + +{ + + ULONG ControllerId; + PCSRT_RESOURCE_DESCRIPTOR_HEADER ResourceDescriptor; + + ResourceDescriptor = NULL; + ControllerId = 0; + for (;;) { + ResourceDescriptor = + GetNextResourceDescriptor(Handle, + ResourceGroup, + ResourceDescriptor, + CSRT_RD_TYPE_DMA, + CSRT_RD_SUBTYPE_ANY, + CSRT_RD_UID_ANY); + + if (ResourceDescriptor == NULL) { + break; + } + + if (ResourceDescriptor->Subtype == CSRT_RD_SUBTYPE_DMA_CONTROLLER) { + RegisterDmaController(Handle, + ResourceGroup, + ResourceDescriptor, + &ControllerId); + + } else if (ResourceDescriptor->Subtype == CSRT_RD_SUBTYPE_DMA_CHANNEL) { + RegisterDmaChannel(Handle, + ResourceGroup, + ResourceDescriptor, + ControllerId); + } else { + + NT_ASSERT(FALSE); + } + } + + return STATUS_SUCCESS; +} diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.def b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.def new file mode 100644 index 00000000..22ecba00 --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.def @@ -0,0 +1,2 @@ +LIBRARY HalExtSampleDma + diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.rc b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.rc new file mode 100644 index 00000000..534afafb --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.rc @@ -0,0 +1,10 @@ +#include "verrsrc.h" +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "HAL Extension Sample - DMA" +#define VER_INTERNALNAME_STR "HalExtSampleDma.DLL" +#define VER_ORIGINALFILENAME_STR "HalExtSampleDma.DLL" + +#include <common.ver> diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj new file mode 100644 index 00000000..4d7b340c --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Arm"> + <Configuration>Debug</Configuration> + <Platform>Arm</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Arm"> + <Configuration>Release</Configuration> + <Platform>Arm</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{7568DCFB-C421-478A-A809-21EF6EC243BE}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Arm</Platform> + <SampleGuid>{03525FA0-7E40-493E-AAB7-D8D73FACBC51}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Arm'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Arm'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Arm'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">HalExtensionInit@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">HalExtensionInit</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">HalExtensionInit@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">HalExtensionInit</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Arm'"> + <TargetName>HalExtSampleDma</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'"> + <TargetName>HalExtSampleDma</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Arm'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /J</AdditionalOptions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);halextlib.lib;libcntpr.lib;bufferoverflowfastfailk.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE -merge:INITCONST=INIT /LARGEADDRESSAWARE</AdditionalOptions> + <ModuleDefinitionFile>HalExtSampleDma.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalOptions>%(AdditionalOptions) /J</AdditionalOptions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);halextlib.lib;libcntpr.lib;bufferoverflowfastfailk.lib</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) -merge:PAGECONST=PAGE -merge:INITCONST=INIT /LARGEADDRESSAWARE</AdditionalOptions> + <ModuleDefinitionFile>HalExtSampleDma.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="HalExtSampleDma.c" /> + <ResourceCompile Include="HalExtSampleDma.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + </ItemGroup> + <ItemGroup> + <None Exclude="@(None)" Include="*.txt;*.htm;*.html" /> + <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" /> + <None Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" /> + </ItemGroup> + <ItemGroup> + <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> +</Project>
\ No newline at end of file diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj.Filters b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj.Filters new file mode 100644 index 00000000..0e78975f --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj.Filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions> + <UniqueIdentifier>{C49AD628-A169-4113-A58C-7869B002B124}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{4066A1BF-4F9E-4F43-B6C3-3DEEDE4A553C}</UniqueIdentifier> + </Filter> + <Filter Include="Resource Files"> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions> + <UniqueIdentifier>{CD82A108-349C-4687-A02C-C816B6A47307}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="HalExtSampleDma.c"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="HalExtSampleDma.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="HalExtSampleDma.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDmaReadme.txt b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDmaReadme.txt new file mode 100644 index 00000000..05e44648 --- /dev/null +++ b/general/HalExtensionSample/HalExtSampleDma/HalExtSampleDmaReadme.txt @@ -0,0 +1,139 @@ +Copyright (c) 2011 Microsoft Corporation + +Author: Cody Hartwig (chartwig) 9-Jun-2011 + +------ + +This document describes the chDMA controller. chDMA is a 32-channel, +32-request line DMA controller for which a sample HAL extension has been +implemented. This document also describes a sample peripheral device and the +configuration required for use with the DMA controller. + +General Controller Information +============================== + +Base Physical Address 0x70001000 +GSI 0x27 +Number of Channels 32 +Number of Request Lines 32 +Cache Coherent No +Supports ReadDmaCounter Yes + + +Register Layout +=============== + +CH_DMA_CONTROL (Offset: 0x00, RW, Reset: 0x00000000) +-------------- + +This register sets controller-wide settings such as controller enable. + +Bit Function +31 Controller Enable: 1-enable, 0-disable +30-0 Reserved + +CH_DMA_STATUS (Offset: 0x04, RW1C, Reset: 0x00000000) +------------- + +This register describes which channels are currently asserting an interrupt. +Interrupts are cleared by writing 1 to the appropriate bit. + +Bit Function +31 Channel 31 interrupt status +30 Channel 30 interrupt status +.. +0 Channel 0 interrupt status + +CH_DMA_INTERRUPT_MASK (Offset: 0x08, RW, Reset: 0x00000000) +--------------------- + +A channel interrupt is unmasked by writing 1 to the corresponding bit in this +register. + +Bit Function +31 Channel 31 interrupt mask +30 Channel 30 interrupt mask +.. +0 Channel 0 interrupt mask + +CH_DMA_CHANNEL_i_CONTROL (Offset: 0x10 + (i * 0x10), RW, Reset:0x00000000) +------------------------ + +This register controls per channel operation of the controller. A transfer +may begin once the enable bit is set. When the enable bit is cleared, the +current burst is finished and the transfer will stop. + +Bit Function +31 Enable +30 Interrupt on completion +29-28 Device Width: + 0b00 - 8-bit + 0b01 - 16-bit + 0b10 - 32-bit + 0b11 - Reserved +27-26 Burst Size: + 0b00 - 1 Word + 0b01 - 2 Word + 0b10 - 4 Word + 0b11 - 8 Word +25 Flow Control: 1-enable, 0-disable +24 Loop: 1-repeat transfer, 0-transfer once +23-19 Request line trigger +18 Transfer Direction: 1-device to mem, 0-mem to device +17-16 Reserved +15-0 Transfer Length + +CH_DMA_CHANNEL_i_MEM_PTR (Offset: 0x14 + (i * 0x10), RW, Reset: 0x00000000) +------------------------ + +This register sets the memory-side address of the transfer. + +Bit Function +31-0 Memory-side address + +CH_DMA_CHANNEL_i_DEV_PTR (Offset: 0x18 + (i * 0x10), RW, Reset: 0x00000000) +------------------------ + +This register sets the device-side address of the transfer. + +Bit Function +31-0 Device-side address + +CH_DMA_CHANNEL_i_STATUS (Offset: 0x1c + (i * 0x10), RO, Reset: 0x00000000) +----------------------- + +This register reports transfer status. + +Bit Function +31 Channel Busy +30-16 Reserved +15-0 Bytes Transferred + + + +Programming Model +================= +Normal operation of the DMA controller is achieved by the following steps: + +1. Enable the controller by writing 0x80000000 to the CH_DMA_CONTROL register. +2. Unmask channel 0's interrupt by or'ing 0x1 with the CH_DMA_INTERRUPT_MASK + register +3. Program the memory-side transfer address into the CH_DMA_CHANNEL_0_MEM_PTR + register. +4. Program the device-side transfer address into the CH_DMA_CHANNEL_0_DEV_PTR + register. +5. Program the CH_DMA_CHANNEL_0_CONTROL register. This enables the channel. + + +Peripheral Information +====================== + +For the purposes of this sample, the chDMA controller is connected to a single +UAART. This UART requires the following DMA controller configuration to +work properly: + +Parameter Value +Bus Width 8 bits +Burst Size 1 Word +Request Line 0x15 +Flow Control Enabled |
