summaryrefslogtreecommitdiff
path: root/general/HalExtensionSample
diff options
context:
space:
mode:
authorAdam Shapiro <[email protected]>2015-11-17 12:11:14 -0800
committerAdam Shapiro <[email protected]>2015-11-17 12:11:14 -0800
commit5b815f85ef86b2c2522dbd79e9b1b900f8fb77e4 (patch)
tree37a66ba8dadc5ad5d04e49d815cd19907ef8805e /general/HalExtensionSample
parent2c9b5b696dc2c396e6ffc9ec721d8085f279a114 (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')
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.c1253
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.def2
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.rc10
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj126
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDma.vcxproj.Filters30
-rw-r--r--general/HalExtensionSample/HalExtSampleDma/HalExtSampleDmaReadme.txt139
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.c763
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.def2
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.rc10
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.vcxproj126
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.vcxproj.Filters30
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.c825
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.def2
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.rc10
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj126
-rw-r--r--general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj.Filters30
-rw-r--r--general/HalExtensionSample/HalExtensionSample.sln45
17 files changed, 3529 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
diff --git a/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.c b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.c
new file mode 100644
index 00000000..f45b32b6
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.c
@@ -0,0 +1,763 @@
+/*++
+
+Copyright (c) 2011 Microsoft Corporation
+
+Module Name:
+
+ HalExtSampleTimers.c
+
+Abstract:
+
+ This file implements a HAL Extension Module for the fictitious EGTimer.
+
+Author:
+
+ Evan Green (evgreen) 8-Jan-2011
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <nthalext.h>
+
+//
+// -------------------------------------------------------------- Specification
+//
+
+//
+// The EGTimer is a fast-access low-latency timer designed for high-performance
+// timekeeping operations. It consists of 4 timers with identical register
+// definitions offset from each other. Each timer contains a 32-bit
+// counter and is capable of generating one-shot or periodic interrupts using
+// a "Reload Value" register. The counter counts up and generates an interrupt
+// once it rolls over from its maximum value of 0xFFFFFFFF to 0 if the
+// interrupt enable bit is set. The counter always runs at a frequency of
+// 10MHz. The register layout of the timer appears below:
+//
+// Offset Register Size
+// 0x00 Timer0_Control 4
+// 0x04 Timer0_ReloadValue 4
+// 0x08 Timer0_CurrentCount 4
+// 0x0C Timer0_InterruptAcknowledge 4
+// 0x10 Timer1_Control 4
+// 0x14 Timer1_ReloadValue 4
+// 0x18 Timer1_CurrentCount 4
+// 0x1C Timer1_InterruptAcknowledge 4
+// 0x20 Timer2_Control 4
+// 0x24 Timer2_ReloadValue 4
+// 0x28 Timer2_CurrentCount 4
+// 0x2C Timer2_InterruptAcknowledge 4
+// 0x30 Timer3_Control 4
+// 0x34 Timer3_ReloadValue 4
+// 0x38 Timer3_CurrentCount 4
+// 0x3C Timer3_InterruptAcknowledge 4
+//
+// Register Descriptions:
+//
+// TimerN_Control - This is a Read/Write register containing a bitfield of
+// control values that govern the timer's operation. The initial value of
+// this register at reset is 0. The defined bits are listed below. 0 should
+// always be written to undefined bits, and will always be read as 0.
+//
+// Bit Function
+// 31-3 Reserved. Read as 0, always write 0 to maintain future
+// compatibility.
+//
+// 2 Periodic. When set to 1, the timer will automatically reload
+// itself with the value in the ReloadValue register.
+// When set to 0, the timer's counter will be disabled by
+// clearing the "Counter Enabled" bit when it overflows
+// from 0xFFFFFFFF to 0.
+//
+// 1 Interrupt Enable. When set to 1, the timer will generate an
+// interrupt when the counter overflows from 0xFFFFFFFF to 0.
+// When set to 0, the timer will not generate an interrupt upon
+// overflow.
+//
+// 0 Counter Enable. When set to 1, the counter is enabled and
+// running. When set to 0, the counter is disable and will not
+// run.
+//
+// TimerN_ReloadValue - This is a Read/Write register containing the value to
+// reload the counter with when the timer is in Periodic mode and overflows
+// from 0xFFFFFFFF to 0. Writing a value to this register also immediately
+// writes the same value to the current count register. The initial value
+// of this register at reset is 0.
+//
+// TimerN_CurrentCount - This is a Read/Write register containg the current
+// value of the counter. This value can be overwritten at any time. It is
+// also overwritten by a write to the ReloadValue register. The initial
+// value of this register at reset is 0.
+//
+// TimerN_InterruptAcknowledge - This is a Read/Write register. On reads, it
+// returns 1 if an interrupt is pending that has yet to be acknowledged.
+// Writing a value of 0 clears the pending interrupt. This initial value of
+// this register at reset is 0.
+//
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// Define the total size of the register block, which is 1 page.
+//
+
+#define EGTIMER_BLOCK_SIZE 0x1000
+
+//
+// Define the size of one timer's registers.
+//
+
+#define EGTIMER_SIZE 0x10
+
+//
+// Define the total number of timers.
+//
+
+#define EGTIMER_COUNT 4
+
+//
+// Define the timer's bit width.
+//
+
+#define EGTIMER_BIT_WIDTH 32
+
+//
+// Define the counter's frequency, in Hertz.
+//
+
+#define EGTIMER_FREQUENCY 10000000
+
+//
+// Define bits for the control register.
+//
+
+#define EGTIMER_CONTROL_ENABLE 0x00000001
+#define EGTIMER_CONTROL_INTERRUPT_ENABLE 0x00000002
+#define EGTIMER_CONTROL_PERIODIC 0x00000004
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+
+//
+// Define the registers and their offsets, in ULONGs.
+//
+
+typedef enum _EGTIMER_REGISTER {
+ EgTimerControl = 0,
+ EgTimerReloadValue = 1,
+ EgTimerCurrentCount = 2,
+ EgTimerInterruptAcknowledge = 3
+} EGTIMER_REGISTER, *PEGTIMER_REGISTER;
+
+//
+// Define the format of the private data structure. The TimerIndex member
+// allows the extension to pass the same functions for all timer an identify
+// which timer is being referred to.
+//
+
+typedef struct _EGTIMER_DATA {
+ ULONG TimerIndex;
+} EGTIMER_DATA, *PEGTIMER_DATA;
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// The following macros are used to read from and write to the timer. The first
+// parameter is the offset from the entire timer block where this timer is
+// found (which timer), and the second parameter is the register to read or
+// write. For the write function, the third parameter is the value to write.
+// READ_REGISTER_ULONG and WRITE_REGISTER_ULONG should always be used to
+// ensure that the proper barriers and flushes are in place for doing direct
+// hardware accesses.
+//
+
+#define READ_EGTIMER(_TimerIndex, _Register) \
+ READ_REGISTER_ULONG((PULONG)((PUCHAR)EgTimerBase + \
+ ((_TimerIndex) * EGTIMER_SIZE)) + (_Register))
+
+#define WRITE_EGTIMER(_TimerIndex, _Register, _Value) \
+ WRITE_REGISTER_ULONG((PULONG)((PUCHAR)EgTimerBase + \
+ ((_TimerIndex) * EGTIMER_SIZE)) + \
+ (_Register), \
+ _Value)
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+NTSTATUS
+EgTimerRegister (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ );
+
+_Function_class_(TIMER_INITIALIZE)
+NTSTATUS
+EgTimerInitialize (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_QUERY_COUNTER)
+ULONGLONG
+EgTimerQueryCounter (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_ACKNOWLEDGE_INTERRUPT)
+VOID
+EgTimerAcknowledgeInterrupt (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_ARM_TIMER)
+NTSTATUS
+EgTimerArm (
+ __in PVOID TimerData,
+ __in TIMER_MODE Mode,
+ __in ULONGLONG TickCount
+ );
+
+_Function_class_(TIMER_STOP)
+VOID
+EgTimerStop (
+ __in PVOID TimerData
+ );
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// Define the physical address of the timer block. This information can either
+// be hardcoded like it is here or fetched out of the CSRT resource passed to
+// the extension.
+//
+
+ULONGLONG EgTimerPhysicalAddress = 0x0BADF00D;
+
+//
+// Define the GSIVs for each timer's interrupt. This is also a candidate for
+// information to be retrieved out of the CSRT.
+//
+
+ULONG EgTimerGsi[EGTIMER_COUNT] = {
+ 32,
+ 33,
+ 34,
+ 35
+};
+
+//
+// Define the mapped virtual address of the timer block.
+//
+
+PVOID EgTimerBase = NULL;
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+AddResourceGroup (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ )
+
+/*++
+
+Routine Description:
+
+ This routine identifies and registers all of the Resource Descriptors
+ in the specified Resource Group.
+
+Arguments:
+
+ Handle - Supplies the HAL Extension handle which must be passed to other
+ HAL Extension APIs.
+
+ ResourceGroup - Supplies a pointer to the Resource Group which the
+ HAL Extension has been installed on.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ //
+ // Register the main timer block.
+ //
+
+ Status = EgTimerRegister(Handle, ResourceGroup);
+ if (!NT_SUCCESS(Status)) {
+ goto AddResourceGroupEnd;
+ }
+
+ Status = STATUS_SUCCESS;
+
+AddResourceGroupEnd:
+ return Status;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+
+NTSTATUS
+EgTimerRegister (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ )
+
+/*++
+
+Routine Description:
+
+ This routine registers the EG Timer hardware.
+
+Arguments:
+
+ Handle - Supplies the HAL Extension handle which must be passed to other
+ HAL Extension APIs.
+
+ ResourceGroup - Supplies a pointer to the Resource Group which the
+ HAL Extension has been installed on.
+
+Return Value:
+
+ NT status code.
+
+--*/
+
+{
+
+ EGTIMER_DATA InternalData;
+ TIMER_INITIALIZATION_BLOCK NewTimer;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ CSRT_RESOURCE_DESCRIPTOR_HEADER ResourceDescriptorHeader;
+ NTSTATUS Status;
+ ULONG TimerIndex;
+
+ //
+ // DEV HACK: Makeup a resource type until we get correct CSRT parsing.
+ //
+
+ ResourceDescriptorHeader.Type = CSRT_RD_TYPE_TIMER;
+ ResourceDescriptorHeader.Subtype = CSRT_RD_SUBTYPE_TIMER;
+ ResourceDescriptorHeader.Length = sizeof(CSRT_RESOURCE_DESCRIPTOR_HEADER);
+
+ //
+ // Register the entire timer block's address usage with the HAL. This
+ // address space should be shown to the HAL as reserved even if the timer
+ // is not going to be registered or used so that the system knows that
+ // region of *physical* address space is occupied.
+ //
+
+ PhysicalAddress.QuadPart = EgTimerPhysicalAddress;
+ Status = HalRegisterPermanentAddressUsage(PhysicalAddress,
+ EGTIMER_BLOCK_SIZE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+
+ //
+ // Register each timer with the HAL.
+ //
+
+ for (TimerIndex = 0; TimerIndex < EGTIMER_COUNT; TimerIndex += 1) {
+
+ //
+ // Initialize the timer structure.
+ //
+
+ RtlZeroMemory(&NewTimer, sizeof(TIMER_INITIALIZATION_BLOCK));
+ RtlZeroMemory(&InternalData, sizeof(EGTIMER_DATA));
+ INITIALIZE_TIMER_HEADER(&NewTimer);
+ NewTimer.CounterBitWidth = EGTIMER_BIT_WIDTH;
+ NewTimer.CounterFrequency = EGTIMER_FREQUENCY;
+
+ //
+ // Set the pointer to the internal data and its size. The pointer can
+ // be the same for each timer (and a local variable) because a *copy*
+ // of this data will be made for each timer registered. This is the
+ // extensions only chance to dynamically allocate memory.
+ //
+
+ NewTimer.InternalData = &InternalData;
+ NewTimer.InternalDataSize = sizeof(EGTIMER_DATA);
+ NewTimer.Interrupt.Mode = LevelSensitive;
+ NewTimer.Interrupt.Polarity = InterruptActiveHigh;
+
+ //
+ // This must be set to indicate that this is a custom third-party timer.
+ // The HAL will fail the registration if this is not set correctly.
+ //
+
+ NewTimer.KnownType = TimerUnknown;
+
+ //
+ // The timer does not support a divisor. The GSI data can be hardcoded
+ // like it is here or pulled out of the resource from the CSRT table.
+ //
+
+ NewTimer.MaxDivisor = 1;
+ NewTimer.Interrupt.Gsi = EgTimerGsi[TimerIndex];
+ NewTimer.FunctionTable.Initialize = EgTimerInitialize;
+ NewTimer.FunctionTable.QueryCounter = EgTimerQueryCounter;
+ NewTimer.FunctionTable.AcknowledgeInterrupt =
+ EgTimerAcknowledgeInterrupt;
+
+ NewTimer.FunctionTable.ArmTimer = EgTimerArm;
+ NewTimer.FunctionTable.Stop = EgTimerStop;
+ NewTimer.Capabilities = TIMER_COUNTER_READABLE |
+ TIMER_ONE_SHOT_CAPABLE |
+ TIMER_PERIODIC_CAPABLE |
+ TIMER_GENERATES_LINE_BASED_INTERRUPTS;
+
+ InternalData.TimerIndex = TimerIndex;
+ ResourceDescriptorHeader.Uid = TimerIndex;
+ Status = RegisterResourceDescriptor(Handle,
+ ResourceGroup,
+ &ResourceDescriptorHeader,
+ &NewTimer);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+ }
+
+ Status = STATUS_SUCCESS;
+
+RegisterEnd:
+ return Status;
+}
+
+_Function_class_(TIMER_INITIALIZE)
+NTSTATUS
+EgTimerInitialize (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for initializing the timer hardware. This is
+ guaranteed to be the first timer routine called by the HAL. It must prepare
+ the timer for use by beginning the timer's counter ticking if the counter
+ is readable, setting the intial input clock divisor to 1 if applicable,
+ and masking all interrupts. If the timer's stop routine is called, this
+ routine will be called before the timer is queried or armed again. It will
+ not be called between every rearming of the timer.
+
+ This routine will not be called concurrently with any other calls to
+ this HAL Timer extension. For per-processor timers, this routine will be
+ called once on each processor. A failure on any processor blocks the timer's
+ use on all processors.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context. The contents
+ of this pointer were specified when the timer was initially registered,
+ and may be modified inside this routine. The HAL does not interpret any
+ data deferenced from this pointer.
+
+Return Value:
+
+ Returns an NT status code indicating success or failure. If a successful
+ status code is returned then the HAL may subsequently call further routines
+ in this HAL extension to query or arm the timer. If a failure code is
+ returned, this HAL extension will not attempt to use this timer unless the
+ Initialize routine is called again and succeeds.
+
+--*/
+
+{
+
+ PHYSICAL_ADDRESS PhysicalAddress;
+ ULONG RegisterValue;
+ NTSTATUS Status;
+ PEGTIMER_DATA Timer;
+
+ Timer = (PEGTIMER_DATA)TimerData;
+
+ //
+ // Map the timer if no one has done that yet.
+ //
+
+ if (EgTimerBase == NULL) {
+ PhysicalAddress.QuadPart = EgTimerPhysicalAddress;
+ EgTimerBase = HalMapIoSpace(PhysicalAddress,
+ EGTIMER_BLOCK_SIZE,
+ MmNonCached);
+
+ if (EgTimerBase == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto InitializeEnd;
+ }
+ }
+
+ //
+ // Start the counter ticking in free running mode, and mask all interrupts.
+ // The counter doesn't necessarily need to be reset to 0.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerReloadValue, 0);
+ RegisterValue = EGTIMER_CONTROL_ENABLE | EGTIMER_CONTROL_PERIODIC;
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerControl, RegisterValue);
+ Status = STATUS_SUCCESS;
+
+InitializeEnd:
+ return Status;
+}
+
+_Function_class_(TIMER_QUERY_COUNTER)
+ULONGLONG
+EgTimerQueryCounter (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queries the timer hardware and retrieves the current counter
+ value.
+
+ Timers are assumed to always count *up*. If the actual timer hardware counts
+ down, then this routine should subtract the current count from the maximum
+ counter value so that values appear to count up. This routine may be called
+ concurrently on multiple processors and must be reentrant. This routine is
+ extremely performance sensitive, as it may be used to back the system
+ performance counter.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ Returns the hardware's current count.
+
+--*/
+
+{
+
+ PEGTIMER_DATA Timer;
+
+ Timer = (PEGTIMER_DATA)TimerData;
+
+ return READ_EGTIMER(Timer->TimerIndex, EgTimerCurrentCount);
+}
+
+_Function_class_(TIMER_ACKNOWLEDGE_INTERRUPT)
+VOID
+EgTimerAcknowledgeInterrupt (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs any actions necessary to acknowledge and quiesce a
+ timer interrupt. For per-processor timers, this routine may be called
+ concurrently on multiple processors. This routine will be called on every
+ timer interrupt at the hardware priority level of that interrupt, so this
+ routine is extremely performance sensitive. For timers running in
+ pseudo-periodic mode, this routine must rearm the timer for the same
+ interval as it was armed with without introducing delay into the interrupt
+ interval. Only deadline-based timers support pseudo-periodic mode.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PEGTIMER_DATA Timer;
+
+ Timer = (PEGTIMER_DATA)TimerData;
+
+ //
+ // Acknowledge the interrupt by writing to the interrupt acknowledge
+ // register.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerInterruptAcknowledge, 0);
+ return;
+}
+
+_Function_class_(TIMER_ARM_TIMER)
+NTSTATUS
+EgTimerArm (
+ __in PVOID TimerData,
+ __in TIMER_MODE Mode,
+ __in ULONGLONG TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine arms a timer to fire an interrupt after the given number of
+ timer ticks. For timers that only interrupt on rollovers, this simply
+ enables the interrupt, the tick count parameter is ignored. If the timer
+ is currently armed for a different mode or tick count, this call is
+ expected to replace that programming. This routine will not get called
+ concurrently with other timer calls, except on per-processor timers, where
+ it may get called concurrently on different processors.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+ Mode - Supplies the mode to arm the timer in, which will be one of the
+ modes the HAL extension advertised support for when registering the
+ timer. The modes are as follows:
+
+ OneShot - Arms the timer to fire the given number of ticks from now.
+ Only one interrupt is expected to come in. The HAL does not make
+ assumptions on whether or not the expiration of this interrupt
+ causes the counter to stop. The Query Counter routine will not be
+ called while a timer is armed to fire an interrupt.
+
+ Periodic - Arms the timer to fire periodically with an interval of the
+ given number of ticks. The first interrupt should happen
+ approximately the given number of ticks from when the arm timer
+ function was invoked.
+
+ PseudoPeriodic - Arms the timer with the same functional behavior as
+ periodic mode, with the knowledge that the timer will have to rearm
+ itself during the acknowledge interrupt routine. This mode is
+ expected to have slightly worse performance than pure periodic mode,
+ but is expected to generate periodic interrupts at the exact rate
+ specified.
+
+ TickCount - Supplies the number of ticks from now that the timer should
+ assert its interrupt in. For timers that are only capable of
+ interrupting on rollovers from their maximum value to 0, this parameter
+ is ignored.
+
+Return Value:
+
+ Returns and NTSTATUS code indicating success or failure. If the timer
+ returns success, then the interrupt is expected to come in the specified
+ number of ticks from when the function was called, with a tolerance of
+ however long the function took to execute. If the routine fails, then no
+ timer routines will be called again until the timer Initialize routine is
+ called again and succeeds. In most cases, returning a failure code results
+ in a system bugcheck.
+
+--*/
+
+{
+
+ ULONG ControlRegister;
+ PEGTIMER_DATA Timer;
+
+ Timer = (PEGTIMER_DATA)TimerData;
+
+ NT_ASSERT(TickCount != 0);
+ NT_ASSERT(TickCount <= 0xFFFFFFFF);
+ NT_ASSERT(Mode != TimerModePseudoPeriodic);
+
+ //
+ // This will never occur.
+ //
+
+ if ((TickCount > 0xFFFFFFFF) || (TickCount == 0)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ ControlRegister = EGTIMER_CONTROL_ENABLE | EGTIMER_CONTROL_INTERRUPT_ENABLE;
+ if (Mode == TimerModePeriodic) {
+ ControlRegister |= EGTIMER_CONTROL_PERIODIC;
+ }
+
+ //
+ // Disable the timer while it's being programmed to avoid spurious
+ // interrupts.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerControl, 0);
+
+ //
+ // Write the reload register to set both the current count value and the
+ // reload value if the interrupt is periodic.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex,
+ EgTimerReloadValue,
+ 0 - (ULONG)TickCount);
+
+ //
+ // Enable the timer.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerControl, ControlRegister);
+ return STATUS_SUCCESS;
+}
+
+_Function_class_(TIMER_STOP)
+VOID
+EgTimerStop (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops a timer from ticking. After this function returns, the
+ timer should not generate any more interrupts, and reads to its counter
+ might return the same value every time.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ None, this function must succeed.
+
+--*/
+
+{
+
+ PEGTIMER_DATA Timer;
+
+ Timer = (PEGTIMER_DATA)TimerData;
+
+ //
+ // All that technically needs to be done to stop the timer from firing is
+ // to clear the interrupt enable bit. Stopping the timer entirely works too.
+ //
+
+ WRITE_EGTIMER(Timer->TimerIndex, EgTimerControl, 0);
+ return;
+}
+
diff --git a/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.def b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.def
new file mode 100644
index 00000000..786620d2
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.def
@@ -0,0 +1,2 @@
+LIBRARY HalExtSampleTimers
+
diff --git a/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.rc b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.rc
new file mode 100644
index 00000000..89069fbd
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.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 - Timers"
+#define VER_INTERNALNAME_STR "HalExtSampleTimers.DLL"
+#define VER_ORIGINALFILENAME_STR "HalExtSampleTimers.DLL"
+
+#include <common.ver>
diff --git a/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.vcxproj b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.vcxproj
new file mode 100644
index 00000000..f03fae0d
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.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>{708FC03F-4440-4AF4-B68F-5ADE99A0690B}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Arm</Platform>
+ <SampleGuid>{74DA088F-D0F8-4839-9BFF-3C72F7D46E64}</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>HalExtSampleTimers</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'">
+ <TargetName>HalExtSampleTimers</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>HalExtSampleTimers.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>HalExtSampleTimers.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="HalExtSampleTimers.c" />
+ <ResourceCompile Include="HalExtSampleTimers.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/HalExtSampleTimers/HalExtSampleTimers.vcxproj.Filters b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.vcxproj.Filters
new file mode 100644
index 00000000..3948916a
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers/HalExtSampleTimers.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>{5E4E1ADC-DD92-4AFF-B021-09A73A1D08DF}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{E29262B9-C497-404D-A5E0-5E6064005E48}</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>{E3A98D78-1B54-4D53-AFC0-D44C9D37EC38}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="HalExtSampleTimers.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="HalExtSampleTimers.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="HalExtSampleTimers.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.c b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.c
new file mode 100644
index 00000000..9a580fea
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.c
@@ -0,0 +1,825 @@
+/*++
+
+Copyright (c) 2011 Microsoft Corporation
+
+Module Name:
+
+ HalExtSampleTimers2.c
+
+Abstract:
+
+ This file implements a HAL Extension Module for the fictitious EG2Timer.
+
+Author:
+
+ Evan Green (evgreen) 8-Jan-2011
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <nthalext.h>
+
+//
+// -------------------------------------------------------------- Specification
+//
+
+//
+// The EG2Timer is a fast-access low latency deadline-based timer designed
+// for high-performance timekeeping operations. It consists of one counter
+// counter and three match registers against that counter. Each match register
+// consists of a 32-bit value that is compared on each clock cycle to the
+// current count value. If the values match and the match register is enabled
+// for generating an interrupt, an edge triggered interrupt will be fired. The
+// register can also be configured with an "interval" value such that the
+// match register is automatically moved forward by the given interval to
+// generate periodic interrupts. The main counter is 32 bits and runs at 15MHz.
+// The register layout of the timer block appears below.
+//
+// Offset Register Size
+// 0x00 GlobalControl 4
+// 0x04 CounterValue 4
+// 0x08 Timer0_Match 4
+// 0x0C Timer0_Interval 4
+// 0x10 Timer0_Control 4
+// 0x14 Timer1_Match 4
+// 0x18 Timer1_Interval 4
+// 0x1C Timer1_Control 4
+// 0x20 Timer2_Match 4
+// 0x24 Timer2_Interval 4
+// 0x28 Timer2_Control 4
+//
+// Register Descriptions:
+//
+// GlobalControl - Controls global state relating to the timer block. On reset,
+// this register's value is 0. This register is Read/Write.
+//
+// Bit Function
+// 31-1 Reserved. Read as 0, always write 0 to maintain future
+// compatibility.
+//
+// 0 Enabled. When set to 1, the main counter is enabled and will
+// count. When set to 0, the main counter is disabled and will
+// not run.
+//
+// CounterValue - A Read/Write register containing the current value of the
+// counter. Writes to this register must be done with caution as they do
+// not alter or adjust the contents of the match registers. On reset, the
+// value of this register is 0.
+//
+// TimerN_Match - A Read/Write register that contains the match value that this
+// interrupt is primed against. When the global counter equals the match
+// value, an interrupt will be generated. If the interrupt is set for
+// periodic mode, the Interval value will be automatically added to the
+// match value when the interrupt occurs. On reset, the value of this
+// register is 0.
+//
+// TimerN_Interval - A Read/Write register that contains the periodic interval
+// to add to the match register if the interrupt is armed for periodic
+// mode. On reset, the value of this register is 0.
+//
+// TimerN_Control - A Read/Write register containing a bitfield that controls
+// the behavior of the match register and associated interrupt. On reset,
+// the value of this register is 0.
+//
+// Bit Function
+// 31-2 Reserved. Read as 0, always write 0 to maintain future
+// compatibility.
+//
+// 1 Periodic. When set to 1, the value in the Interval register will
+// automatically be added to the value in the Match register and
+// written back to the Match register when a match occurs. When
+// set to 0, the Match register will not change when a match
+// occurs.
+//
+// 0 InterruptEnable. When set to 1, an interrupt will be generated
+// when a match occurs. When set to 0, no interrupt will be
+// generated when a match occurs. The periodic bit is still live
+// however, the Match register will continue to get accumulated
+// with the Interval register on matches.
+//
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// Define the total size of the register block, which is 1 page.
+//
+
+#define EG2TIMER_BLOCK_SIZE 0x1000
+
+//
+// Define the size of one timer's match register block, in ULONGs.
+//
+
+#define EG2MATCH_SIZE 3
+
+//
+// Define the total number of match registers.
+//
+
+#define EG2MATCH_COUNT 3
+
+//
+// Define the timer's bit width.
+//
+
+#define EG2TIMER_BIT_WIDTH 32
+
+//
+// Define the counter's frequency, in Hertz.
+//
+
+#define EG2TIMER_FREQUENCY 15000000
+
+//
+// Define the global control bits.
+//
+
+#define EG2TIMER_GLOBAL_CONTROL_ENABLE 0x00000001
+
+//
+// Define bits for the control register.
+//
+
+#define EG2TIMER_MATCH_INTERRUPT_ENABLE 0x00000001
+#define EG2TIMER_MATCH_PERIODIC 0x00000002
+
+//
+// Define the special offset used to indicate this timer is the counter
+// itself.
+//
+
+#define EG2TIMER_COUNTER_OFFSET 0xFFFFFFFF
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+
+//
+// Define the registers and their offsets, in ULONGs.
+//
+
+typedef enum _EG2TIMER_REGISTER {
+ Eg2TimerGlobalControl = 0,
+ Eg2TimerCurrentCount = 1,
+ Eg2TimerMatch = 2,
+ Eg2TimerInterval = 3,
+ Eg2TimerControl = 4
+} EG2TIMER_REGISTER, *PEG2TIMER_REGISTER;
+
+//
+// Define the format of the private data structure. The offset member stores the
+// offset to the match register, in ULONGs. The value 0 is reserved for the
+// global counter.
+//
+
+typedef struct _EG2TIMER_DATA {
+ ULONG Offset;
+ TIMER_MODE Mode;
+ ULONG Period;
+} EG2TIMER_DATA, *PEG2TIMER_DATA;
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// The following macros are used to read from and write to the timer. The first
+// parameter is the offset in ULONGs to apply to the requested register. The
+// second parameter is the register to read or write. For write functions, the
+// third parameter is the value to write.
+//
+// READ_REGISTER_ULONG and WRITE_REGISTER_ULONG should always be used to
+// ensure that the proper barriers and flushes are in place for doing direct
+// hardware accesses.
+//
+
+#define READ_EG2TIMER(_TimerOffset, _Register) \
+ READ_REGISTER_ULONG((PULONG)Eg2TimerBase + (_TimerOffset) + (_Register))
+
+#define WRITE_EG2TIMER(_TimerOffset, _Register, _Value) \
+ WRITE_REGISTER_ULONG((PULONG)Eg2TimerBase + (_TimerOffset) + (_Register), \
+ (_Value))
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+NTSTATUS
+Eg2TimerRegister (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ );
+
+_Function_class_(TIMER_INITIALIZE)
+NTSTATUS
+Eg2TimerInitialize (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_QUERY_COUNTER)
+ULONGLONG
+Eg2TimerQueryCounter (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_ACKNOWLEDGE_INTERRUPT)
+VOID
+Eg2TimerAcknowledgeInterrupt (
+ __in PVOID TimerData
+ );
+
+_Function_class_(TIMER_ARM_TIMER)
+NTSTATUS
+Eg2TimerArm (
+ __in PVOID TimerData,
+ __in TIMER_MODE Mode,
+ __in ULONGLONG TickCount
+ );
+
+_Function_class_(TIMER_STOP)
+VOID
+Eg2TimerStop (
+ __in PVOID TimerData
+ );
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// Define the physical address of the timer block. This information can either
+// be hardcoded like it is here or fetched out of the CSRT resource passed to
+// the extension.
+//
+
+ULONGLONG Eg2TimerPhysicalAddress = 0xBEEF7AC0;
+
+//
+// Define the GSIVs for each timer's interrupt. This is also a candidate for
+// information to be retrieved out of the CSRT.
+//
+
+ULONG Eg2TimerGsi[EG2MATCH_COUNT] = {
+ 40,
+ 41,
+ 42,
+};
+
+//
+// Define the mapped virtual address of the timer block.
+//
+
+PVOID Eg2TimerBase = NULL;
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+NTSTATUS
+AddResourceGroup (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ )
+
+/*++
+
+Routine Description:
+
+ This routine identifies and registers all of the Resource Descriptors
+ in the specified Resource Group.
+
+Arguments:
+
+ Handle - Supplies the HAL Extension handle which must be passed to other
+ HAL Extension APIs.
+
+ ResourceGroup - Supplies a pointer to the Resource Group which the
+ HAL Extension has been installed on.
+
+Return Value:
+
+ NTSTATUS code.
+
+--*/
+
+{
+
+ NTSTATUS Status;
+
+ //
+ // Register the main timer block.
+ //
+
+ Status = Eg2TimerRegister(Handle, ResourceGroup);
+ if (!NT_SUCCESS(Status)) {
+ goto AddResourceGroupEnd;
+ }
+
+ Status = STATUS_SUCCESS;
+
+AddResourceGroupEnd:
+ return Status;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+
+NTSTATUS
+Eg2TimerRegister (
+ __in ULONG Handle,
+ __in PCSRT_RESOURCE_GROUP_HEADER ResourceGroup
+ )
+
+/*++
+
+Routine Description:
+
+ This routine registers the EG2 Timer hardware.
+
+Arguments:
+
+ Handle - Supplies the HAL Extension handle which must be passed to other
+ HAL Extension APIs.
+
+ ResourceGroup - Supplies a pointer to the Resource Group which the
+ HAL Extension has been installed on.
+
+Return Value:
+
+ NT status code.
+
+--*/
+
+{
+
+ EG2TIMER_DATA InternalData;
+ TIMER_INITIALIZATION_BLOCK NewTimer;
+ PHYSICAL_ADDRESS PhysicalAddress;
+ CSRT_RESOURCE_DESCRIPTOR_HEADER ResourceDescriptorHeader;
+ NTSTATUS Status;
+ ULONG TimerIndex;
+
+ //
+ // DEV HACK: Makeup a resource type until we get correct CSRT parsing.
+ //
+
+ ResourceDescriptorHeader.Type = CSRT_RD_TYPE_TIMER;
+ ResourceDescriptorHeader.Subtype = CSRT_RD_SUBTYPE_TIMER;
+ ResourceDescriptorHeader.Length = sizeof(CSRT_RESOURCE_DESCRIPTOR_HEADER);
+
+ //
+ // Register the entire timer block's address usage with the HAL. This
+ // address space should be shown to the HAL as reserved even if the timer
+ // is not going to be registered or used so that the system knows that
+ // region of *physical* address space is occupied.
+ //
+
+ PhysicalAddress.QuadPart = Eg2TimerPhysicalAddress;
+ Status = HalRegisterPermanentAddressUsage(PhysicalAddress,
+ EG2TIMER_BLOCK_SIZE);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+
+ //
+ // Register the main counter as a non-interrupt generating timer, as it can
+ // be used completely independently of the match registers as long as it
+ // is never written to.
+ //
+
+ RtlZeroMemory(&NewTimer, sizeof(TIMER_INITIALIZATION_BLOCK));
+ RtlZeroMemory(&InternalData, sizeof(EG2TIMER_DATA));
+ INITIALIZE_TIMER_HEADER(&NewTimer);
+ NewTimer.CounterBitWidth = EG2TIMER_BIT_WIDTH;
+ NewTimer.CounterFrequency = EG2TIMER_FREQUENCY;
+
+ //
+ // Set the pointer to the internal data and its size. The pointer can
+ // be the same for each timer (and a local variable) because a *copy*
+ // of this data will be made for each timer registered. This is the
+ // extensions only chance to dynamically allocate memory.
+ //
+
+ NewTimer.InternalData = &InternalData;
+ NewTimer.InternalDataSize = sizeof(EG2TIMER_DATA);
+ NewTimer.Interrupt.Mode = Latched;
+ NewTimer.Interrupt.Polarity = InterruptActiveHigh;
+
+ //
+ // This must be set to indicate that this is a custom third-party timer.
+ // The HAL will fail the registration if this is not set correctly.
+ //
+
+ NewTimer.KnownType = TimerUnknown;
+
+ //
+ // The timer does not support a divisor. The GSI data can be hardcoded
+ // like it is here or pulled out of the resource from the CSRT table.
+ // Filling in extra functions doesn't hurt as the HAL will never call
+ // anything but Initialize and QueryCounter on timers that don't
+ // generate interrupts.
+ //
+
+ NewTimer.MaxDivisor = 1;
+ NewTimer.FunctionTable.Initialize = Eg2TimerInitialize;
+ NewTimer.FunctionTable.QueryCounter = Eg2TimerQueryCounter;
+ NewTimer.FunctionTable.AcknowledgeInterrupt = Eg2TimerAcknowledgeInterrupt;
+ NewTimer.FunctionTable.ArmTimer = Eg2TimerArm;
+ NewTimer.FunctionTable.Stop = Eg2TimerStop;
+ NewTimer.Capabilities = TIMER_COUNTER_READABLE;
+ InternalData.Offset = EG2TIMER_COUNTER_OFFSET;
+ ResourceDescriptorHeader.Uid = EG2TIMER_COUNTER_OFFSET;
+ Status = RegisterResourceDescriptor(Handle,
+ ResourceGroup,
+ &ResourceDescriptorHeader,
+ &NewTimer);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+
+
+ //
+ // Register each match register as a separate non-readable timer with the
+ // HAL. Since this timer is deadline-based, it can do pseudo-periodic
+ // mode and lossless rate transitions.
+ //
+
+ NewTimer.Capabilities = TIMER_ONE_SHOT_CAPABLE |
+ TIMER_PERIODIC_CAPABLE |
+ TIMER_PSEUDO_PERIODIC_CAPABLE |
+ TIMER_GENERATES_LINE_BASED_INTERRUPTS;
+
+ for (TimerIndex = 0; TimerIndex < EG2MATCH_COUNT; TimerIndex += 1) {
+ NewTimer.Interrupt.Gsi = Eg2TimerGsi[TimerIndex];
+ InternalData.Offset = EG2MATCH_SIZE * TimerIndex;
+ ResourceDescriptorHeader.Uid = EG2MATCH_SIZE * TimerIndex;
+ Status = RegisterResourceDescriptor(Handle,
+ ResourceGroup,
+ &ResourceDescriptorHeader,
+ &NewTimer);
+
+ if (!NT_SUCCESS(Status)) {
+ goto RegisterEnd;
+ }
+ }
+
+ Status = STATUS_SUCCESS;
+
+RegisterEnd:
+ return Status;
+}
+
+_Function_class_(TIMER_INITIALIZE)
+NTSTATUS
+Eg2TimerInitialize (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for initializing the timer hardware. This is
+ guaranteed to be the first timer routine called by the HAL. It must prepare
+ the timer for use by beginning the timer's counter ticking if the counter
+ is readable, setting the intial input clock divisor to 1 if applicable,
+ and masking all interrupts. If the timer's stop routine is called, this
+ routine will be called before the timer is queried or armed again. It will
+ not be called between every rearming of the timer.
+
+ This routine will not be called concurrently with any other calls to
+ this HAL Timer extension. For per-processor timers, this routine will be
+ called once on each processor. A failure on any processor blocks the timer's
+ use on all processors.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context. The contents
+ of this pointer were specified when the timer was initially registered,
+ and may be modified inside this routine. The HAL does not interpret any
+ data deferenced from this pointer.
+
+Return Value:
+
+ Returns an NT status code indicating success or failure. If a successful
+ status code is returned then the HAL may subsequently call further routines
+ in this HAL extension to query or arm the timer. If a failure code is
+ returned, this HAL extension will not attempt to use this timer unless the
+ Initialize routine is called again and succeeds.
+
+--*/
+
+{
+
+ PHYSICAL_ADDRESS PhysicalAddress;
+ NTSTATUS Status;
+ PEG2TIMER_DATA Timer;
+
+ Timer = (PEG2TIMER_DATA)TimerData;
+
+ //
+ // Map the timer if no one has done that yet.
+ //
+
+ if (Eg2TimerBase == NULL) {
+ PhysicalAddress.QuadPart = Eg2TimerPhysicalAddress;
+ Eg2TimerBase = HalMapIoSpace(PhysicalAddress,
+ EG2TIMER_BLOCK_SIZE,
+ MmNonCached);
+
+ if (Eg2TimerBase == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto InitializeEnd;
+ }
+ }
+
+ //
+ // Start the counter ticking in free running mode, and mask all interrupts.
+ // The counter must *not* be reset here, otherwise an Initialize call on the
+ // counter would affect the match register timers, which as far as the HAL
+ // is concerned are completely independent from one another.
+ //
+
+ WRITE_EG2TIMER(0, Eg2TimerGlobalControl, EG2TIMER_GLOBAL_CONTROL_ENABLE);
+ if (Timer->Offset != EG2TIMER_COUNTER_OFFSET) {
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerControl, 0);
+ }
+
+ Status = STATUS_SUCCESS;
+
+InitializeEnd:
+ return Status;
+}
+
+_Function_class_(TIMER_QUERY_COUNTER)
+ULONGLONG
+Eg2TimerQueryCounter (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queries the timer hardware and retrieves the current counter
+ value.
+
+ Timers are assumed to always count *up*. If the actual timer hardware counts
+ down, then this routine should subtract the current count from the maximum
+ counter value so that values appear to count up. This routine may be called
+ concurrently on multiple processors and must be reentrant. This routine is
+ extremely performance sensitive, as it may be used to back the system
+ performance counter.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ Returns the hardware's current count.
+
+--*/
+
+{
+
+ PEG2TIMER_DATA Timer;
+
+ Timer = (PEG2TIMER_DATA)TimerData;
+
+ NT_ASSERT(Timer->Offset == EG2TIMER_COUNTER_OFFSET);
+
+ return READ_EG2TIMER(Timer->Offset, Eg2TimerCurrentCount);
+}
+
+_Function_class_(TIMER_ACKNOWLEDGE_INTERRUPT)
+VOID
+Eg2TimerAcknowledgeInterrupt (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs any actions necessary to acknowledge and quiesce a
+ timer interrupt. For per-processor timers, this routine may be called
+ concurrently on multiple processors. This routine will be called on every
+ timer interrupt at the hardware priority level of that interrupt, so this
+ routine is extremely performance sensitive. For timers running in
+ pseudo-periodic mode, this routine must rearm the timer for the same
+ interval as it was armed with without introducing delay into the interrupt
+ interval. Only deadline-based timers support pseudo-periodic mode.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG MatchValue;
+ PEG2TIMER_DATA Timer;
+
+ //
+ // No action is necessary here as far as acknowledging the interrupt.
+ // If the current mode is pseudo-periodic, the next interrupt must be
+ // armed now.
+ //
+
+ Timer = (PEG2TIMER_DATA)TimerData;
+
+ NT_ASSERT(Timer->Offset != EG2TIMER_COUNTER_OFFSET);
+ NT_ASSERT(Timer->Mode != TimerModeInvalid);
+
+ if (Timer->Mode == TimerModePseudoPeriodic) {
+
+ NT_ASSERT(Timer->Period != 0);
+
+ //
+ // Read the deadline that just passed, add the period, and then write
+ // the new deadline.
+ //
+
+ MatchValue = READ_EG2TIMER(Timer->Offset, Eg2TimerMatch);
+ MatchValue += Timer->Period;
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerMatch, MatchValue);
+ }
+
+ return;
+}
+
+_Function_class_(TIMER_ARM_TIMER)
+NTSTATUS
+Eg2TimerArm (
+ __in PVOID TimerData,
+ __in TIMER_MODE Mode,
+ __in ULONGLONG TickCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine arms a timer to fire an interrupt after the given number of
+ timer ticks. For timers that only interrupt on rollovers, this simply
+ enables the interrupt, the tick count parameter is ignored. If the timer
+ is currently armed for a different mode or tick count, this call is
+ expected to replace that programming. This routine will not get called
+ concurrently with other timer calls, except on per-processor timers, where
+ it may get called concurrently on different processors.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+ Mode - Supplies the mode to arm the timer in, which will be one of the
+ modes the HAL extension advertised support for when registering the
+ timer. The modes are as follows:
+
+ OneShot - Arms the timer to fire the given number of ticks from now.
+ Only one interrupt is expected to come in. The HAL does not make
+ assumptions on whether or not the expiration of this interrupt
+ causes the counter to stop. The Query Counter routine will not be
+ called while a timer is armed to fire an interrupt.
+
+ Periodic - Arms the timer to fire periodically with an interval of the
+ given number of ticks. The first interrupt should happen
+ approximately the given number of ticks from when the arm timer
+ function was invoked.
+
+ PseudoPeriodic - Arms the timer with the same functional behavior as
+ periodic mode, with the knowledge that the timer will have to rearm
+ itself during the acknowledge interrupt routine. This mode is
+ expected to have slightly worse performance than pure periodic mode,
+ but is expected to generate periodic interrupts at the exact rate
+ specified.
+
+ TickCount - Supplies the number of ticks from now that the timer should
+ assert its interrupt in. For timers that are only capable of
+ interrupting on rollovers from their maximum value to 0, this parameter
+ is ignored.
+
+Return Value:
+
+ Returns and NTSTATUS code indicating success or failure. If the timer
+ returns success, then the interrupt is expected to come in the specified
+ number of ticks from when the function was called, with a tolerance of
+ however long the function took to execute. If the routine fails, then no
+ timer routines will be called again until the timer Initialize routine is
+ called again and succeeds. In most cases, returning a failure code results
+ in a system bugcheck.
+
+--*/
+
+{
+
+ ULONG ControlRegister;
+ ULONG MatchValue;
+ PEG2TIMER_DATA Timer;
+
+ Timer = (PEG2TIMER_DATA)TimerData;
+
+ NT_ASSERT(TickCount != 0);
+ NT_ASSERT(TickCount <= 0xFFFFFFFF);
+ NT_ASSERT(Timer->Offset != EG2TIMER_COUNTER_OFFSET);
+
+ //
+ // This will never occur.
+ //
+
+ if ((TickCount > 0xFFFFFFFF) || (TickCount == 0)) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Disable the timer while it's being programmed to avoid spurious
+ // interrupts.
+ //
+
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerControl, 0);
+ ControlRegister = EG2TIMER_MATCH_INTERRUPT_ENABLE;
+
+ //
+ // For periodic mode, set the periodic interval register.
+ //
+
+ if (Mode == TimerModePeriodic) {
+ ControlRegister |= EG2TIMER_MATCH_PERIODIC;
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerInterval, (ULONG)TickCount);
+ }
+
+ Timer->Mode = Mode;
+ Timer->Period = (ULONG)TickCount;
+
+ //
+ // Calculate and write in the first match value.
+ //
+
+ MatchValue = READ_EG2TIMER(Timer->Offset, Eg2TimerCurrentCount);
+ MatchValue += (ULONG)TickCount;
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerMatch, MatchValue);
+
+ //
+ // Enable the interrupt.
+ //
+
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerControl, ControlRegister);
+ return STATUS_SUCCESS;
+}
+
+_Function_class_(TIMER_STOP)
+VOID
+Eg2TimerStop (
+ __in PVOID TimerData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stops a timer from ticking. After this function returns, the
+ timer should not generate any more interrupts, and reads to its counter
+ might return the same value every time.
+
+Arguments:
+
+ TimerData - Supplies a pointer to the timer's private context, whose
+ initial content was supplied when the timer was registered.
+
+Return Value:
+
+ None, this function must succeed.
+
+--*/
+
+{
+
+ PEG2TIMER_DATA Timer;
+
+ Timer = (PEG2TIMER_DATA)TimerData;
+
+ //
+ // Clear the interrupt enable bit.
+ //
+
+ WRITE_EG2TIMER(Timer->Offset, Eg2TimerControl, 0);
+ return;
+}
diff --git a/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.def b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.def
new file mode 100644
index 00000000..685129d2
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.def
@@ -0,0 +1,2 @@
+LIBRARY HalExtSampleTimers2
+
diff --git a/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.rc b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.rc
new file mode 100644
index 00000000..c82378e0
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.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 - Timers 2"
+#define VER_INTERNALNAME_STR "HalExtSampleTimers2.DLL"
+#define VER_ORIGINALFILENAME_STR "HalExtSampleTimers2.DLL"
+
+#include <common.ver>
diff --git a/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj
new file mode 100644
index 00000000..dc581c00
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.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>{A99E0448-5F6C-42B3-99AA-C43464989418}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Arm</Platform>
+ <SampleGuid>{E9FE899A-F0DB-43B5-8DFD-65D5D790DD76}</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>HalExtSampleTimers2</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Arm'">
+ <TargetName>HalExtSampleTimers2</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>HalExtSampleTimers2.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>HalExtSampleTimers2.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="HalExtSampleTimers2.c" />
+ <ResourceCompile Include="HalExtSampleTimers2.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/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj.Filters b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.vcxproj.Filters
new file mode 100644
index 00000000..d752a638
--- /dev/null
+++ b/general/HalExtensionSample/HalExtSampleTimers2/HalExtSampleTimers2.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>{CE019AA9-89F5-4A8E-87D1-ED585767F789}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{EF3411D2-5BFE-41A9-906C-0E6611142568}</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>{07F31510-2D3D-4110-85A6-F39922948329}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="HalExtSampleTimers2.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="HalExtSampleTimers2.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="HalExtSampleTimers2.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/general/HalExtensionSample/HalExtensionSample.sln b/general/HalExtensionSample/HalExtensionSample.sln
new file mode 100644
index 00000000..b284bd36
--- /dev/null
+++ b/general/HalExtensionSample/HalExtensionSample.sln
@@ -0,0 +1,45 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HalExtSampleDma", "HalExtSampleDma", "{C258909E-9676-4DCA-AB5E-4134876CC0F1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HalExtSampleTimers", "HalExtSampleTimers", "{2F891F34-1182-4F77-8923-AF73DF4844C2}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HalExtSampleTimers2", "HalExtSampleTimers2", "{20ADC56F-63BE-4671-81B1-D2AC009F7E3C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HalExtSampleDma", "HalExtSampleDma\HalExtSampleDma.vcxproj", "{7568DCFB-C421-478A-A809-21EF6EC243BE}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HalExtSampleTimers", "HalExtSampleTimers\HalExtSampleTimers.vcxproj", "{708FC03F-4440-4AF4-B68F-5ADE99A0690B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HalExtSampleTimers2", "HalExtSampleTimers2\HalExtSampleTimers2.vcxproj", "{A99E0448-5F6C-42B3-99AA-C43464989418}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Arm = Debug|Arm
+ Release|Arm = Release|Arm
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7568DCFB-C421-478A-A809-21EF6EC243BE}.Debug|Arm.ActiveCfg = Debug|Arm
+ {7568DCFB-C421-478A-A809-21EF6EC243BE}.Debug|Arm.Build.0 = Debug|Arm
+ {7568DCFB-C421-478A-A809-21EF6EC243BE}.Release|Arm.ActiveCfg = Release|Arm
+ {7568DCFB-C421-478A-A809-21EF6EC243BE}.Release|Arm.Build.0 = Release|Arm
+ {708FC03F-4440-4AF4-B68F-5ADE99A0690B}.Debug|Arm.ActiveCfg = Debug|Arm
+ {708FC03F-4440-4AF4-B68F-5ADE99A0690B}.Debug|Arm.Build.0 = Debug|Arm
+ {708FC03F-4440-4AF4-B68F-5ADE99A0690B}.Release|Arm.ActiveCfg = Release|Arm
+ {708FC03F-4440-4AF4-B68F-5ADE99A0690B}.Release|Arm.Build.0 = Release|Arm
+ {A99E0448-5F6C-42B3-99AA-C43464989418}.Debug|Arm.ActiveCfg = Debug|Arm
+ {A99E0448-5F6C-42B3-99AA-C43464989418}.Debug|Arm.Build.0 = Debug|Arm
+ {A99E0448-5F6C-42B3-99AA-C43464989418}.Release|Arm.ActiveCfg = Release|Arm
+ {A99E0448-5F6C-42B3-99AA-C43464989418}.Release|Arm.Build.0 = Release|Arm
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {7568DCFB-C421-478A-A809-21EF6EC243BE} = {C258909E-9676-4DCA-AB5E-4134876CC0F1}
+ {708FC03F-4440-4AF4-B68F-5ADE99A0690B} = {2F891F34-1182-4F77-8923-AF73DF4844C2}
+ {A99E0448-5F6C-42B3-99AA-C43464989418} = {20ADC56F-63BE-4671-81B1-D2AC009F7E3C}
+ EndGlobalSection
+EndGlobal