diff options
| author | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
|---|---|---|
| committer | Dave Wilson <[email protected]> | 2015-03-17 19:50:07 -0700 |
| commit | 97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch) | |
| tree | 46f3701832d70b420eb0fc0eb93261f9da45db3f /general | |
| parent | ef1905bf1e8825bb31120dfb27e0daf3154d859a (diff) | |
Initial publish
Diffstat (limited to 'general')
385 files changed, 81381 insertions, 0 deletions
diff --git a/general/PLX9x5x/PLX9x5x.sln b/general/PLX9x5x/PLX9x5x.sln new file mode 100644 index 00000000..c54db7f0 --- /dev/null +++ b/general/PLX9x5x/PLX9x5x.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{C3251AB4-8086-4862-985F-35302E40A027}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{954C16D2-23E1-4D8C-A040-5D4FB830D689}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Pci9x5x", "sys\Pci9x5x.vcxproj", "{12A2C4C0-856A-49BE-9F54-30D4D040C3E9}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plx", "test\plx.vcxproj", "{BF101CB1-B147-40AC-8F84-13AC122A2D37}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|Win32.ActiveCfg = Debug|Win32 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|Win32.Build.0 = Debug|Win32 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|Win32.ActiveCfg = Release|Win32 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|Win32.Build.0 = Release|Win32 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|x64.ActiveCfg = Debug|x64 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Debug|x64.Build.0 = Debug|x64 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|x64.ActiveCfg = Release|x64 + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9}.Release|x64.Build.0 = Release|x64 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|Win32.ActiveCfg = Debug|Win32 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|Win32.Build.0 = Debug|Win32 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|Win32.ActiveCfg = Release|Win32 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|Win32.Build.0 = Release|Win32 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|x64.ActiveCfg = Debug|x64 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Debug|x64.Build.0 = Debug|x64 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|x64.ActiveCfg = Release|x64 + {BF101CB1-B147-40AC-8F84-13AC122A2D37}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {12A2C4C0-856A-49BE-9F54-30D4D040C3E9} = {C3251AB4-8086-4862-985F-35302E40A027} + {BF101CB1-B147-40AC-8F84-13AC122A2D37} = {954C16D2-23E1-4D8C-A040-5D4FB830D689} + EndGlobalSection +EndGlobal diff --git a/general/PLX9x5x/ReadMe.md b/general/PLX9x5x/ReadMe.md new file mode 100644 index 00000000..a706b7d0 --- /dev/null +++ b/general/PLX9x5x/ReadMe.md @@ -0,0 +1,23 @@ +PLX9x5x PCI Driver +================== + +This sample demonstrates how to write driver for a generic PCI device using Windows Driver Framework. The target hardware for this driver is PLX9656/9653RDK-LITE board. The product kit and the hardware specification are available at <http://www.plxtech.com>. + +For more information, see [Peripheral Component Interconnect (PCI) Bus Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff537451). + +The device is a PCI device with port, memory, interrupt and DMA resources. Device can be stopped and started at run-time and also supports low power states. The driver is capable of doing concurrent read and write operations to the device but it can handle only one read or write request at any time. The following lists the driver framework interfaces demonstrated in this sample: + +- Handling PnP & Power Events +- Registering a Device Interface +- Hardware resource mapping: Port, Memory & Interrupt +- DMA Interfaces +- Serialized Default Queue for Write requests +- Serialized custom Queue for Read requests +- Handling Interrupt & DPC + +To test the driver, run the PLX.EXE test application. + +This sample driver is a minimal driver meant to demonstrate the usage of the Windows Driver Framework. It is not intended for use in a production environment. + + + diff --git a/general/PLX9x5x/sys/Init.c b/general/PLX9x5x/sys/Init.c new file mode 100644 index 00000000..b18c80c6 --- /dev/null +++ b/general/PLX9x5x/sys/Init.c @@ -0,0 +1,777 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Init.c + +Abstract: + + Contains most of initialization functions + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#include "Init.tmh" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, PLxInitializeDeviceExtension) +#pragma alloc_text (PAGE, PLxPrepareHardware) +#pragma alloc_text (PAGE, PLxInitializeDMA) +#endif + +PVOID LocalMmMapIoSpace( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ SIZE_T NumberOfBytes + ) +{ + typedef + PVOID + (*PFN_MM_MAP_IO_SPACE_EX) ( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ SIZE_T NumberOfBytes, + _In_ ULONG Protect + ); + + UNICODE_STRING name; + PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx; + + RtlInitUnicodeString(&name, L"MmMapIoSpaceEx"); + pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name); + + if (pMmMapIoSpaceEx != NULL){ + // + // Call WIN10 API if available + // + return pMmMapIoSpaceEx(PhysicalAddress, + NumberOfBytes, + PAGE_READWRITE | PAGE_NOCACHE); + } + + return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached); +} + + +NTSTATUS +PLxInitializeDeviceExtension( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + This routine is called by EvtDeviceAdd. Here the device context is + initialized and all the software resources required by the device is + allocated. + +Arguments: + + DevExt Pointer to the Device Extension + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + ULONG dteCount; + WDF_IO_QUEUE_CONFIG queueConfig; + + PAGED_CODE(); + + // + // Set Maximum Transfer Length (which must be less than the SRAM size). + // + DevExt->MaximumTransferLength = PCI9656_MAXIMUM_TRANSFER_LENGTH; + if(DevExt->MaximumTransferLength > PCI9656_SRAM_SIZE) { + DevExt->MaximumTransferLength = PCI9656_SRAM_SIZE; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "MaximumTransferLength %d", DevExt->MaximumTransferLength); + + // + // Calculate the number of DMA_TRANSFER_ELEMENTS + 1 needed to + // support the MaximumTransferLength. + // + dteCount = BYTES_TO_PAGES((ULONG) ROUND_TO_PAGES( + DevExt->MaximumTransferLength) + PAGE_SIZE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "Number of DTEs %d", dteCount); + + // + // Set the number of DMA_TRANSFER_ELEMENTs (DTE) to be available. + // + DevExt->WriteTransferElements = dteCount; + DevExt->ReadTransferElements = dteCount; + + // + // The PCI9656 has two DMA Channels. This driver will use DMA Channel 0 + // as the "ToDevice" channel (Writes) and DMA Channel 1 as the + // "From Device" channel (Reads). + // + // In order to support "duplex" DMA operation (the ability to have + // concurrent reads and writes) two Dispatch Queues are created: + // one for the Write (ToDevice) requests and another for the Read + // (FromDevice) requests. While eache Dispatch Queue will operate + // independently for each other, the requests within a given Dispatch + // Queue will be serialized. This is hardware can only process one request + // per DMA Channel at a time. + // + + + // + // Setup a queue to handle only IRP_MJ_WRITE requests in Sequential + // dispatch mode. This mode ensures there is only one write request + // outstanding in the driver at any time. Framework will present the next + // request only if the current request is completed. + // Since we have configured the queue to dispatch all the specific requests + // we care about, we don't need a default queue. A default queue is + // used to receive requests that are not preconfigured to goto + // a specific queue. + // + WDF_IO_QUEUE_CONFIG_INIT ( &queueConfig, + WdfIoQueueDispatchSequential); + + queueConfig.EvtIoWrite = PLxEvtIoWrite; + + // + // Static Driver Verifier (SDV) displays a warning if it doesn't find the + // EvtIoStop callback on a power-managed queue. The 'assume' below lets + // SDV know not to worry about the EvtIoStop. + // If not explicitly set, the framework creates power-managed queues when + // the device is not a filter driver. Normally the EvtIoStop is required + // for power-managed queues, but for this driver it is not need b/c the + // driver doesn't hold on to the requests for long time or forward them to + // other drivers. + // If the EvtIoStop callback is not implemented, the framework + // waits for all in-flight (driver owned) requests to be done before + // moving the device in the Dx/sleep states or before removing the device, + // which is the correct behavior for this type of driver. + // If the requests were taking an undetermined amount of time to complete, + // or the requests were forwarded to a lower driver/another stack, the + // queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate( DevExt->Device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->WriteQueue ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed: %!STATUS!", status); + return status; + } + + // + // Set the Write Queue forwarding for IRP_MJ_WRITE requests. + // + status = WdfDeviceConfigureRequestDispatching( DevExt->Device, + DevExt->WriteQueue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "DeviceConfigureRequestDispatching failed: %!STATUS!", status); + return status; + } + + + // + // Create a new IO Queue for IRP_MJ_READ requests in sequential mode. + // + WDF_IO_QUEUE_CONFIG_INIT( &queueConfig, + WdfIoQueueDispatchSequential); + + queueConfig.EvtIoRead = PLxEvtIoRead; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests for + // long time or forward them to other drivers. + // If the EvtIoStop callback is not implemented, the framework waits for + // all driver-owned requests to be done before moving in the Dx/sleep + // states or before removing the device, which is the correct behavior + // for this type of driver. If the requests were taking an indeterminate + // amount of time to complete, or if the driver forwarded the requests + // to a lower driver/another stack, the queue should have an + // EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate( DevExt->Device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->ReadQueue ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfIoQueueCreate failed: %!STATUS!", status); + return status; + } + + // + // Set the Read Queue forwarding for IRP_MJ_READ requests. + // + status = WdfDeviceConfigureRequestDispatching( DevExt->Device, + DevExt->ReadQueue, + WdfRequestTypeRead); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "DeviceConfigureRequestDispatching failed: %!STATUS!", status); + return status; + } + + + // + // Create a WDFINTERRUPT object. + // + status = PLxInterruptCreate(DevExt); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = PLxInitializeDMA( DevExt ); + + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + + +NTSTATUS +PLxPrepareHardware( + IN PDEVICE_EXTENSION DevExt, + IN WDFCMRESLIST ResourcesTranslated + ) +/*++ +Routine Description: + + Gets the HW resources assigned by the bus driver from the start-irp + and maps it to system address space. + +Arguments: + + DevExt Pointer to our DEVICE_EXTENSION + +Return Value: + + None + +--*/ +{ + ULONG i; + NTSTATUS status = STATUS_SUCCESS; + CHAR * bar; + + BOOLEAN foundRegs = FALSE; + PHYSICAL_ADDRESS regsBasePA = {0}; + ULONG regsLength = 0; + + BOOLEAN foundSRAM = FALSE; + PHYSICAL_ADDRESS SRAMBasePA = {0}; + ULONG SRAMLength = 0; + + BOOLEAN foundSRAM2 = FALSE; + //PHYSICAL_ADDRESS SRAM2BasePA = {0}; + //ULONG SRAM2Length = 0; + + BOOLEAN foundPort = FALSE; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + + PAGED_CODE(); + + // + // Parse the resource list and save the resource information. + // + for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + desc = WdfCmResourceListGetDescriptor( ResourcesTranslated, i ); + + if(!desc) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfResourceCmGetDescriptor failed"); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + switch (desc->Type) { + + case CmResourceTypeMemory: + + bar = NULL; + + if (foundSRAM && !foundSRAM2 && + desc->u.Memory.Length == PCI9656_SRAM_SIZE) { + + //SRAM2BasePA = desc->u.Memory.Start; + //SRAM2Length = desc->u.Memory.Length; + foundSRAM2 = TRUE; + bar = "BAR3"; + } + + if (foundRegs && !foundSRAM && + desc->u.Memory.Length == PCI9656_SRAM_SIZE) { + + SRAMBasePA = desc->u.Memory.Start; + SRAMLength = desc->u.Memory.Length; + foundSRAM = TRUE; + bar = "BAR2"; + } + + if (!foundRegs && + desc->u.Memory.Length == 0x200) { + + regsBasePA = desc->u.Memory.Start; + regsLength = desc->u.Memory.Length; + foundRegs = TRUE; + bar = "BAR0"; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " - Memory Resource [%I64X-%I64X] %s", + desc->u.Memory.Start.QuadPart, + desc->u.Memory.Start.QuadPart + + desc->u.Memory.Length, + (bar) ? bar : "<unrecognized>" ); + break; + + case CmResourceTypePort: + + bar = NULL; + + if (!foundPort && + desc->u.Port.Length >= 0x100) { + foundPort = TRUE; + bar = "BAR1"; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " - Port Resource [%08I64X-%08I64X] %s", + desc->u.Port.Start.QuadPart, + desc->u.Port.Start.QuadPart + + desc->u.Port.Length, + (bar) ? bar : "<unrecognized>" ); + break; + + default: + // + // Ignore all other descriptors + // + break; + } + } + + if (!(foundRegs && foundSRAM)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "PLxMapResources: Missing resources"); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + // + // Map in the Registers Memory resource: BAR0 + // + DevExt->RegsBase = (PUCHAR) LocalMmMapIoSpace(regsBasePA, + regsLength); + + if (!DevExt->RegsBase) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " - Unable to map Registers memory %08I64X, length %d", + regsBasePA.QuadPart, regsLength); + return STATUS_INSUFFICIENT_RESOURCES; + } + + DevExt->RegsLength = regsLength; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " - Registers %p, length %d", + DevExt->RegsBase, DevExt->RegsLength ); + + // + // Set seperated pointer to PCI9656_REGS structure. + // + DevExt->Regs = (PPCI9656_REGS) DevExt->RegsBase; + + // + // Map in the SRAM Memory Space resource: BAR2 + // + DevExt->SRAMBase = (PUCHAR) LocalMmMapIoSpace(SRAMBasePA, + SRAMLength); + + if (!DevExt->SRAMBase) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + " - Unable to map SRAM memory %08I64X, length %d", + SRAMBasePA.QuadPart, SRAMLength); + return STATUS_INSUFFICIENT_RESOURCES; + } + + DevExt->SRAMLength = SRAMLength; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " - SRAM %p, length %d", + DevExt->SRAMBase, DevExt->SRAMLength ); + + return status; +} + +NTSTATUS +PLxInitializeDMA( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + Initializes the DMA adapter. + +Arguments: + + DevExt Pointer to our DEVICE_EXTENSION + +Return Value: + + None + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + // + // PLx PCI9656 DMA_TRANSFER_ELEMENTS must be 16-byte aligned + // + WdfDeviceSetAlignmentRequirement( DevExt->Device, + PCI9656_DTE_ALIGNMENT_16 ); + + // + // Create a new DMA Enabler instance. + // Use Scatter/Gather, 64-bit Addresses, Duplex-type profile. + // + { + WDF_DMA_ENABLER_CONFIG dmaConfig; + + WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, + WdfDmaProfileScatterGather64Duplex, + DevExt->MaximumTransferLength ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " - The DMA Profile is WdfDmaProfileScatterGather64Duplex"); + + status = WdfDmaEnablerCreate( DevExt->Device, + &dmaConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->DmaEnabler ); + + if (!NT_SUCCESS (status)) { + + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDmaEnablerCreate failed: %!STATUS!", status); + return status; + } + } + + // + // Allocate common buffer for building writes + // + // NOTE: This common buffer will not be cached. + // Perhaps in some future revision, cached option could + // be used. This would have faster access, but requires + // flushing before starting the DMA in PLxStartWriteDma. + // + DevExt->WriteCommonBufferSize = + sizeof(DMA_TRANSFER_ELEMENT) * DevExt->WriteTransferElements; + + _Analysis_assume_(DevExt->WriteCommonBufferSize > 0); + status = WdfCommonBufferCreate( DevExt->DmaEnabler, + DevExt->WriteCommonBufferSize, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->WriteCommonBuffer ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfCommonBufferCreate (write) failed: %!STATUS!", status); + return status; + } + + + DevExt->WriteCommonBufferBase = + WdfCommonBufferGetAlignedVirtualAddress(DevExt->WriteCommonBuffer); + + DevExt->WriteCommonBufferBaseLA = + WdfCommonBufferGetAlignedLogicalAddress(DevExt->WriteCommonBuffer); + + RtlZeroMemory( DevExt->WriteCommonBufferBase, + DevExt->WriteCommonBufferSize); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "WriteCommonBuffer 0x%p (#0x%I64X), length %I64d", + DevExt->WriteCommonBufferBase, + DevExt->WriteCommonBufferBaseLA.QuadPart, + WdfCommonBufferGetLength(DevExt->WriteCommonBuffer) ); + + // + // Allocate common buffer for building reads + // + // NOTE: This common buffer will not be cached. + // Perhaps in some future revision, cached option could + // be used. This would have faster access, but requires + // flushing before starting the DMA in PLxStartReadDma. + // + DevExt->ReadCommonBufferSize = + sizeof(DMA_TRANSFER_ELEMENT) * DevExt->ReadTransferElements; + + _Analysis_assume_(DevExt->ReadCommonBufferSize > 0); + status = WdfCommonBufferCreate( DevExt->DmaEnabler, + DevExt->ReadCommonBufferSize, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->ReadCommonBuffer ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfCommonBufferCreate (read) failed %!STATUS!", status); + return status; + } + + DevExt->ReadCommonBufferBase = + WdfCommonBufferGetAlignedVirtualAddress(DevExt->ReadCommonBuffer); + + DevExt->ReadCommonBufferBaseLA = + WdfCommonBufferGetAlignedLogicalAddress(DevExt->ReadCommonBuffer); + + RtlZeroMemory( DevExt->ReadCommonBufferBase, + DevExt->ReadCommonBufferSize); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "ReadCommonBuffer 0x%p (#0x%I64X), length %I64d", + DevExt->ReadCommonBufferBase, + DevExt->ReadCommonBufferBaseLA.QuadPart, + WdfCommonBufferGetLength(DevExt->ReadCommonBuffer) ); + + // + // Since we are using sequential queue and processing one request + // at a time, we will create transaction objects upfront and reuse + // them to do DMA transfer. Transactions objects are parented to + // DMA enabler object by default. They will be deleted along with + // along with the DMA enabler object. So need to delete them + // explicitly. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT); + + status = WdfDmaTransactionCreate( DevExt->DmaEnabler, + &attributes, + &DevExt->ReadDmaTransaction); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionCreate(read) failed: %!STATUS!", status); + return status; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TRANSACTION_CONTEXT); + // + // Create a new DmaTransaction. + // + status = WdfDmaTransactionCreate( DevExt->DmaEnabler, + &attributes, + &DevExt->WriteDmaTransaction ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionCreate(write) failed: %!STATUS!", status); + return status; + } + + return status; +} + + +NTSTATUS +PLxInitWrite( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + Initialize write data structures + +Arguments: + + DevExt Pointer to Device Extension + +Return Value: + + None + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxInitWrite"); + + // + // Make sure the Dma0 DAC (Dual Address Cycle) register is set to 0. + // + WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->Dma0_PCI_DAC, 0 ); + + // + // Clear the saved copy of the DMA Channel 0's CSR + // + DevExt->Dma0Csr.uchar = 0; + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxInitWrite"); + + return STATUS_SUCCESS; +} + + +NTSTATUS +PLxInitRead( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + Initialize read data structures + +Arguments: + + DevExt Pointer to Device Extension + +Return Value: + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxInitRead"); + + // + // Make sure the DMA Chan 1 DAC (Dual Address Cycle) is set to 0. + // + WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->Dma1_PCI_DAC, 0 ); + + // + // Clear the saved copy of the DMA Channel 1's CSR + // + DevExt->Dma1Csr.uchar = 0; + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxInitRead"); + + return STATUS_SUCCESS; +} + +VOID +PLxShutdown( + IN PDEVICE_EXTENSION DevExt + ) +/*++ + +Routine Description: + + Reset the device to put the device in a known initial state. + This is called from D0Exit when the device is torn down or + when the system is shutdown. Note that Wdf has already + called out EvtDisable callback to disable the interrupt. + +Arguments: + + DevExt - Pointer to our adapter + +Return Value: + + None + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "---> PLxShutdown"); + + // + // WdfInterrupt is already disabled so issue a full reset + // + if (DevExt->Regs) { + + PLxHardwareReset(DevExt); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<--- PLxShutdown"); +} + +VOID +PLxHardwareReset( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + Called by D0Exit when the device is being disabled or when the system is shutdown to + put the device in a known initial state. + +Arguments: + + DevExt Pointer to Device Extension + +Return Value: + +--*/ +{ + LARGE_INTEGER delay; + + union { + EEPROM_CSR bits; + ULONG ulong; + } eeCSR; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxIssueFullReset"); + + // + // Drive the 9656 into soft reset. + // + eeCSR.ulong = + READ_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat ); + + eeCSR.bits.SoftwareReset = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat, + eeCSR.ulong ); + + // + // Wait 100 msec. + // + delay.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); + + KeDelayExecutionThread( KernelMode, TRUE, &delay ); + + // + // Finally pull the 9656 out of reset. + // + eeCSR.bits.SoftwareReset = FALSE; + + WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat, + eeCSR.ulong ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxIssueFullReset"); +} + + + diff --git a/general/PLX9x5x/sys/IsrDpc.c b/general/PLX9x5x/sys/IsrDpc.c new file mode 100644 index 00000000..a7d319d3 --- /dev/null +++ b/general/PLX9x5x/sys/IsrDpc.c @@ -0,0 +1,441 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + IsrDpc.c + +Abstract: + + Contains routines related to interrupt and dpc handling. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#include "IsrDpc.tmh" + +NTSTATUS +PLxInterruptCreate( + IN PDEVICE_EXTENSION DevExt + ) +/*++ +Routine Description: + + Configure and create the WDFINTERRUPT object. + This routine is called by EvtDeviceAdd callback. + +Arguments: + + DevExt Pointer to our DEVICE_EXTENSION + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + WDF_INTERRUPT_CONFIG InterruptConfig; + + WDF_INTERRUPT_CONFIG_INIT( &InterruptConfig, + PLxEvtInterruptIsr, + PLxEvtInterruptDpc ); + + InterruptConfig.EvtInterruptEnable = PLxEvtInterruptEnable; + InterruptConfig.EvtInterruptDisable = PLxEvtInterruptDisable; + + // JOHNR: Enable testing of the DpcForIsr Synchronization + InterruptConfig.AutomaticSerialization = TRUE; + + // + // Unlike WDM, framework driver should create interrupt object in EvtDeviceAdd and + // let the framework do the resource parsing and registration of ISR with the kernel. + // Framework connects the interrupt after invoking the EvtDeviceD0Entry callback + // and disconnect before invoking EvtDeviceD0Exit. EvtInterruptEnable is called after + // the interrupt interrupt is connected and EvtInterruptDisable before the interrupt is + // disconnected. + // + status = WdfInterruptCreate( DevExt->Device, + &InterruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &DevExt->Interrupt ); + + if( !NT_SUCCESS(status) ) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfInterruptCreate failed: %!STATUS!", status); + } + + return status; +} + +BOOLEAN +PLxEvtInterruptIsr( + IN WDFINTERRUPT Interrupt, + IN ULONG MessageID + ) +/*++ +Routine Description: + + Interrupt handler for this driver. Called at DIRQL level when the + device or another device sharing the same interrupt line asserts + the interrupt. The driver first checks the device to make sure whether + this interrupt is generated by its device and if so clear the interrupt + register to disable further generation of interrupts and queue a + DPC to do other I/O work related to interrupt - such as reading + the device memory, starting a DMA transaction, coping it to + the request buffer and completing the request, etc. + +Arguments: + + Interupt - Handle to WDFINTERRUPT Object for this device. + MessageID - MSI message ID (always 0 in this configuration) + +Return Value: + + TRUE -- This device generated the interrupt. + FALSE -- This device did not generated this interrupt. + +--*/ +{ + PDEVICE_EXTENSION devExt; + BOOLEAN isRecognized = FALSE; + + union { + INT_CSR bits; + ULONG ulong; + } intCsr; + + UNREFERENCED_PARAMETER(MessageID); + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + // "--> PLxInterruptHandler"); + + devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); + + // + // Read the Interrupt CSR register (INTCSR) + // + intCsr.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); + + // + // Is DMA channel 0 (Write-side) Active? + // + if (intCsr.bits.DmaChan0IntActive) { + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + " Interrupt for DMA Channel 0 (write)"); + + devExt->IntCsr.bits.DmaChan0IntActive = TRUE; + + // + // Clear this interrupt. + // + devExt->Dma0Csr.uchar = + READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr ); + + devExt->Dma0Csr.bits.Clear = TRUE; + + WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr, + devExt->Dma0Csr.uchar ); + + isRecognized = TRUE; + } + + // + // Is DMA channel 1 (Read-side) Active? + // + if (intCsr.bits.DmaChan1IntActive) { + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + " Interrupt for DMA Channel 1 (read)"); + + devExt->IntCsr.bits.DmaChan1IntActive = TRUE; + + // + // Clear this interrupt. + // + devExt->Dma1Csr.uchar = + READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr ); + + devExt->Dma1Csr.bits.Clear = TRUE; + + WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr, + devExt->Dma1Csr.uchar ); + + isRecognized = TRUE; + } + + if ((isRecognized) && + ((devExt->Dma0Csr.bits.Done) || + (devExt->Dma1Csr.bits.Done))) { + // + // A read or a write or both is done. Queue a DPC. + // + WdfInterruptQueueDpcForIsr( devExt->Interrupt ); + } + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + // "<-- PLxInterruptHandler"); + + return isRecognized; +} + +_Use_decl_annotations_ +VOID +PLxEvtInterruptDpc( + WDFINTERRUPT Interrupt, + WDFOBJECT Device + ) +/*++ + +Routine Description: + + DPC callback for ISR. Please note that on a multiprocessor system, + you could have more than one DPCs running simulataneously on + multiple processors. So if you are accesing any global resources + make sure to synchrnonize the accesses with a spinlock. + +Arguments: + + Interupt - Handle to WDFINTERRUPT Object for this device. + Device - WDFDEVICE object passed to InterruptCreate + +Return Value: + +--*/ +{ + NTSTATUS status; + WDFDMATRANSACTION dmaTransaction; + PDEVICE_EXTENSION devExt; + BOOLEAN writeInterrupt = FALSE; + BOOLEAN readInterrupt = FALSE; + + UNREFERENCED_PARAMETER(Device); + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "--> EvtInterruptDpc"); + + devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); + + // + // Acquire this device's InterruptSpinLock. + // + WdfInterruptAcquireLock( Interrupt ); + + + if ((devExt->IntCsr.bits.DmaChan0IntActive) && + (devExt->Dma0Csr.bits.Done)) { + + // + // If Dma0 channel 0 (write) is interrupting and the + // Done bit is set in the Dma0 CSR, + // we're interrupting because a WRITE is complete. + // Clear the done bit and channel interrupting bit from + // our copies... + // + devExt->IntCsr.bits.DmaChan0IntActive = FALSE; + devExt->Dma0Csr.uchar = 0; + + writeInterrupt = TRUE; + } + + if ((devExt->IntCsr.bits.DmaChan1IntActive) && + (devExt->Dma1Csr.bits.Done)) { + + // + // If DMA channel 1 is interrupting and the + // DONE bit is set in the DMA1 control/status + // register, we're interrupting because a READ + // is complete. + // Clear the done bit and channel interrupting bit from + // our copies... + // + devExt->IntCsr.bits.DmaChan1IntActive = FALSE; + devExt->Dma0Csr.uchar = 0; + + readInterrupt = TRUE; + } + + // + // Release our interrupt spinlock + // + WdfInterruptReleaseLock( Interrupt ); + + // + // Did a Write DMA complete? + // + if (writeInterrupt) { + + BOOLEAN transactionComplete; + + // + // Get the current Write DmaTransaction. + // + dmaTransaction = devExt->WriteDmaTransaction; + + // + // Indicate this DMA operation has completed: + // This may drive the transfer on the next packet if + // there is still data to be transfered in the request. + // + transactionComplete = WdfDmaTransactionDmaCompleted( dmaTransaction, + &status ); + + if (transactionComplete) { + // + // Complete this DmaTransaction. + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, + "Completing Write request in the DpcForIsr"); + + PLxWriteRequestComplete( dmaTransaction, status ); + + } + } + + // + // Did a Read DMA complete? + // + if (readInterrupt) { + + BOOLEAN transactionComplete; + PDMA_TRANSFER_ELEMENT dteVA; + size_t length; + + // + // Get the current Read DmaTransaction. + // + dmaTransaction = devExt->ReadDmaTransaction; + + // + // Only on Read-side -- + // Use "DMA Clear-Count Mode" to get complemetary + // transferred byte count. + // + length = WdfDmaTransactionGetCurrentDmaTransferLength( dmaTransaction ); + + dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase; + + while(dteVA->DescPtr.LastElement == FALSE) { + length -= dteVA->TransferSize; + dteVA++; + } + length -= dteVA->TransferSize; + + // + // Indicate this DMA operation has completed: + // This may drive the transfer on the next packet if + // there is still data to be transfered in the request. + // + transactionComplete = + WdfDmaTransactionDmaCompletedWithLength( dmaTransaction, + length, + &status ); + + if (transactionComplete) { + // + // Complete this DmaTransaction. + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, + "Completing Read request in the DpcForIsr"); + + PLxReadRequestComplete( dmaTransaction, status ); + + } + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "<-- EvtInterruptDpc"); + + return; +} + +NTSTATUS +PLxEvtInterruptEnable( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + Called by the framework at DIRQL immediately after registering the ISR with the kernel + by calling IoConnectInterrupt. + +Return Value: + + NTSTATUS +--*/ +{ + PDEVICE_EXTENSION devExt; + + union { + INT_CSR bits; + ULONG ulong; + } intCSR; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + "PLxEvtInterruptEnable: Interrupt 0x%p, Device 0x%p\n", + Interrupt, Device); + + devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); + + intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); + + intCSR.bits.PciIntEnable = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, + intCSR.ulong ); + + return STATUS_SUCCESS; +} + +NTSTATUS +PLxEvtInterruptDisable( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + Called by the framework at DIRQL before Deregistering the ISR with the kernel + by calling IoDisconnectInterrupt. + +Return Value: + + NTSTATUS +--*/ +{ + PDEVICE_EXTENSION devExt; + + union { + INT_CSR bits; + ULONG ulong; + } intCSR; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INTERRUPT, + "PLxEvtInterruptDisable: Interrupt 0x%p, Device 0x%p\n", + Interrupt, Device); + + devExt = PLxGetDeviceContext(WdfInterruptGetDevice(Interrupt)); + + intCSR.ulong = READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); + + intCSR.bits.PciIntEnable = FALSE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, + intCSR.ulong ); + + return STATUS_SUCCESS; +} diff --git a/general/PLX9x5x/sys/Pci9656.c b/general/PLX9x5x/sys/Pci9656.c new file mode 100644 index 00000000..176b9ca7 --- /dev/null +++ b/general/PLX9x5x/sys/Pci9656.c @@ -0,0 +1,623 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Pci9656.c + +Abstract: + + This is a generic WDF sample driver for PLx PCI9656RDK-Lite reference + adapter. It illustrates how to use the WDF DmaObject to perform + Scatter/Gather DMA operations. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in toaster.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated by the WPP preprocessor. +// +#include "Pci9656.tmh" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, PLxEvtDeviceAdd) +#pragma alloc_text (PAGE, PLxEvtDevicePrepareHardware) +#pragma alloc_text (PAGE, PLxEvtDeviceReleaseHardware) +#pragma alloc_text (PAGE, PLxEvtDeviceD0Exit) +#pragma alloc_text (PAGE, PlxEvtDriverContextCleanup) +#pragma alloc_text (PAGE, PLxSetIdleAndWakeSettings) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + NTSTATUS - if the status value is not STATUS_SUCCESS, + the driver will get unloaded immediately. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attributes; + + // + // Initialize WDF WPP tracing. + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + // + // TraceEvents function is mapped to DoTraceMessage provided by + // WPP by using a directive in the sources file. + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Pci9656 Sample - Driver Framework Edition."); + + // + // Initialize the Driver Config structure. + // + WDF_DRIVER_CONFIG_INIT( &config, PLxEvtDeviceAdd ); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = PlxEvtDriverContextCleanup; + + status = WdfDriverCreate( DriverObject, + RegistryPath, + &attributes, + &config, + WDF_NO_HANDLE); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDriverCreate failed with status %!STATUS!", status); + // + // Cleanup tracing here because DriverContextCleanup will not be called + // as we have failed to create WDFDRIVER object itself. + // Please note that if your return failure from DriverEntry after the + // WDFDRIVER object is created successfully, you don't have to + // call WPP cleanup because in those cases DriverContextCleanup + // will be executed when the framework deletes the DriverObject. + // + WPP_CLEANUP(DriverObject); + } + + return status; +} + + +NTSTATUS +PLxEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. Here the driver should register all the + PNP, power and Io callbacks, register interfaces and allocate other + software resources required by the device. The driver can query + any interfaces or get the config space information from the bus driver + but cannot access hardware registers or initialize the device. + +Arguments: + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES attributes; + WDFDEVICE device; + PDEVICE_EXTENSION devExt = NULL; + + UNREFERENCED_PARAMETER( Driver ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxEvtDeviceAdd"); + + PAGED_CODE(); + + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); + + // + // Zero out the PnpPowerCallbacks structure. + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Set Callbacks for any of the functions we are interested in. + // If no callback is set, Framework will take the default action + // by itself. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = PLxEvtDevicePrepareHardware; + pnpPowerCallbacks.EvtDeviceReleaseHardware = PLxEvtDeviceReleaseHardware; + + // + // These two callbacks set up and tear down hardware state that must be + // done every time the device moves in and out of the D0-working state. + // + pnpPowerCallbacks.EvtDeviceD0Entry = PLxEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = PLxEvtDeviceD0Exit; + + // + // Register the PnP Callbacks.. + // + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Initialize Fdo Attributes. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_EXTENSION); + // + // By opting for SynchronizationScopeDevice, we tell the framework to + // synchronize callbacks events of all the objects directly associated + // with the device. In this driver, we will associate queues and + // and DpcForIsr. By doing that we don't have to worrry about synchronizing + // access to device-context by Io Events and DpcForIsr because they would + // not concurrently ever. Framework will serialize them by using an + // internal device-lock. + // + attributes.SynchronizationScope = WdfSynchronizationScopeDevice; + + // + // Create the device + // + status = WdfDeviceCreate( &DeviceInit, &attributes, &device ); + + if (!NT_SUCCESS(status)) { + // + // Device Initialization failed. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "DeviceCreate failed %!STATUS!", status); + return status; + } + + // + // Get the DeviceExtension and initialize it. PLxGetDeviceContext is an inline function + // defined by WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro in the + // private header file. This function will do the type checking and return + // the device context. If you pass a wrong object a wrong object handle + // it will return NULL and assert if run under framework verifier mode. + // + devExt = PLxGetDeviceContext(device); + + devExt->Device = device; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + " AddDevice PDO (0x%p) FDO (0x%p), DevExt (0x%p)", + WdfDeviceWdmGetPhysicalDevice(device), + WdfDeviceWdmGetDeviceObject(device), devExt); + + // + // Tell the Framework that this device will need an interface + // + // NOTE: See the note in Public.h concerning this GUID value. + // + status = WdfDeviceCreateDeviceInterface( device, + (LPGUID) &GUID_PLX_INTERFACE, + NULL ); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "<-- DeviceCreateDeviceInterface " + "failed %!STATUS!", status); + return status; + } + + // + // Set the idle and wait-wake policy for this device. + // + status = PLxSetIdleAndWakeSettings(devExt); + + if (!NT_SUCCESS (status)) { + // + // NOTE: The attempt to set the Idle and Wake options + // is a best-effort try. Failure is probably due to + // the non-driver environmentals, such as the system, + // bus or OS indicating that Wake is not supported for + // this case. + // All that being said, it probably not desirable to + // return the failure code as it would cause the + // AddDevice to fail and Idle and Wake are probably not + // "must-have" options. + // + // You must decide for your case whether Idle/Wake are + // "must-have" options...but my guess is probably not. + // +#if 1 + status = STATUS_SUCCESS; +#else + return status; +#endif + } + + // + // Initalize the Device Extension. + // + status = PLxInitializeDeviceExtension(devExt); + + if (!NT_SUCCESS(status)) { + return status; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PLxEvtDeviceAdd %!STATUS!", status); + + return status; +} + +NTSTATUS +PLxEvtDevicePrepareHardware ( + WDFDEVICE Device, + WDFCMRESLIST Resources, + WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + Performs whatever initialization is needed to setup the device, setting up + a DMA channel or mapping any I/O port resources. This will only be called + as a device starts or restarts, not every time the device moves into the D0 + state. Consequently, most hardware initialization belongs elsewhere. + +Arguments: + + Device - A handle to the WDFDEVICE + + Resources - The raw PnP resources associated with the device. Most of the + time, these aren't useful for a PCI device. + + ResourcesTranslated - The translated PnP resources associated with the + device. This is what is important to a PCI device. + +Return Value: + + NT status code - failure will result in the device stack being torn down + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PDEVICE_EXTENSION devExt; + + UNREFERENCED_PARAMETER(Resources); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PLxEvtDevicePrepareHardware"); + + devExt = PLxGetDeviceContext(Device); + + status = PLxPrepareHardware(devExt, ResourcesTranslated); + if (!NT_SUCCESS (status)){ + return status; + } + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PLxEvtDevicePrepareHardware, status %!STATUS!", status); + + return status; +} + +NTSTATUS +PLxEvtDeviceReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + Unmap the resources that were mapped in PLxEvtDevicePrepareHardware. + This will only be called when the device stopped for resource rebalance, + surprise-removed or query-removed. + +Arguments: + + Device - A handle to the WDFDEVICE + + ResourcesTranslated - The translated PnP resources associated with the + device. This is what is important to a PCI device. + +Return Value: + + NT status code - failure will result in the device stack being torn down + +--*/ +{ + PDEVICE_EXTENSION devExt; + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(ResourcesTranslated); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PLxEvtDeviceReleaseHardware"); + + devExt = PLxGetDeviceContext(Device); + + if (devExt->RegsBase) { + + MmUnmapIoSpace(devExt->RegsBase, devExt->RegsLength); + devExt->RegsBase = NULL; + } + + if(devExt->SRAMBase){ + MmUnmapIoSpace(devExt->SRAMBase, devExt->SRAMLength); + devExt->SRAMBase = NULL; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PLxEvtDeviceReleaseHardware"); + + return status; +} + + +NTSTATUS +PLxEvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + This routine prepares the device for use. It is called whenever the device + enters the D0 state, which happens when the device is started, when it is + restarted, and when it has been powered off. + + Note that interrupts will not be enabled at the time that this is called. + They will be enabled after this callback completes. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - The handle to the WDF device object + + PreviousState - The state the device was in before this callback was invoked. + +Return Value: + + NTSTATUS + + Success implies that the device can be used. + + Failure will result in the device stack being torn down. + +--*/ +{ + PDEVICE_EXTENSION devExt; + NTSTATUS status; + + UNREFERENCED_PARAMETER(PreviousState); + + devExt = PLxGetDeviceContext(Device); + + status = PLxInitWrite( devExt ); + if (NT_SUCCESS(status)) { + + status = PLxInitRead( devExt ); + + } + + return status; +} + +NTSTATUS +PLxEvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in PLxEvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device + is stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + Note that interrupts have already been disabled by the time that this + callback is invoked. + +Arguments: + + Device - The handle to the WDF device object + + TargetState - The state the device will go to when this callback completes. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + PDEVICE_EXTENSION devExt; + + PAGED_CODE(); + + devExt = PLxGetDeviceContext(Device); + + switch (TargetState) { + case WdfPowerDeviceD1: + case WdfPowerDeviceD2: + case WdfPowerDeviceD3: + + // + // Fill in any code to save hardware state here. + // + + // + // Fill in any code to put the device in a low-power state here. + // + break; + + case WdfPowerDevicePrepareForHibernation: + + // + // Fill in any code to save hardware state here. Do not put in any + // code to shut the device off. If this device cannot support being + // in the paging path (or being a parent or grandparent of a paging + // path device) then this whole case can be deleted. + // + + break; + + case WdfPowerDeviceD3Final: + default: + + // + // Reset the hardware, as we're shutting down for the last time. + // + PLxShutdown(devExt); + break; + } + + return STATUS_SUCCESS; +} + + +_Use_decl_annotations_ +VOID +PlxEvtDriverContextCleanup( + WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free all the resources allocated in DriverEntry. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PAGED_CODE (); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "PlxEvtDriverContextCleanup: enter"); + + WPP_CLEANUP( WdfDriverWdmGetDriverObject( Driver ) ); + +} + + + +NTSTATUS +PLxSetIdleAndWakeSettings( + IN PDEVICE_EXTENSION FdoData + ) +/*++ +Routine Description: + + Called by EvtDeviceAdd to set the idle and wait-wake policy. Registering this policy + causes Power Management Tab to show up in the device manager. By default these + options are enabled and the user is provided control to change the settings. + +Return Value: + + NTSTATUS - Failure status is returned if the device is not capable of suspending + or wait-waking the machine by an external event. Framework checks the + capability information reported by the bus driver to decide whether the device is + capable of waking the machine. + +--*/ +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxSetIdleAndWakeSettings"); + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCanWakeFromS0); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(FdoData->Device, &idleSettings); + if ( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "DeviceSetPowerPolicyS0IdlePolicy failed %!STATUS!", status); + return status; + } + + // + // Init wait-wake policy structure. + // + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + + status = WdfDeviceAssignSxWakeSettings(FdoData->Device, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "DeviceAssignSxWakeSettings failed %!STATUS!", status); + return status; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxSetIdleAndWakeSettings"); + + return status; +} + + diff --git a/general/PLX9x5x/sys/Pci9656.h b/general/PLX9x5x/sys/Pci9656.h new file mode 100644 index 00000000..48e9260d --- /dev/null +++ b/general/PLX9x5x/sys/Pci9656.h @@ -0,0 +1,14 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Driver for PLx PCI9656RDK-Lite Adapter" +#define VER_INTERNALNAME_STR "PCI9656.sys" +#define VER_ORIGINALFILENAME_STR "PCI9656.sys" + +#include "common.ver" + + + diff --git a/general/PLX9x5x/sys/Pci9656.rc b/general/PLX9x5x/sys/Pci9656.rc new file mode 100644 index 00000000..48e9260d --- /dev/null +++ b/general/PLX9x5x/sys/Pci9656.rc @@ -0,0 +1,14 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDF Driver for PLx PCI9656RDK-Lite Adapter" +#define VER_INTERNALNAME_STR "PCI9656.sys" +#define VER_ORIGINALFILENAME_STR "PCI9656.sys" + +#include "common.ver" + + + diff --git a/general/PLX9x5x/sys/Pci9x5x.vcxproj b/general/PLX9x5x/sys/Pci9x5x.vcxproj new file mode 100644 index 00000000..7493d098 --- /dev/null +++ b/general/PLX9x5x/sys/Pci9x5x.vcxproj @@ -0,0 +1,221 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{12A2C4C0-856A-49BE-9F54-30D4D040C3E9}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <KMDF_VERSION_MINOR>9</KMDF_VERSION_MINOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{0DB7EDF4-ADCA-4623-A75A-2D53E0B95D89}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="Pci9656.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="Init.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="IsrDpc.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="Read.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="Write.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <Inf Include=".\pci9x5x.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\pci9x5x.inf</CopyOutput> + </Inf> + <OtherWpp Include="Pci9656.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>Pci9x5x</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>Pci9x5x</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>Pci9x5x</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>Pci9x5x</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="Pci9656.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/PLX9x5x/sys/Pci9x5x.vcxproj.Filters b/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters new file mode 100644 index 00000000..1cf6e8b2 --- /dev/null +++ b/general/PLX9x5x/sys/Pci9x5x.vcxproj.Filters @@ -0,0 +1,54 @@ +<?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>{CFE8A049-4352-4797-A933-02B2457B9660}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{EA19AC8F-5C37-4641-AAFA-4924984AF0F7}</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>{D407D40B-9D6E-4731-85DE-808B502FF92E}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{39E92CE4-17AE-463E-B0CB-746990AE72D1}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Init.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="IsrDpc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Pci9656.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="precompsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Read.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Write.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\pci9x5x.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\pci9x5x.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Pci9656.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/PLX9x5x/sys/Precomp.h b/general/PLX9x5x/sys/Precomp.h new file mode 100644 index 00000000..ada4939a --- /dev/null +++ b/general/PLX9x5x/sys/Precomp.h @@ -0,0 +1,17 @@ +#define WIN9X_COMPAT_SPINLOCK +#include <ntddk.h> +#pragma warning(disable:4201) // nameless struct/union warning + +#include <stdarg.h> +#include <wdf.h> + +#pragma warning(default:4201) + +#include <initguid.h> // required for GUID definitions +#include <wdmguid.h> // required for WMILIB_CONTEXT + +#include "Reg9656.h" +#include "Public.h" +#include "Private.h" +#include "trace.h" + diff --git a/general/PLX9x5x/sys/Private.h b/general/PLX9x5x/sys/Private.h new file mode 100644 index 00000000..8eae7a45 --- /dev/null +++ b/general/PLX9x5x/sys/Private.h @@ -0,0 +1,211 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Private.h + +Abstract: + +Environment: + + Kernel mode + +--*/ + + +#if !defined(_PCI9656_H_) +#define _PCI9659_H_ + +// +// The device extension for the device object +// +typedef struct _DEVICE_EXTENSION { + + WDFDEVICE Device; + + // Following fields are specific to the hardware + // Configuration + + // HW Resources + PPCI9656_REGS Regs; // Registers address + PUCHAR RegsBase; // Registers base address + ULONG RegsLength; // Registers base length + + PUCHAR PortBase; // Port base address + ULONG PortLength; // Port base length + + PUCHAR SRAMBase; // SRAM base address + ULONG SRAMLength; // SRAM base length + + PUCHAR SRAM2Base; // SRAM (alt) base address + ULONG SRAM2Length; // SRAM (alt) base length + + WDFINTERRUPT Interrupt; // Returned by InterruptCreate + + union { + INT_CSR bits; + ULONG ulong; + } IntCsr; + + union { + DMA_CSR bits; + UCHAR uchar; + } Dma0Csr; + + union { + DMA_CSR bits; + UCHAR uchar; + } Dma1Csr; + + // DmaEnabler + WDFDMAENABLER DmaEnabler; + ULONG MaximumTransferLength; + + // Write + WDFQUEUE WriteQueue; + + WDFDMATRANSACTION WriteDmaTransaction; + + ULONG WriteTransferElements; + WDFCOMMONBUFFER WriteCommonBuffer; + size_t WriteCommonBufferSize; + _Field_size_(WriteCommonBufferSize) PUCHAR WriteCommonBufferBase; + PHYSICAL_ADDRESS WriteCommonBufferBaseLA; // Logical Address + + // Read + ULONG ReadTransferElements; + WDFCOMMONBUFFER ReadCommonBuffer; + size_t ReadCommonBufferSize; + _Field_size_(ReadCommonBufferSize) PUCHAR ReadCommonBufferBase; + PHYSICAL_ADDRESS ReadCommonBufferBaseLA; // Logical Address + + WDFDMATRANSACTION ReadDmaTransaction; + + WDFQUEUE ReadQueue; + + ULONG HwErrCount; + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +// +// This will generate the function named PLxGetDeviceContext to be use for +// retreiving the DEVICE_EXTENSION pointer. +// +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, PLxGetDeviceContext) + +#if !defined(ASSOC_WRITE_REQUEST_WITH_DMA_TRANSACTION) +// +// The context structure used with WdfDmaTransactionCreate +// +typedef struct TRANSACTION_CONTEXT { + + WDFREQUEST Request; + +} TRANSACTION_CONTEXT, * PTRANSACTION_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(TRANSACTION_CONTEXT, PLxGetTransactionContext) + +#endif + +// +// Function prototypes +// +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD PLxEvtDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP PlxEvtDriverContextCleanup; + +EVT_WDF_DEVICE_D0_ENTRY PLxEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT PLxEvtDeviceD0Exit; +EVT_WDF_DEVICE_PREPARE_HARDWARE PLxEvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE PLxEvtDeviceReleaseHardware; + +EVT_WDF_IO_QUEUE_IO_READ PLxEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE PLxEvtIoWrite; + +EVT_WDF_INTERRUPT_ISR PLxEvtInterruptIsr; +EVT_WDF_INTERRUPT_DPC PLxEvtInterruptDpc; +EVT_WDF_INTERRUPT_ENABLE PLxEvtInterruptEnable; +EVT_WDF_INTERRUPT_DISABLE PLxEvtInterruptDisable; + +NTSTATUS +PLxSetIdleAndWakeSettings( + IN PDEVICE_EXTENSION FdoData + ); + +NTSTATUS +PLxInitializeDeviceExtension( + IN PDEVICE_EXTENSION DevExt + ); + +NTSTATUS +PLxPrepareHardware( + IN PDEVICE_EXTENSION DevExt, + IN WDFCMRESLIST ResourcesTranslated + ); + +NTSTATUS +PLxInitRead( + IN PDEVICE_EXTENSION DevExt + ); + +NTSTATUS +PLxInitWrite( + IN PDEVICE_EXTENSION DevExt + ); + +// +// WDFINTERRUPT Support +// +NTSTATUS +PLxInterruptCreate( + IN PDEVICE_EXTENSION DevExt + ); + +VOID +PLxReadRequestComplete( + IN WDFDMATRANSACTION DmaTransaction, + IN NTSTATUS Status + ); + +VOID +PLxWriteRequestComplete( + IN WDFDMATRANSACTION DmaTransaction, + IN NTSTATUS Status + ); + +NTSTATUS +PLxInitializeHardware( + IN PDEVICE_EXTENSION DevExt + ); + +VOID +PLxShutdown( + IN PDEVICE_EXTENSION DevExt + ); + +EVT_WDF_PROGRAM_DMA PLxEvtProgramReadDma; +EVT_WDF_PROGRAM_DMA PLxEvtProgramWriteDma; + +VOID +PLxHardwareReset( + IN PDEVICE_EXTENSION DevExt + ); + +NTSTATUS +PLxInitializeDMA( + IN PDEVICE_EXTENSION DevExt + ); + +#pragma warning(disable:4127) // avoid conditional expression is constant error with W4 + +#endif // _PCI9656_H_ + diff --git a/general/PLX9x5x/sys/Public.h b/general/PLX9x5x/sys/Public.h new file mode 100644 index 00000000..16c425ae --- /dev/null +++ b/general/PLX9x5x/sys/Public.h @@ -0,0 +1,35 @@ +/*++ + Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + +Environment: + + user and kernel + +--*/ + +// +// The following value is arbitrarily chosen from the space defined +// by Microsoft as being "for non-Microsoft use" +// +// NOTE: we use OSR's GUID_OSR_PLX_INTERFACE GUID value so that we +// can use OSR's PLxTest program :-) +// +// {29D2A384-2E47-49b5-AEBF-6962C22BD7C2} +DEFINE_GUID (GUID_PLX_INTERFACE, + 0x29d2a384, 0x2e47, 0x49b5, 0xae, 0xbf, 0x69, 0x62, 0xc2, 0x2b, 0xd7, 0xc2); + + diff --git a/general/PLX9x5x/sys/Read.c b/general/PLX9x5x/sys/Read.c new file mode 100644 index 00000000..319cf094 --- /dev/null +++ b/general/PLX9x5x/sys/Read.c @@ -0,0 +1,453 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Read.c + +Abstract: + + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#include "Read.tmh" + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +VOID +PLxEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + Called by the framework as soon as it receives a read request. + If the device is not ready, fail the request. + Otherwise get scatter-gather list for this request and send the + packet to the hardware for DMA. + +Arguments: + + Queue - Default queue handle + Request - Handle to the write request + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PDEVICE_EXTENSION devExt; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "--> PLxEvtIoRead: Request %p", Request); + + // + // Get the DevExt from the Queue handle + // + devExt = PLxGetDeviceContext(WdfIoQueueGetDevice(Queue)); + + do { + // + // Validate the Length parameter. + // + if (Length > PCI9656_SRAM_SIZE) { + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + // + // Initialize this new DmaTransaction. + // + status = WdfDmaTransactionInitializeUsingRequest( + devExt->ReadDmaTransaction, + Request, + PLxEvtProgramReadDma, + WdfDmaDirectionReadFromDevice ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfDmaTransactionInitializeUsingRequest " + "failed: %!STATUS!", status); + break; + } + +#if 0 // FYI + // + // Modify the MaximumLength for this DmaTransaction only. + // + // Note: The new length must be less than or equal to that set when + // the DmaEnabler was created. + // + { + ULONG length = devExt->MaximumTransferLength / 2; + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + // "Setting a new MaxLen %d\n", length); + + WdfDmaTransactionSetMaximumLength( devExt->ReadDmaTransaction, + length ); + } +#endif + + // + // Execute this DmaTransaction. + // + status = WdfDmaTransactionExecute( devExt->ReadDmaTransaction, + WDF_NO_CONTEXT); + + if(!NT_SUCCESS(status)) { + // + // Couldn't execute this DmaTransaction, so fail Request. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "WdfDmaTransactionExecute failed: %!STATUS!", status); + break; + } + + // + // Indicate that Dma transaction has been started successfully. + // The request will be complete by the Dpc routine when the DMA + // transaction completes. + // + status = STATUS_SUCCESS; + + } while (0); + + // + // If there are errors, then clean up and complete the Request. + // + if (!NT_SUCCESS(status )) { + WdfDmaTransactionRelease(devExt->ReadDmaTransaction); + WdfRequestComplete(Request, status); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "<-- PLxEvtIoRead: status %!STATUS!", status); + + return; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +BOOLEAN +PLxEvtProgramReadDma( + IN WDFDMATRANSACTION Transaction, + IN WDFDEVICE Device, + IN WDFCONTEXT Context, + IN WDF_DMA_DIRECTION Direction, + IN PSCATTER_GATHER_LIST SgList + ) +/*++ + +Routine Description: + + The framework calls a driver's EvtProgramDma event callback function + when the driver calls WdfDmaTransactionExecute and the system has + enough map registers to do the transfer. The callback function must + program the hardware to start the transfer. A single transaction + initiated by calling WdfDmaTransactionExecute may result in multiple + calls to this function if the buffer is too large and there aren't + enough map registers to do the whole transfer. + + +Arguments: + +Return Value: + +--*/ +{ + PDEVICE_EXTENSION devExt; + size_t offset; + PDMA_TRANSFER_ELEMENT dteVA; + ULONG_PTR dteLA; + BOOLEAN errors; + ULONG i; + + UNREFERENCED_PARAMETER( Context ); + UNREFERENCED_PARAMETER( Direction ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "--> PLxEvtProgramReadDma"); + + // + // Initialize locals + // + devExt = PLxGetDeviceContext(Device); + errors = FALSE; + + // + // Get the number of bytes as the offset to the beginning of this + // Dma operations transfer location in the buffer. + // + offset = WdfDmaTransactionGetBytesTransferred(Transaction); + + // + // Setup the pointer to the next DMA_TRANSFER_ELEMENT + // for both virtual and physical address references. + // + dteVA = (PDMA_TRANSFER_ELEMENT) devExt->ReadCommonBufferBase; + dteLA = (devExt->ReadCommonBufferBaseLA.LowPart + + sizeof(DMA_TRANSFER_ELEMENT)); + + // + // Translate the System's SCATTER_GATHER_LIST elements + // into the device's DMA_TRANSFER_ELEMENT elements. + // + for (i=0; i < SgList->NumberOfElements; i++) { + + // + // Construct this DTE. + // + // NOTE: The LocalAddress is the offset into the SRAM from + // where this Read will start. + // + dteVA->PciAddressLow = SgList->Elements[i].Address.LowPart; + dteVA->PciAddressHigh = SgList->Elements[i].Address.HighPart; + dteVA->TransferSize = SgList->Elements[i].Length; + + dteVA->LocalAddress = (ULONG) offset; + + dteVA->DescPtr.DescLocation = DESC_PTR_DESC_LOCATION__PCI; + dteVA->DescPtr.TermCountInt = FALSE; + dteVA->DescPtr.LastElement = FALSE; + dteVA->DescPtr.DirOfTransfer = DESC_PTR_DIRECTION__FROM_DEVICE; + dteVA->DescPtr.Address = DESC_PTR_ADDR( dteLA ); + + // + // Increment the DmaTransaction length by this element length + // + offset += SgList->Elements[i].Length; + + // + // If at end of SgList, then set LastElement bit in final NTE. + // + if (i == SgList->NumberOfElements - 1) { + + dteVA->DescPtr.LastElement = TRUE; + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + // "\tDTE[%d] : Addr #%X%08X Len %5d, Local %08X, " + // "Loc(%d), Last(%d), TermInt(%d), ToPci(%d)\n", + // i, + // dteVA->PciAddressHigh, + // dteVA->PciAddressLow, + // dteVA->TransferSize, + // dteVA->LocalAddress, + // dteVA->DescPtr.DescLocation, + // dteVA->DescPtr.LastElement, + // dteVA->DescPtr.TermCountInt, + // dteVA->DescPtr.DirOfTransfer ); + break; + } + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + // "\tDTE[%d] : Addr #%X%08X Len %5d, Local %08X, " + // "Loc(%d), Last(%d), TermInt(%d), ToPci(%d)\n", + // i, + // dteVA->PciAddressHigh, + // dteVA->PciAddressLow, + // dteVA->TransferSize, + // dteVA->LocalAddress, + // dteVA->DescPtr.DescLocation, + // dteVA->DescPtr.LastElement, + // dteVA->DescPtr.TermCountInt, + // dteVA->DescPtr.DirOfTransfer ); + + // + // Adjust the next DMA_TRANSFER_ELEMEMT + // + dteVA++; + dteLA += sizeof(DMA_TRANSFER_ELEMENT); + } + + // + // Start the DMA operation. + // Acquire this device's InterruptSpinLock. + // + WdfInterruptAcquireLock( devExt->Interrupt ); + + // + // DMA 1 Mode Register - (DMAMODE1) + // Enable Scatter/Gather Mode, Interrupt On Done, + // and route Ints to PCI. + // + { + union { + DMA_MODE bits; + ULONG ulong; + } dmaMode; + + dmaMode.ulong = + READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma1_Mode ); + + dmaMode.bits.SgModeEnable = TRUE; + dmaMode.bits.DoneIntEnable = TRUE; + dmaMode.bits.IntToPci = TRUE; + + dmaMode.bits.ClearCountMode = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma1_Mode, + dmaMode.ulong ); + } + + // + // Interrupt CSR Register - (INTCSR) + // Enable PCI Ints and DMA Channel 1 Ints. + // + { + union { + INT_CSR bits; + ULONG ulong; + } intCSR; + + intCSR.ulong = + READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); + + intCSR.bits.PciIntEnable = TRUE; + intCSR.bits.DmaChan1IntEnable = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, + intCSR.ulong ); + } + + // + // DMA 1 Descriptor Pointer Register - (DMADPR1) + // Write the base LOGICAL address of the DMA_TRANSFER_ELEMENT list. + // + { + union { + DESC_PTR bits; + ULONG ulong; + } ptr; + + ptr.bits.DescLocation = DESC_PTR_DESC_LOCATION__PCI; + ptr.bits.TermCountInt = TRUE; + ptr.bits.Address = + DESC_PTR_ADDR( devExt->ReadCommonBufferBaseLA.LowPart ); + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma1_Desc_Ptr, + ptr.ulong ); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + " PLxEvtProgramReadDma: Start a Read DMA operation"); + + // + // DMA 1 CSR Register - (DMACSR1) + // Start the DMA operation: Set Enable and Start bits. + // + { + union { + DMA_CSR bits; + UCHAR uchar; + } dmaCSR; + + dmaCSR.uchar = + READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr ); + + dmaCSR.bits.Enable = TRUE; + dmaCSR.bits.Start = TRUE; + + WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma1_Csr, + dmaCSR.uchar ); + } + + // + // Release our interrupt spinlock + // + WdfInterruptReleaseLock( devExt->Interrupt ); + + // + // NOTE: This shows how to process errors which occur in the + // PFN_WDF_PROGRAM_DMA function in general. + // Basically the DmaTransaction must be deleted and + // the Request must be completed. + // + if (errors) { + NTSTATUS status; + + // + // Must abort the transaction before deleting. + // + (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); + ASSERT(NT_SUCCESS(status)); + + PLxReadRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE ); + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, + "<-- PLxEvtProgramReadDma: errors ****"); + return FALSE; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, + "<-- PLxEvtProgramReadDma"); + + return TRUE; +} + +VOID +PLxReadRequestComplete( + IN WDFDMATRANSACTION DmaTransaction, + IN NTSTATUS Status + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + WDFREQUEST request; + size_t bytesTransferred; + + // + // Get the associated request from the transaction. + // + request = WdfDmaTransactionGetRequest(DmaTransaction); + + ASSERT(request); + + // + // Get the final bytes transferred count. + // + bytesTransferred = WdfDmaTransactionGetBytesTransferred( DmaTransaction ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, + "PLxReadRequestComplete: Request %p, Status %!STATUS!, " + "bytes transferred %d\n", + request, Status, (int) bytesTransferred ); + + WdfDmaTransactionRelease(DmaTransaction); + + // + // Complete this Request. + // + WdfRequestCompleteWithInformation( request, Status, bytesTransferred); + +} + diff --git a/general/PLX9x5x/sys/Reg9656.h b/general/PLX9x5x/sys/Reg9656.h new file mode 100644 index 00000000..9165403b --- /dev/null +++ b/general/PLX9x5x/sys/Reg9656.h @@ -0,0 +1,259 @@ +#ifndef __REG9656_H_ +#define __REG9656_H_ + +//***************************************************************************** +// +// File Name: Reg9656.h +// +// Description: This file defines all the PLX 9656 chip Registers. +// +// NOTE: These definitions are for memory-mapped register access only. +// +//***************************************************************************** + +//----------------------------------------------------------------------------- +// PCI Device/Vendor Ids. +//----------------------------------------------------------------------------- +#define PLX_PCI_VENDOR_ID 0x10B5 +#define PLX_PCI_DEVICE_ID 0x9601 + +//----------------------------------------------------------------------------- +// Expected size of the PCI9656RDK-Lite on-board SRAM +//----------------------------------------------------------------------------- +#define PCI9656_SRAM_SIZE (0x20000) + +//----------------------------------------------------------------------------- +// Maximum DMA transfer size (in bytes). +// +// NOTE: This value is rather abritrary for this drive, +// but must be between [0 - PCI9656_SRAM_SIZE] in value. +// You can play with the value to see how requests are sequenced as a +// set of one or more DMA operations. +//----------------------------------------------------------------------------- +#define PCI9656_MAXIMUM_TRANSFER_LENGTH (8*1024) + +//----------------------------------------------------------------------------- +// The DMA_TRANSFER_ELEMENTS (the 9656's hardware scatter/gather list element) +// must be aligned on a 16-byte boundry. This is because the lower 4 bits of +// the DESC_PTR.Address contain bit fields not included in the "next" address. +//----------------------------------------------------------------------------- +#define PCI9656_DTE_ALIGNMENT_16 FILE_OCTA_ALIGNMENT + +//----------------------------------------------------------------------------- +// Number of DMA channels supported by PLX Chip +//----------------------------------------------------------------------------- +#define PCI9656_DMA_CHANNELS (2) + +//----------------------------------------------------------------------------- +// DMA Transfer Element (DTE) +// +// NOTE: This structure is modeled after the DMAPADRx, DMALADRx, DMASIZx and +// DMAADPRx registers. See DataBook Registers description: 11-74 to 11-77. +//----------------------------------------------------------------------------- +typedef struct _DESC_PTR_ { + + unsigned int DescLocation : 1 ; // TRUE - Desc in PCI (host) memory + unsigned int LastElement : 1 ; // TRUE - last NTE in chain + unsigned int TermCountInt : 1 ; // TRUE - Interrupt on term count. + unsigned int DirOfTransfer : 1 ; // see defines below + unsigned int Address : 28 ; + +} DESC_PTR; + +#define DESC_PTR_DESC_LOCATION__LOCAL (0) +#define DESC_PTR_DESC_LOCATION__PCI (1) + +#define DESC_PTR_DIRECTION__TO_DEVICE (0) +#define DESC_PTR_DIRECTION__FROM_DEVICE (1) + +typedef struct _DMA_TRANSFER_ELEMENT { + + unsigned int PciAddressLow ; + unsigned int LocalAddress ; + unsigned int TransferSize ; + DESC_PTR DescPtr ; + unsigned int PciAddressHigh ; + unsigned int pad [3] ; + +} DMA_TRANSFER_ELEMENT, * PDMA_TRANSFER_ELEMENT; + +#define DESC_PTR_ADDR_SHIFT (4) +#define DESC_PTR_ADDR(a) (((ULONG) a) >> DESC_PTR_ADDR_SHIFT) + + +//----------------------------------------------------------------------------- +// Define the Interrupt Command Status Register (CSR) +//----------------------------------------------------------------------------- +typedef struct _INT_CSR_ { + unsigned int EnableIntSources : 2; // bit 0-1 + unsigned int GenPciBusSerrInt : 1; // bit 2 + unsigned int MailboxIntEnable : 1; // bit 3 + unsigned int PowerMgmtIntEnable : 1; // bit 4 + unsigned int PowerMgmtInt : 1; // bit 5 + unsigned int DM_WriteParityCheck : 1; // bit 6 + unsigned int DM_WriteParityCheckErr : 1; // bit 7 + unsigned int PciIntEnable : 1; // bit 8 + unsigned int PciDoorbellIntEnable : 1; // bit 9 + unsigned int PciAbortIntEnable : 1; // bit 10 + unsigned int LocalIntInputEnable : 1; // bit 11 + unsigned int RetryAbortEnable : 1; // bit 12 + unsigned int PciDoorbellIntActive : 1; // bit 13 + unsigned int PciAbortIntActive : 1; // bit 14 + unsigned int LocalIntInputActive : 1; // bit 15 + unsigned int LocalIntOutputEnable : 1; // bit 16 + unsigned int LocalDoorbellIntEnable : 1; // bit 17 + unsigned int DmaChan0IntEnable : 1; // bit 18 + unsigned int DmaChan1IntEnable : 1; // bit 19 + unsigned int LocalDoorbellIntActive : 1; // bit 20 + unsigned int DmaChan0IntActive : 1; // bit 21 + unsigned int DmaChan1IntActive : 1; // bit 22 + unsigned int BistIntActive : 1; // bit 23 + unsigned int DM_WasBusMastOnAbort : 1; // bit 24 + unsigned int Dma0_WasBusMastOnAbort : 1; // bit 25 + unsigned int Dma1_WasBusMastOnAbort : 1; // bit 26 + unsigned int AbortAfter256Retries : 1; // bit 27 + unsigned int DataInMailbox0 : 1; // bit 28 + unsigned int DataInMailbox1 : 1; // bit 29 + unsigned int DataInMailbox2 : 1; // bit 30 + unsigned int DataInMailbox3 : 1; // bit 31 +} INT_CSR; + + +//----------------------------------------------------------------------------- +// Define the EEPROM CSR (CNTRL) +//----------------------------------------------------------------------------- +typedef struct _EEPROM_CSR_ { + unsigned int PciReadCmdForDma : 4; // bit 0-3 + unsigned int PciWriteCmdForDma : 4; // bit 4-7 + unsigned int PciMemReadCmdForDM : 4; // bit 8-11 + unsigned int PciMemWriteCmdForDM : 4; // bit 12-15 + unsigned int GPIO_Output : 1; // bit 16 + unsigned int GPIO_Input : 1; // bit 17 + unsigned int User_i_Select : 1; // bit 18 + unsigned int User_o_Select : 1; // bit 19 + unsigned int LINT_o_IntStatus : 1; // bit 20 + unsigned int TeaIntStatus : 1; // bit 21 + unsigned int reserved : 2; // bit 22-23 + unsigned int SerialEEPROMClockOut : 1; // bit 24 + unsigned int SerialEEPROMChipSelect : 1; // bit 25 + unsigned int SerialEEPROMDataIn : 1; // bit 26 + unsigned int SerialEEPROMDataOut : 1; // bit 27 + unsigned int SerialEEPROMPresent : 1; // bit 28 + unsigned int ReloadConfigRegisters : 1; // bit 29 + unsigned int SoftwareReset : 1; // bit 30 + unsigned int EEDOInputEnable : 1; // bit 31 +} EEPROM_CSR; + +//----------------------------------------------------------------------------- +// Define the DMA Mode Register +//----------------------------------------------------------------------------- +typedef struct _DMA_MODE_ { + unsigned int LocalBusDataWidth : 2 ; // bit 0-1 + unsigned int WaitStateCounter : 4 ; // bit 2-5 + unsigned int TaRdyInputEnable : 1 ; // bit 6 + unsigned int BurstEnable : 1 ; // bit 7 + unsigned int LocalBurstEnable : 1 ; // bit 8 + unsigned int SgModeEnable : 1 ; // bit 9 + unsigned int DoneIntEnable : 1 ; // bit 10 + unsigned int LocalAddressMode : 1 ; // bit 11 + unsigned int DemandMode : 1 ; // bit 12 + unsigned int MWIEnable : 1 ; // bit 13 + unsigned int EOTEnable : 1 ; // bit 14 + unsigned int TermModeSelect : 1 ; // bit 15 + unsigned int ClearCountMode : 1 ; // bit 16 + unsigned int IntToPci : 1 ; // bit 17 + unsigned int DACChainLoad : 1 ; // bit 18 + unsigned int EOTEndLink : 1 ; // bit 19 + unsigned int RingMgmtValidMode : 1 ; // bit 20 + unsigned int RingMgmtValidStop : 1 ; // bit 21 + unsigned int reserved : 10; // bit 22-31 +} DMA_MODE; + +//----------------------------------------------------------------------------- +// Define the DMA Command Status Register (CSR) +//----------------------------------------------------------------------------- +#pragma warning(disable:4214) // bit field types other than int warning + +typedef struct _DMA_CSR_ { + unsigned char Enable : 1; // bit 0 + unsigned char Start : 1; // bit 1 + unsigned char Abort : 1; // bit 2 + unsigned char Clear : 1; // bit 3 + unsigned char Done : 1; // bit 4 + unsigned char pad : 1; // bit 5-7 +} DMA_CSR; + +#pragma warning(default:4214) + +//----------------------------------------------------------------------------- +// PCI9659_REGS structure +//----------------------------------------------------------------------------- +typedef struct _PCI9656_REGS_ { + + unsigned int Space0_Range ; // 0x000 + unsigned int Space0_Remap ; // 0x004 + unsigned int Local_DMA_Arbit ; // 0x008 + unsigned int Endian_Desc ; // 0x00C + unsigned int Exp_XP_ROM_Range ; // 0x010 + unsigned int Exp_ROM_Remap ; // 0x014 + unsigned int Space0_ROM_Desc ; // 0x018 + unsigned int DM_Range ; // 0x01C + unsigned int DM_Mem_Base ; // 0x020 + unsigned int DM_IO_Base ; // 0x024 + unsigned int DM_PCI_Mem_Remap ; // 0x028 + + unsigned int pad1 [7] ; // range [0x02C - 0x044] + + unsigned int Mailbox2 ; // 0x048 + unsigned int Mailbox3 ; // 0x04C + unsigned int Mailbox4 ; // 0x050 + unsigned int Mailbox5 ; // 0x054 + unsigned int Mailbox6 ; // 0x058 + unsigned int Mailbox7 ; // 0x05C + + unsigned int Local_Doorbell ; // 0x060 + unsigned int PCI_Doorbell ; // 0x064 + INT_CSR Int_Csr ; // 0x068 + EEPROM_CSR EEPROM_Ctrl_Stat ; // 0x06C + unsigned int Perm_Vendor_Id ; // 0x070 + unsigned int Revision_Id ; // 0x074 + + unsigned int pad2 [2] ; // range [0x078 - 0x07C] + + DMA_MODE Dma0_Mode ; // 0x080 + unsigned int Dma0_PCI_Addr ; // 0x084 + unsigned int Dma0_Local_Addr ; // 0x088 + unsigned int Dma0_Count ; // 0x08C + DESC_PTR Dma0_Desc_Ptr ; // 0x090 + + DMA_MODE Dma1_Mode ; // 0x094 + unsigned int Dma1_PCI_Addr ; // 0x098 + unsigned int Dma1_Local_Addr ; // 0x09C + unsigned int Dma1_Count ; // 0x0A0 + DESC_PTR Dma1_Desc_Ptr ; // 0x0A4 + + DMA_CSR Dma0_Csr ; // 0x0A8 + DMA_CSR Dma1_Csr ; // 0x0A9 + + unsigned char pad3 [2] ; // pad to next 32-bit boundry + + unsigned int Dma_Arbit ; // 0x0AC + unsigned int Dma_Threshold ; // 0x0B0 + + unsigned int Dma0_PCI_DAC ; // 0x0B4 + unsigned int Dma1_PCI_DAC ; // 0x0B8 + + unsigned int pad4 [13] ; // range [0x0BC - 0x0EC] + + unsigned int Space1_Range ; // 0x0F0 + unsigned int Space1_Remap ; // 0x0F4 + unsigned int Space1_Desc ; // 0x0F8 + unsigned int DM_DAC ; // 0x0FC + + unsigned int Arbiter_Cntl ; // 0x100 + unsigned int Abort_Address ; // 0x104 + +} PCI9656_REGS, * PPCI9656_REGS; + + +#endif // __REG9656_H_ diff --git a/general/PLX9x5x/sys/Write.c b/general/PLX9x5x/sys/Write.c new file mode 100644 index 00000000..3e4d8b53 --- /dev/null +++ b/general/PLX9x5x/sys/Write.c @@ -0,0 +1,525 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Write.c + +Abstract: + + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#include "Write.tmh" + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +VOID +PLxEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + Called by the framework as soon as it receives a write request. + If the device is not ready, fail the request. + Otherwise get scatter-gather list for this request and send the + packet to the hardware for DMA. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + PDEVICE_EXTENSION devExt = NULL; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "--> PLxEvtIoWrite: Request %p", Request); + + // + // Get the DevExt from the Queue handle + // + devExt = PLxGetDeviceContext(WdfIoQueueGetDevice(Queue)); + + // + // Validate the Length parameter. + // + if (Length > PCI9656_SRAM_SIZE) { + status = STATUS_INVALID_BUFFER_SIZE; + goto CleanUp; + } + + // + // Following code illustrates two different ways of initializing a DMA + // transaction object. If ASSOC_WRITE_REQUEST_WITH_DMA_TRANSACTION is + // defined in the sources file, the first section will be used. + // +#ifdef ASSOC_WRITE_REQUEST_WITH_DMA_TRANSACTION + + // + // This section illustrates how to create and initialize + // a DmaTransaction using a WDF Request. + // This type of coding pattern would probably be the most commonly used + // for handling client Requests. + // + status = WdfDmaTransactionInitializeUsingRequest( + devExt->WriteDmaTransaction, + Request, + PLxEvtProgramWriteDma, + WdfDmaDirectionWriteToDevice ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionInitializeUsingRequest failed: " + "%!STATUS!", status); + goto CleanUp; + } +#else + // + // This section illustrates how to create and initialize + // a DmaTransaction via direct parameters (e.g. not using a WDF Request). + // This type of coding pattern might be used for driver-initiated DMA + // operations (e.g. DMA operations not based on driver client requests.) + // + // NOTE: This example unpacks the WDF Request in order to get a set of + // parameters for the call to WdfDmaTransactionInitialize. While + // this is completely legimate, the represenative usage pattern + // for WdfDmaTransactionIniitalize would have the driver create/ + // initialized a DmaTransactin without a WDF Request. A simple + // example might be where the driver needs to DMA the devices's + // firmware to it during device initialization. There would be + // no WDF Request; the driver would supply the parameters for + // WdfDmaTransactionInitialize directly. + // + { + PTRANSACTION_CONTEXT transContext; + PMDL mdl; + PVOID virtualAddress; + ULONG length; + + // + // Initialize this new DmaTransaction with direct parameters. + // + status = WdfRequestRetrieveInputWdmMdl(Request, &mdl); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfRequestRetrieveInputWdmMdl failed: %!STATUS!", status); + goto CleanUp; + } + + virtualAddress = MmGetMdlVirtualAddress(mdl); + length = MmGetMdlByteCount(mdl); + + _Analysis_assume_(length > 0); + status = WdfDmaTransactionInitialize( devExt->WriteDmaTransaction, + PLxEvtProgramWriteDma, + WdfDmaDirectionWriteToDevice, + mdl, + virtualAddress, + length ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionInitialize failed: %!STATUS!", status); + goto CleanUp; + } + + // + // Retreive this DmaTransaction's context ptr (aka TRANSACTION_CONTEXT) + // and fill it in with info. + // + transContext = PLxGetTransactionContext( devExt->WriteDmaTransaction ); + transContext->Request = Request; + } +#endif + +#if 0 //FYI + // + // Modify the MaximumLength for this DmaTransaction only. + // + // Note: The new length must be less than or equal to that set when + // the DmaEnabler was created. + // + { + ULONG length = devExt->MaximumTransferLength / 2; + + //TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + // "Setting a new MaxLen %d", length); + + WdfDmaTransactionSetMaximumLength( devExt->WriteDmaTransaction, length ); + } +#endif + + // + // Execute this DmaTransaction transaction. + // + status = WdfDmaTransactionExecute( devExt->WriteDmaTransaction, + WDF_NO_CONTEXT); + + if(!NT_SUCCESS(status)) { + + // + // Couldn't execute this DmaTransaction, so fail Request. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionExecute failed: %!STATUS!", status); + goto CleanUp; + } + + // + // Indicate that Dma transaction has been started successfully. The request + // will be complete by the Dpc routine when the DMA transaction completes. + // + status = STATUS_SUCCESS; + +CleanUp: + + // + // If there are errors, then clean up and complete the Request. + // + if (!NT_SUCCESS(status)) { + WdfDmaTransactionRelease(devExt->WriteDmaTransaction); + WdfRequestComplete(Request, status); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "<-- PLxEvtIoWrite: %!STATUS!", status); + + return; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +BOOLEAN +PLxEvtProgramWriteDma( + IN WDFDMATRANSACTION Transaction, + IN WDFDEVICE Device, + IN PVOID Context, + IN WDF_DMA_DIRECTION Direction, + IN PSCATTER_GATHER_LIST SgList + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + PDEVICE_EXTENSION devExt; + size_t offset; + PDMA_TRANSFER_ELEMENT dteVA; + ULONG_PTR dteLA; + BOOLEAN errors; + ULONG i; + + UNREFERENCED_PARAMETER( Context ); + UNREFERENCED_PARAMETER( Direction ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "--> PLxEvtProgramWriteDma"); + + // + // Initialize locals + // + devExt = PLxGetDeviceContext(Device); + errors = FALSE; + + // + // Get the number of bytes as the offset to the beginning of this + // Dma operations transfer location in the buffer. + // + offset = WdfDmaTransactionGetBytesTransferred(Transaction); + + // + // Setup the pointer to the next DMA_TRANSFER_ELEMENT + // for both virtual and physical address references. + // + dteVA = (PDMA_TRANSFER_ELEMENT) devExt->WriteCommonBufferBase; + dteLA = (devExt->WriteCommonBufferBaseLA.LowPart + + sizeof(DMA_TRANSFER_ELEMENT)); + + // + // Translate the System's SCATTER_GATHER_LIST elements + // into the device's DMA_TRANSFER_ELEMENT elements. + // + for (i=0; i < SgList->NumberOfElements; i++) { + + // + // Construct this DTE. + // + // NOTE: The LocalAddress is the offset into the SRAM from + // where this Write will start. + // + dteVA->PciAddressLow = SgList->Elements[i].Address.LowPart; + dteVA->PciAddressHigh = SgList->Elements[i].Address.HighPart; + dteVA->TransferSize = SgList->Elements[i].Length; + + dteVA->LocalAddress = (ULONG) offset; + + dteVA->DescPtr.DescLocation = DESC_PTR_DESC_LOCATION__PCI; + dteVA->DescPtr.TermCountInt = FALSE; + dteVA->DescPtr.LastElement = FALSE; + dteVA->DescPtr.DirOfTransfer = DESC_PTR_DIRECTION__TO_DEVICE; + dteVA->DescPtr.Address = DESC_PTR_ADDR( dteLA ); + + // + // Increment the DmaTransaction length by this element length + // + offset += SgList->Elements[i].Length; + + // + // If at end of SgList, then set LastElement bit in final NTE. + // + if (i == SgList->NumberOfElements - 1) { + + dteVA->DescPtr.LastElement = TRUE; + +#if 0 // set to 1 for recording the details + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "\tDTE[%d] : Addr #%X%08X Len %5d, Local %08X, " + "Loc(%d), Last(%d), TermInt(%d), ToPci(%d)\n", + i, + dteVA->PciAddressHigh, + dteVA->PciAddressLow, + dteVA->TransferSize, + dteVA->LocalAddress, + dteVA->DescPtr.DescLocation, + dteVA->DescPtr.LastElement, + dteVA->DescPtr.TermCountInt, + dteVA->DescPtr.DirOfTransfer ); +#endif + break; + } + +#if 0 // set to 1 for recording the details + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "\tDTE[%d] : Addr #%X%08X Len %5d, Local %08X, " + "Loc(%d), Last(%d), TermInt(%d), ToPci(%d)\n", + i, + dteVA->PciAddressHigh, + dteVA->PciAddressLow, + dteVA->TransferSize, + dteVA->LocalAddress, + dteVA->DescPtr.DescLocation, + dteVA->DescPtr.LastElement, + dteVA->DescPtr.TermCountInt, + dteVA->DescPtr.DirOfTransfer ); +#endif + + // + // Adjust the next DMA_TRANSFER_ELEMEMT + // + dteVA++; + dteLA += sizeof(DMA_TRANSFER_ELEMENT); + } + + // + // Start the DMA operation. + // Acquire this device's InterruptSpinLock. + // + WdfInterruptAcquireLock( devExt->Interrupt ); + + // + // DMA 0 Mode Register - (DMAMODE0) + // Enable Scatter/Gather Mode, Interrupt On Done, + // and route Ints to PCI. + // + { + union { + DMA_MODE bits; + ULONG ulong; + } dmaMode; + + dmaMode.ulong = + READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma0_Mode ); + + dmaMode.bits.SgModeEnable = TRUE; + dmaMode.bits.DoneIntEnable = TRUE; + dmaMode.bits.IntToPci = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma0_Mode, + dmaMode.ulong ); + } + + // + // Interrupt CSR Register - (INTCSR) + // Enable PCI Ints and DMA Channel 0 Ints. + // + { + union { + INT_CSR bits; + ULONG ulong; + } intCSR; + + intCSR.ulong = + READ_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr ); + + intCSR.bits.PciIntEnable = TRUE; + intCSR.bits.DmaChan0IntEnable = TRUE; + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Int_Csr, + intCSR.ulong ); + } + + // + // DMA 0 Descriptor Pointer Register - (DMADPR0) + // Write the base LOGICAL address of the DMA_TRANSFER_ELEMENT list. + // + { + union { + DESC_PTR bits; + ULONG ulong; + } ptr; + + ptr.bits.DescLocation = DESC_PTR_DESC_LOCATION__PCI; + ptr.bits.TermCountInt = TRUE; + ptr.bits.Address = + DESC_PTR_ADDR( devExt->WriteCommonBufferBaseLA.LowPart ); + + WRITE_REGISTER_ULONG( (PULONG) &devExt->Regs->Dma0_Desc_Ptr, + ptr.ulong ); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + " PLxEvtProgramWriteDma: Start a Write DMA operation"); + + // + // DMA 0 CSR Register - (DMACSR0) + // Start the DMA operation: Set Enable and Start bits. + // + { + union { + DMA_CSR bits; + UCHAR uchar; + } dmaCSR; + + dmaCSR.uchar = + READ_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr ); + + dmaCSR.bits.Enable = TRUE; + dmaCSR.bits.Start = TRUE; + + WRITE_REGISTER_UCHAR( (PUCHAR) &devExt->Regs->Dma0_Csr, + dmaCSR.uchar ); + } + + // + // Release our interrupt spinlock + // + WdfInterruptReleaseLock( devExt->Interrupt ); + + // + // NOTE: This shows how to process errors which occur in the + // PFN_WDF_PROGRAM_DMA function in general. + // Basically the DmaTransaction must be deleted and + // the Request must be completed. + // + if (errors) { + // + // Must abort the transaction before deleting it. + // + NTSTATUS status; + + (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); + ASSERT(NT_SUCCESS(status)); + PLxWriteRequestComplete( Transaction, STATUS_INVALID_DEVICE_STATE ); + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "<-- PLxEvtProgramWriteDma: error ****"); + return FALSE; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_WRITE, + "<-- PLxEvtProgramWriteDma"); + + return TRUE; +} + + +VOID +PLxWriteRequestComplete( + IN WDFDMATRANSACTION DmaTransaction, + IN NTSTATUS Status + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + WDFREQUEST request; + size_t bytesTransferred; + + // + // Initialize locals + // + +#ifdef ASSOC_WRITE_REQUEST_WITH_DMA_TRANSACTION + + request = WdfDmaTransactionGetRequest(DmaTransaction); + +#else + // + // If CreateDirect was used then there will be no assoc. Request. + // + { + PTRANSACTION_CONTEXT transContext = PLxGetTransactionContext(DmaTransaction); + + request = transContext->Request; + transContext->Request = NULL; + + } +#endif + + // + // Get the final bytes transferred count. + // + bytesTransferred = WdfDmaTransactionGetBytesTransferred( DmaTransaction ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, + "PLxWriteRequestComplete: Request %p, Status %!STATUS!, " + "bytes transferred %d\n", + request, Status, (int) bytesTransferred ); + + WdfDmaTransactionRelease(DmaTransaction); + + WdfRequestCompleteWithInformation( request, Status, bytesTransferred); + +} + diff --git a/general/PLX9x5x/sys/pci9x5x.inx b/general/PLX9x5x/sys/pci9x5x.inx new file mode 100644 index 00000000..3904344b --- /dev/null +++ b/general/PLX9x5x/sys/pci9x5x.inx @@ -0,0 +1,97 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; +; Pci9x5x.INF +; +;Abstract: +; INF file for the PLx PCI9x5xRDK-Lite driver. +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 +HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. + + +; ================= Device Install section ===================== + +[ControlFlags] +ExcludeFromSelect=* + +[Manufacturer] +%MSFT%=MSFT,NT$ARCH$ + +[SourceDisksFiles] +Pci9x5x.sys=1 + +[SourceDisksNames] +1=%DISK_NAME%, + +; For Win2K +[MSFT] +; DisplayName Section DeviceId +; ----------- ------- -------- +%Pci9056.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_5601 +%Pci9656.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_9601 + +; For XP and later +[MSFT.NT$ARCH$] +; DisplayName Section DeviceId +; ----------- ------- -------- +%Pci9056.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_5601 +%Pci9656.DRVDESC%= Pci9x5x_Inst, PCI\VEN_10b5&DEV_9601 + +[Pci9x5x_Inst.NT] +CopyFiles=Pci9x5x.CopyFiles + +[Pci9x5x.CopyFiles] +Pci9x5x.sys + +[Pci9x5x_Inst.NT.Services] +AddService=Pci9x5x,0x00000002,Pci9x5x_Service + +[Pci9x5x_Service] +DisplayName = %Pci9x5x.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\Pci9x5x.sys + +[Pci9x5x_Inst.NT.Wdf] +KmdfService = Pci9x5x, Pci9x5x_wdfsect +[Pci9x5x_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +[Strings] +MSFT = "Microsoft" +ClassName = "Sample Device" +Pci9x5x.SVCDESC = "Sample Driver Service for the PCI9x5xRDK-Lite adapter" +Pci9056.DRVDESC = "Sample Driver for the PCI9056RDK-Lite adapter" +Pci9656.DRVDESC = "Sample Driver for the PCI9656RDK-Lite adapter" +DISK_NAME = "Pci9x5x Sample Install Disk" diff --git a/general/PLX9x5x/sys/precompsrc.c b/general/PLX9x5x/sys/precompsrc.c new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/general/PLX9x5x/sys/precompsrc.c @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/general/PLX9x5x/sys/trace.h b/general/PLX9x5x/sys/trace.h new file mode 100644 index 00000000..a9726b3a --- /dev/null +++ b/general/PLX9x5x/sys/trace.h @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TRACE.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + +Environment: + + Kernel mode + + +--*/ + +#include <evntrace.h> // For TRACE_LEVEL definitions + +// +// If software tracing is defined in the sources file.. +// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. +// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** +// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. +// The names defined in the WPP_DEFINE_BIT call define the actual names +// that are used to control the level of tracing for the control guid +// specified. +// +// Name of the logger is PLX9x5x and the guid is +// {CA630800-D4D4-4457-8983-DFBBFCAC5542} +// (0xca630800, 0xd4d4, 0x4457, 0x89, 0x83, 0xdf, 0xbb, 0xfc, 0xac, 0x55, 0x42); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(PLX9x5xTraceGuid, (ca630800, D4D4, 4457,8983, DFBBFCAC5542),\ + WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(DBG_IOCTLS) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + WPP_DEFINE_BIT(DBG_DPC) /* bit 8 = 0x00000100 */ \ + WPP_DEFINE_BIT(DBG_INTERRUPT) /* bit 9 = 0x00000200 */ \ + WPP_DEFINE_BIT(DBG_LOCKS) /* bit 10 = 0x00000400 */ \ + WPP_DEFINE_BIT(DBG_QUEUEING) /* bit 11 = 0x00000800 */ \ + WPP_DEFINE_BIT(DBG_HW_ACCESS) /* bit 12 = 0x00001000 */ \ + /* You can have up to 32 defines. If you want more than that,\ + you have to provide another trace control GUID */\ + ) + + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + + diff --git a/general/PLX9x5x/test/plx.cpp b/general/PLX9x5x/test/plx.cpp new file mode 100644 index 00000000..c5bae510 --- /dev/null +++ b/general/PLX9x5x/test/plx.cpp @@ -0,0 +1,1104 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + plx.cpp + +Abstract: + + This module implements the PLX class which tests the DMA of PLX devices. + + Example usage: + plx.exe /wr /wb=100 # write-then-read once with a buffer of 100 bytes + plx.exe /thread # repeat write-then-read for default 5000 millisecs. + plx.exe /thread /time=1000 # repeat write-then-read for 1000 millisecs. + + NOTE: The /quite option will suppress most non-error messages. + NOTE: The options and parameters are case sensitive. + +Environment: + + User Mode Win2k or Later + +--*/ + +#define INITGUID + +#include "plx.hpp" + +// +// Define the spin count to be used for critical sections. The value +// specified below is arbitrary. Change it based on your requirements. +// +#define SPIN_COUNT_FOR_CS 0x4000 + +int g_TimeUp =0; + +DWORD WINAPI +ReadThreadProc( + LPVOID lpParameter + ) +{ + ULONG bytes; + PTHREAD_CONTEXT Context = (PTHREAD_CONTEXT)lpParameter; + + while(!g_TimeUp) { + + if(ReadFile(Context->hDevice, + Context->Buffer, + Context->BufferSize, + &bytes, + NULL)) { + + if (!Context->quite) { + printf("Read sucessful.\n"); + } + + } else { + + printf("Read failed.\n"); + ExitProcess(1); + } + } + ExitThread(0); +} + +DWORD WINAPI +WriteThreadProc( + LPVOID lpParameter + ) +{ + ULONG bytes; + PTHREAD_CONTEXT Context = (PTHREAD_CONTEXT)lpParameter; + + while(!g_TimeUp) { + + if(WriteFile(Context->hDevice, + Context->Buffer, + Context->BufferSize, + &bytes, + NULL)) { + + if (!Context->quite) { + printf("Write sucessful.\n"); + } + + } else { + + printf("Write failed.\n"); + ExitProcess(1); + } + } + ExitThread(0); +} + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + PLX Plx; + BOOL status = TRUE; + ULONG test = MENU_TEST; + + if (!Plx.Initialize()) { + printf("Failied to Initialize Test class.\n"); + printf("exit(%u)\n", Plx.Status); + exit(Plx.Status); + } + + if(argc > 1) { + + for(int i=1; (i < argc) && status; i++) { + + char delims[] = "-/="; + char delims2[] = "="; + char *command; + char *data; + char *state = NULL; + + data = NULL; + + #pragma prefast(suppress:6385, "i < argc-1 before it is incremented below"); + command = strtok_s(argv[i], delims, &state); + if(command == NULL) { + status = FALSE; + break; + } + + if(strcmp(command, "rb") == 0) { + + data = strtok_s(NULL, delims2, &state); + + if (!data && i < argc-1) { + data = argv[++i]; + } + + ULONG size = atol(data); + if (size > 0) { + Plx.SetReadBufferSize(size); + } else { + status = FALSE; + } + + } else if(strcmp(command, "wb") == 0) { + + ULONG size = 0; + data = strtok_s(NULL, delims2, &state); + + if (!data && i < argc-1) { + data = argv[++i]; + } + if (data) { + size = atol(data); + } + + if (size > 0) { + Plx.SetWriteBufferSize(size); + } else { + status = FALSE; + } + + } else if (strcmp(command, "bs") == 0) { + data = strtok_s(NULL, delims2, &state); + + if (!data && i < argc-1) { + data = argv[++i]; + } + + ULONG size = atol(data); + if(size > 0) { + Plx.SetWriteBufferSize(size); + } else { + status = FALSE; + } + + } else if(strcmp(command, "wt") == 0) { + + test = WRITE_TEST; + + } else if(strcmp(command, "rt") == 0) { + + test = READ_TEST; + + } else if(strcmp(command, "quite") == 0) { + + Plx.Quite = TRUE; + + } else if(strcmp(command, "thread") == 0) { + + test = THREAD_TEST; + + } else if (strcmp(command, "time") == 0) { + + data = strtok_s(NULL, delims, &state); + + if(!data && i < argc-1) { + #pragma prefast(suppress:6385, "i < argc-1 before it is incremented"); + data = argv[++i]; + } + ULONG size = (NULL != data) ? atol(data) : 0; + Plx.SetThreadLifeTime(size); + + } else { + status = FALSE; + } + + if (!Plx.Quite) { + if (data) { + printf("Arg %d: Command: %s Parameter: %s\n", i, command, data); + } else { + printf("Arg %d: Command: %s\n", i, command); + } + } + } + } + + if (status) { + + switch (test) { + case READ_TEST: + Plx.ReadTest(); + break; + + case WRITE_TEST: + Plx.WriteTest(); + break; + + case READ_WRITE_TEST: + Plx.ReadWriteTest(); + break; + + case THREAD_TEST: + Plx.ThreadedReadWriteTest(); + break; + + case MENU_TEST: + default: + Plx.Menu(); + } + + } else { + + printf("Invalid command line parameter.\n"); + Plx.Status = 1; + } + + printf("exit(%u)\n", Plx.Status); + + exit( Plx.Status ); +} + +PLX::PLX() +{ + ReadBuffer = WriteBuffer = NULL; + hDevInfo = pDeviceInterfaceDetail = NULL; + hDevice = INVALID_HANDLE_VALUE; + console = TRUE; + Contexts = NULL; + Threads = NULL; + ProcessorCount = 0; + CSInitialized = FALSE; + ThreadTimer = 5000; // 5000 milliseconds (5 seconds) + + Quite = FALSE; + Status = 0; +} + +PLX::~PLX() +{ + + if (CSInitialized) { + DeleteCriticalSection(&CriticalSection); + } + if (hDevInfo) { + SetupDiDestroyDeviceInfoList(hDevInfo); + } + + if (pDeviceInterfaceDetail) { + free(pDeviceInterfaceDetail); + } + + if (Contexts) { + _Analysis_assume_(ProcessorCount <= ThreadCount); + for(int i = 0; i < ProcessorCount; i++) { + if (Contexts[i].Buffer) { + delete Contexts[i].Buffer; + } + } + + delete Contexts; + Contexts = NULL; + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + hDevice = INVALID_HANDLE_VALUE; + } +} + +BOOL +PLX::Initialize() +{ + BOOL retValue = TRUE; + + retValue = SetBufferSizes(DEFAULT_READ_BUFFER_SIZE); + if (!retValue) { + return retValue; + } + + retValue = GetDevicePath(); + if (!retValue) { + return retValue; + } + + if (!CSInitialized) { + retValue = InitializeCriticalSectionAndSpinCount(&CriticalSection, SPIN_COUNT_FOR_CS); + if (!retValue) { + printf("InitializeCritialSection failed.\n"); + Status = GetLastError(); + return retValue; + } + CSInitialized = TRUE; + } + + return retValue; +} + +void +PLX::Menu() +{ + int menu = -1; + + while(menu != 0 && pDeviceInterfaceDetail) { + printf("\n" + " 1- Read from device\n" + " 2- Write from device\n" + " 3- Read/Write from device\n" + " 4- Read/Write Thread Test\n" + " 5- Select new device\n" + " 6- Change Buffer Size\n" + " 7- Compare Read/Write Buffers\n" + " 8- Display Read/Write Buffers\n" + " 9- Change Thread Lifetime\n" + "10- Command Line Options\n" + " 0- Quit\n"); + + if (scanf_s("%d", &menu) == 0) { + break; + } + + switch(menu) { + case READ_TEST: // 1 + ReadTest(); + break; + + case WRITE_TEST: // 2 + WriteTest(); + break; + + case READ_WRITE_TEST: // 3 + ReadWriteTest(); + break; + + case THREAD_TEST: // 4 + ThreadedReadWriteTest(); + break; + + case DEVICE_PATH: // 5 + GetDevicePath(); + break; + + case SET_SIZE: // 6 + ULONG size; + printf("\nEnter new buffer size: "); + if (scanf_s("%u", &size) != 0) { + SetBufferSizes(size); + } + break; + + case COMPARE_BUFFERS: // 7 + CompareReadWriteBuffers(); + break; + + case DISPLAY_BUFFERS: // 8 + DisplayReadWriteBuffers(); + break; + + case THREAD_TIME: // 9 + printf("\nEnter new Thread Lifetime (ms): "); + if (scanf_s("%u", &ThreadTimer) == 0) { + break; + } + break; + + case COMMAND_LINE: // 10 + printf("Command Line Options\n" + " Set Read Buffer Size: '/rb=xx'\n" + " Set Write Buffer Size: '/wb=xx'\n" + " Set Both Buffer Sizes: '/bs=xx'\n" + " Perform Write Test: '/wt'\n" + " Perform Read Test: '/rt'\n" + " Perform Read/Write Test: '/wr'\n" + " Perform Read/Write Thread Test: '/thread'\n"); + break; + + default: + break; + } + } +} + +BOOL +PLX::ThreadedReadWriteTest() +{ + BOOL status = TRUE; + DWORD_PTR pAffinity, sAffinity; + int i; + + HANDLE hThread; + HANDLE hProcess = GetCurrentProcess(); + + GetProcessAffinityMask(hProcess, &pAffinity, &sAffinity); + ProcessorCount = 0; + + while(pAffinity) { + ProcessorCount++; + pAffinity = pAffinity >> 1; + } + + if (ProcessorCount == 1) { + ThreadCount = DEFAULT_THREAD_COUNT; + } else { + ThreadCount = ProcessorCount; + } + + Contexts = new THREAD_CONTEXT[ThreadCount]; + Threads = new HANDLE[ThreadCount]; + + if (Contexts == NULL || Threads == NULL) { + return FALSE; + } + + if (hDevice == INVALID_HANDLE_VALUE) { + status = GetDeviceHandle(); + } + + if (!Quite) { + printf("Creating %d threads...\n", ThreadCount); + } + + pAffinity = 1; + + for(i = 0; i < ThreadCount; i++) { + + if ((i % 2) == 0) { + + // + // Create Read Thread + // + Contexts[i].hDevice = hDevice; + Contexts[i].BufferSize = ReadBufferSize; + Contexts[i].Buffer = new UCHAR[ReadBufferSize]; + Contexts[i].quite = Quite; + + hThread = CreateThread(NULL, + 0, + ReadThreadProc, + &Contexts[i], + 0, + NULL); + + if (NULL == hThread) { + printf( "Failed to create thread %d\n", i ); + this->Status = 1; + break; + + } else { + Threads[i] = hThread; + } + + } else { + + // + // Create Write Thread + // + Contexts[i].hDevice = hDevice; + Contexts[i].BufferSize = WriteBufferSize; + Contexts[i].Buffer = new UCHAR[WriteBufferSize]; + Contexts[i].quite = Quite; + + hThread = CreateThread(NULL, + 0, + WriteThreadProc, + &Contexts[i], + 0, + NULL); + + if (NULL == hThread) { + printf( "Failed to create thread %d\n", i ); + this->Status = 1; + break; + + } else { + Threads[i] = hThread; + } + } + + // + // Set Affinity + // + SetThreadAffinityMask(Threads[i], pAffinity); + + pAffinity = pAffinity << 1; + } + + if (i != ThreadCount) { + + // + // some create thread failed, bail out + // + printf( "Some CreateThread was failed, stop\n" ); + g_TimeUp = 1; + + } else { + + // + // wait till either all quit or time is due + // + DWORD error; + + error = WaitForMultipleObjects(i, Threads, TRUE, ThreadTimer); + + if (error == WAIT_TIMEOUT) { + + // + // Stop the threads if time is up + // + g_TimeUp = 2; + error = WaitForMultipleObjects(i, Threads, TRUE, 100000) ; + + if (error) { + printf("WaitForMultipleObjects[%d] error %u\n", i, error); + } + } else { + if (error) { + printf("WaitForMultipleObjects[%d] error %u\n", i, error); + } + } + } + + if (Contexts) { + for (i = 0; i < ThreadCount; i++) { + if (Contexts[i].Buffer) { + delete Contexts[i].Buffer; + } + } + + delete Contexts; + Contexts = NULL; + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + hDevice = INVALID_HANDLE_VALUE; + } + + return status; +} + +BOOL +PLX::ReadTest() +{ + BOOL status = TRUE; + ULONG bytes = 0; + + if (!ReadBuffer) { + status = FALSE; + } + + if ((status == TRUE) && (hDevice == INVALID_HANDLE_VALUE)) { + status = GetDeviceHandle(); + } + + if (status) { + if (ReadFile(hDevice, + ReadBuffer, + ReadBufferSize, + &bytes, + NULL)){ + + EnterCriticalSection(&CriticalSection); + if (!Quite) { + printf("Read sucessful.\n"); + } + LeaveCriticalSection(&CriticalSection); + + } else { + + EnterCriticalSection(&CriticalSection); + printf("Read failed.\n"); + this->Status = 1; + LeaveCriticalSection(&CriticalSection); + } + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + hDevice = INVALID_HANDLE_VALUE; + } + + return status; +} + +BOOL +PLX::WriteTest() +{ + ULONG bytes = 0; + BOOL status = TRUE; + + if (!WriteBuffer) { + status = FALSE; + } + + if ((status == TRUE) && (hDevice == INVALID_HANDLE_VALUE)) { + status = GetDeviceHandle(); + } + + if (status) { + FillMemory(WriteBuffer, WriteBufferSize, 0xAB); + + if (WriteFile(hDevice, + WriteBuffer, + WriteBufferSize, + &bytes, + NULL)) { + + EnterCriticalSection(&CriticalSection); + if (!Quite) { + printf("Write sucessful.\n"); + } + LeaveCriticalSection(&CriticalSection); + + } else { + + EnterCriticalSection(&CriticalSection); + printf("Write failed.\n"); + this->Status = 1; + LeaveCriticalSection(&CriticalSection); + } + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + hDevice = INVALID_HANDLE_VALUE; + } + + return status; +} + +BOOL +PLX::ReadWriteTest() +{ + return (WriteTest() && ReadTest() && CompareReadWriteBuffers()); +} + +BOOL +PLX::CompareReadWriteBuffers() +{ + BOOL status = TRUE; + ULONG size; + PUCHAR WTraverse; + PUCHAR RTraverse; + + if (ReadBufferSize <= WriteBufferSize) { + size = ReadBufferSize; + } else { + size = WriteBufferSize; + } + + WTraverse = WriteBuffer; + RTraverse = ReadBuffer; + + for(ULONG i = 0; i < size; i++) { + if (*WTraverse++ != *RTraverse++) { + status = FALSE; + } + } + + if (status) { + if (!Quite) { + printf("Buffers are identical\n"); + } + } else { + printf("Buffers not identical\n"); + this->Status = 1; + } + + return status; +} + +void +PLX::DisplayReadWriteBuffers() +{ + if (!Quite) { + + PUCHAR WTraverse; + PUCHAR RTraverse; + + WTraverse = WriteBuffer; + RTraverse = ReadBuffer; + + printf("Write: "); + for(ULONG i = 0; i < WriteBufferSize; i++) { + printf("%X ", *WTraverse++); + } + + printf("\n\n\nRead: "); + for(ULONG i = 0; i < ReadBufferSize; i++) { + printf("%X ", *RTraverse++); + } + printf("\n"); + } +} + +BOOL +PLX::SetReadBufferSize(ULONG size) +{ + BOOL status = TRUE; + + if (ReadBuffer) { + free(ReadBuffer); + } + + ReadBufferSize = size; + + ReadBuffer = (PUCHAR)malloc(ReadBufferSize); + + if (!ReadBuffer) { + status = FALSE; + } + + return status; +} + +BOOL +PLX::SetWriteBufferSize(ULONG size) +{ + BOOL status = TRUE; + + if (WriteBuffer) { + free(WriteBuffer); + } + + WriteBufferSize = size; + + WriteBuffer = (PUCHAR)malloc(WriteBufferSize); + + if (!WriteBuffer) { + status = FALSE; + } + + return status; +} + +BOOL +PLX::SetBufferSizes(ULONG size) +{ + BOOL status; + + status = SetReadBufferSize(size); + if (status) { + status = SetWriteBufferSize(size); + } + + return status; +} + +BOOL +PLX::GetDevicePath() +{ + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + SP_DEVINFO_DATA DeviceInfoData; + + ULONG size; + int count, i, index; + BOOL status = TRUE; + TCHAR *DeviceName = NULL; + TCHAR *DeviceLocation = NULL; + + // + // Retreive the device information for all PLX devices. + // + hDevInfo = SetupDiGetClassDevs(&GUID_PLX_INTERFACE, + NULL, + NULL, + DIGCF_DEVICEINTERFACE | + DIGCF_PRESENT); + + // + // Initialize the SP_DEVICE_INTERFACE_DATA Structure. + // + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + // + // Determine how many devices are present. + // + count = 0; + while(SetupDiEnumDeviceInterfaces(hDevInfo, + NULL, + &GUID_PLX_INTERFACE, + count++, //Cycle through the available devices. + &DeviceInterfaceData) + ); + + // + // Since the last call fails when all devices have been enumerated, + // decrement the count to get the true device count. + // + count--; + + // + // If the count is zero then there are no devices present. + // + if (count == 0) { + printf("No PLX devices are present and enabled in the system.\n"); + this->Status = 1; + return FALSE; + } + + // + // Initialize the appropriate data structures in preparation for + // the SetupDi calls. + // + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + // + // Loop through the device list to allow user to choose + // a device. If there is only one device, select it + // by default. + // + i = 0; + while (SetupDiEnumDeviceInterfaces(hDevInfo, + NULL, + (LPGUID)&GUID_PLX_INTERFACE, + i, + &DeviceInterfaceData)) { + + // + // Determine the size required for the DeviceInterfaceData + // + SetupDiGetDeviceInterfaceDetail(hDevInfo, + &DeviceInterfaceData, + NULL, + 0, + &size, + NULL); + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + printf("SetupDiGetDeviceInterfaceDetail failed, Error: %u", GetLastError()); + this->Status = 1; + return FALSE; + } + + pDeviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(size); + + if (!pDeviceInterfaceDetail) { + printf("Insufficient memory.\n"); + this->Status = 1; + return FALSE; + } + + // + // Initialize structure and retrieve data. + // + pDeviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + status = SetupDiGetDeviceInterfaceDetail(hDevInfo, + &DeviceInterfaceData, + pDeviceInterfaceDetail, + size, + NULL, + &DeviceInfoData); + + free(pDeviceInterfaceDetail); + + if (!status) { + printf("SetupDiGetDeviceInterfaceDetail failed, Error: %u", GetLastError()); + this->Status = 1; + return status; + } + + // + // Get the Device Name + // Calls to SetupDiGetDeviceRegistryProperty require two consecutive + // calls, first to get required buffer size and second to get + // the data. + // + SetupDiGetDeviceRegistryProperty(hDevInfo, + &DeviceInfoData, + SPDRP_DEVICEDESC, + NULL, + (PBYTE)DeviceName, + 0, + &size); + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + printf("SetupDiGetDeviceRegistryProperty failed, Error: %u", GetLastError()); + this->Status = 1; + return FALSE; + } + + DeviceName = (TCHAR*) malloc(size); + if (!DeviceName) { + printf("Insufficient memory.\n"); + this->Status = 1; + return FALSE; + } + + status = SetupDiGetDeviceRegistryProperty(hDevInfo, + &DeviceInfoData, + SPDRP_DEVICEDESC, + NULL, + (PBYTE)DeviceName, + size, + NULL); + if (!status) { + printf("SetupDiGetDeviceRegistryProperty failed, Error: %u", + GetLastError()); + free(DeviceName); + this->Status = 1; + return status; + } + + // + // Now retrieve the Device Location. + // + SetupDiGetDeviceRegistryProperty(hDevInfo, + &DeviceInfoData, + SPDRP_LOCATION_INFORMATION, + NULL, + (PBYTE)DeviceLocation, + 0, + &size); + + if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + DeviceLocation = (TCHAR*) malloc(size); + + if (DeviceLocation != NULL) { + + status = SetupDiGetDeviceRegistryProperty(hDevInfo, + &DeviceInfoData, + SPDRP_LOCATION_INFORMATION, + NULL, + (PBYTE)DeviceLocation, + size, + NULL); + if (!status) { + free(DeviceLocation); + DeviceLocation = NULL; + } + } + + } else { + DeviceLocation = NULL; + } + + // + // If there is more than one device print description. + // + if (count > 1 && console) { + printf("%d- ", i); + } + + printf("%s\n", DeviceName); + + if (DeviceLocation) { + printf(" %s\n", DeviceLocation); + } + + free(DeviceName); + DeviceName = NULL; + + if (DeviceLocation) { + free(DeviceLocation); + DeviceLocation = NULL; + } + + i++; // Cycle through the available devices. + } + + // + // Select device. + // + index = 0; + if (count > 1) { + printf("\nSelect Device: "); + + if (scanf_s("%d", &index) == 0) { + return ERROR_INVALID_DATA; + } + } + + // + // Get information for specific device. + // + status = SetupDiEnumDeviceInterfaces(hDevInfo, + NULL, + (LPGUID)&GUID_PLX_INTERFACE, + index, + &DeviceInterfaceData); + + if (!status) { + printf("SetupDiEnumDeviceInterfaces failed, Error: %u", GetLastError()); + return status; + } + + // + // Determine the size required for the DeviceInterfaceData + // + SetupDiGetDeviceInterfaceDetail(hDevInfo, + &DeviceInterfaceData, + NULL, + 0, + &size, + NULL); + + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + printf("SetupDiGetDeviceInterfaceDetail failed, Error: %u", GetLastError()); + this->Status = 1; + return FALSE; + } + + pDeviceInterfaceDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(size); + + if (!pDeviceInterfaceDetail) { + printf("Insufficient memory.\n"); + this->Status = 1; + return FALSE; + } + + // + // Initialize structure and retrieve data. + // + pDeviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + status = SetupDiGetDeviceInterfaceDetail(hDevInfo, + &DeviceInterfaceData, + pDeviceInterfaceDetail, + size, + NULL, + &DeviceInfoData); + if (!status) { + printf("SetupDiGetDeviceInterfaceDetail failed, Error: %u", GetLastError()); + this->Status = 1; + return status; + } + + return status; +} + +BOOL +PLX::GetDeviceHandle() +{ + BOOL status = TRUE; + + if (pDeviceInterfaceDetail == NULL) { + status = GetDevicePath(); + } + if (pDeviceInterfaceDetail == NULL) { + status = FALSE; + } + + if (status) { + + // + // Get handle to device. + // + hDevice = CreateFile(pDeviceInterfaceDetail->DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL); + + if (hDevice == INVALID_HANDLE_VALUE) { + status = FALSE; + printf("CreateFile failed. Error:%u", GetLastError()); + this->Status = 1; + } + } + + return status; +} + +void +PLX::SetThreadLifeTime(ULONG time) +{ + ThreadTimer = time; +} + diff --git a/general/PLX9x5x/test/plx.hpp b/general/PLX9x5x/test/plx.hpp new file mode 100644 index 00000000..fe87fea1 --- /dev/null +++ b/general/PLX9x5x/test/plx.hpp @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 2003 Microsoft Corporation + +Module Name: + + plx.hpp + +Abstract: + + This module defines the PLX class and the + values neccessary for Window operation and IOCTL control. + +Environment: + + User Mode Win2k or Later + +--*/ + +#pragma once + +#include <windows.h> +#include <setupapi.h> + +#include <stdio.h> +#include <stdlib.h> +#include <malloc.h> +#include "public.h" + +// +// scanf_s is not available in the DDK build environment. +// So redefining it to use scanf +// +#if defined(DDKBUILD) + +#define scanf_s scanf + +#endif + + +#define DEFAULT_READ_BUFFER_SIZE 1024 +#define DEFAULT_WRITE_BUFFER_SIZE 1024 + +#define DEFAULT_THREAD_COUNT 2 + +typedef struct _THREAD_CONTEXT +{ + HANDLE hDevice; + BOOL quite; + ULONG BufferSize; + PUCHAR Buffer; + +} THREAD_CONTEXT, *PTHREAD_CONTEXT; + +typedef enum { + + MENU_TEST = 0, + READ_TEST = 1, + WRITE_TEST = 2, + READ_WRITE_TEST = 3, + THREAD_TEST = 4, + DEVICE_PATH = 5, + SET_SIZE = 6, + COMPARE_BUFFERS = 7, + DISPLAY_BUFFERS = 8, + THREAD_TIME = 9, + COMMAND_LINE = 10, + +} COMMAND; + +class PLX +{ + +public: + PLX(); + ~PLX(); + + BOOL + Initialize(); + + void + Menu(); + + BOOL + GetDevicePath(); + + BOOL + ReadTest(); + + BOOL + WriteTest(); + + BOOL + ReadWriteTest(); + + BOOL + CompareReadWriteBuffers(); + + BOOL + SetReadBufferSize(ULONG size); + + BOOL + SetWriteBufferSize(ULONG size); + + BOOL + SetBufferSizes(ULONG size); + + void + DisplayReadWriteBuffers(); + + BOOL + ThreadedReadWriteTest(); + + void + SetThreadLifeTime(ULONG time); + + BOOL Quite; + ULONG Status; + +private: + + BOOL + GetDeviceHandle(); + + HDEVINFO hDevInfo; + PSP_DEVICE_INTERFACE_DETAIL_DATA pDeviceInterfaceDetail; + HANDLE hDevice; + + ULONG ReadBufferSize; + ULONG WriteBufferSize; + _Field_size_bytes_(ReadBufferSize) PUCHAR ReadBuffer; + _Field_size_bytes_(WriteBufferSize) PUCHAR WriteBuffer; + + _Field_size_(ThreadCount) HANDLE *Threads; + _Field_size_(ThreadCount) PTHREAD_CONTEXT Contexts; + int ProcessorCount; + int ThreadCount; + + CRITICAL_SECTION CriticalSection; + BOOL CSInitialized; + + ULONG ThreadTimer; + + BOOL console; +}; + diff --git a/general/PLX9x5x/test/plx.vcxproj b/general/PLX9x5x/test/plx.vcxproj new file mode 100644 index 00000000..3dcbd6f3 --- /dev/null +++ b/general/PLX9x5x/test/plx.vcxproj @@ -0,0 +1,184 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{BF101CB1-B147-40AC-8F84-13AC122A2D37}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{F475764B-7D1A-49E4-8FA0-B4153BB184E4}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="plx.cpp"> + <WppEnabled>true</WppEnabled> + </ClCompile> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>plx</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>plx</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>plx</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>plx</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);BUILT_IN_DDK=1</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/PLX9x5x/test/plx.vcxproj.Filters b/general/PLX9x5x/test/plx.vcxproj.Filters new file mode 100644 index 00000000..b74b5937 --- /dev/null +++ b/general/PLX9x5x/test/plx.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{0B47F4CC-B263-41C6-86AF-E5D9448601A6}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{802D6182-3D0F-4A06-9D94-F6E77BA24FFD}</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>{F55A15F1-EBAB-45A9-AD99-9AA00FA8DA01}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="plx.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/PLX9x5x/test/test.cmd b/general/PLX9x5x/test/test.cmd new file mode 100644 index 00000000..7c744dbf --- /dev/null +++ b/general/PLX9x5x/test/test.cmd @@ -0,0 +1,2 @@ +start obj\i386\plx.exe /thread /time 10000 + diff --git a/general/SystemDma/wdm/ReadMe.md b/general/SystemDma/wdm/ReadMe.md new file mode 100644 index 00000000..6b15c480 --- /dev/null +++ b/general/SystemDma/wdm/ReadMe.md @@ -0,0 +1,14 @@ +System DMA +========== + +This sample demonstrates the usage of V3 System DMA. It shows how a driver could use a system DMA controller supported by Windows to write data to a hardware location using DMA. + +The sample consists of a legacy device driver and a Win32 console mode test application. The test application opens a handle to the device exposed by the driver and makes a DeviceIoControl call to initiate the example system DMA. To understand how the V3 system DMA calls are invoked please study SDmaWrite() in SDma.c. + +**Note** This sample driver is not a PnP driver. This is a minimal driver meant to demonstrate an OS feature. Neither it nor its sample programs are intended for use in a production environment. Rather, they are intended for educational purposes and as a skeleton driver. + +Run the sample +-------------- + +To test this driver, copy the test app, SystemDmaApp.exe, and the driver to the same directory, and run the application. The application will automatically load the driver if it's not already loaded and interact with the driver. When you exit the app, the driver will be stopped, unloaded and removed. Because no system DMA controller exists for Windows which uses the advertised DRQ, the sample driver will not proceed any further than failing to acquire a system DMA adapter. + diff --git a/general/SystemDma/wdm/SystemDma.sln b/general/SystemDma/wdm/SystemDma.sln new file mode 100644 index 00000000..1df1c8b0 --- /dev/null +++ b/general/SystemDma/wdm/SystemDma.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{91E3EEC7-4EBF-4BE0-A947-5C7C164EF77D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{6C0D6BEB-2BA2-4769-BD10-476085814CAE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemDmaApp", "exe\SystemDmaApp.vcxproj", "{3B7F8119-C721-4322-894C-0D3B49A38FFB}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDma", "sys\SDma.vcxproj", "{42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|Win32.ActiveCfg = Debug|Win32 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|Win32.Build.0 = Debug|Win32 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|Win32.ActiveCfg = Release|Win32 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|Win32.Build.0 = Release|Win32 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|x64.ActiveCfg = Debug|x64 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Debug|x64.Build.0 = Debug|x64 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|x64.ActiveCfg = Release|x64 + {3B7F8119-C721-4322-894C-0D3B49A38FFB}.Release|x64.Build.0 = Release|x64 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|Win32.ActiveCfg = Debug|Win32 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|Win32.Build.0 = Debug|Win32 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|Win32.ActiveCfg = Release|Win32 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|Win32.Build.0 = Release|Win32 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|x64.ActiveCfg = Debug|x64 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Debug|x64.Build.0 = Debug|x64 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|x64.ActiveCfg = Release|x64 + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3B7F8119-C721-4322-894C-0D3B49A38FFB} = {91E3EEC7-4EBF-4BE0-A947-5C7C164EF77D} + {42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE} = {6C0D6BEB-2BA2-4769-BD10-476085814CAE} + EndGlobalSection +EndGlobal diff --git a/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj new file mode 100644 index 00000000..25803eb1 --- /dev/null +++ b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj @@ -0,0 +1,196 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{3B7F8119-C721-4322-894C-0D3B49A38FFB}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{91239967-1454-4D74-8730-73372B2E0C94}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SystemDmaApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SystemDmaApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SystemDmaApp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SystemDmaApp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.c" /> + <ClCompile Include="testapp.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters new file mode 100644 index 00000000..6d4320c9 --- /dev/null +++ b/general/SystemDma/wdm/exe/SystemDmaApp.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{83BDC4AF-E38F-41A3-AE52-10470851D503}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{3C82C17E-76AD-4F6A-A677-A4591BB22A00}</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>{0D5328D1-97B0-4961-BF49-FB8CA3B73228}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="testapp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/SystemDma/wdm/exe/install.c b/general/SystemDma/wdm/exe/install.c new file mode 100644 index 00000000..68497c7d --- /dev/null +++ b/general/SystemDma/wdm/exe/install.c @@ -0,0 +1,537 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + +--*/ + + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strsafe.h> +#include "sdma.h" + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("CreateService failed! Error = %d \n", (int)err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + CloseServiceHandle(schService); + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + printf("Invalid Driver or Service provided to ManageDriver() \n"); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + printf("Open SC Manager failed! Error = %d \n", (int)GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + printf("Unknown ManageDriver() function. \n"); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + CloseServiceHandle(schSCManager); + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", (int)GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("DeleteService failed! Error = %d \n", (int)GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + CloseServiceHandle(schService); + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", (int)GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("StartService failure! Error = %d \n", (int)err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + CloseServiceHandle(schService); + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", (int)GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("ControlService failed! Error = %d \n", (int)GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + CloseServiceHandle (schService); + + return rCode; + +} // StopDriver + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ) +{ + HANDLE fileHandle; + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(BufferLength, + DriverLocation + ); + + if (driverLocLen == 0 || driverLocLen < BufferLength) { + + printf("GetCurrentDirectory failed! Error = %d \n", (int)GetLastError()); + + return FALSE; + } + + DriverLocation[ driverLocLen - 1 ] = '\0'; + + // + // Setup path name to driver file. + // + if (FAILED( StringCbCat(DriverLocation, BufferLength, "\\"DRIVER_NAME".sys") )) { + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + printf("%s.sys is not loaded.\n", DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName + + + diff --git a/general/SystemDma/wdm/exe/testapp.c b/general/SystemDma/wdm/exe/testapp.c new file mode 100644 index 00000000..0462f544 --- /dev/null +++ b/general/SystemDma/wdm/exe/testapp.c @@ -0,0 +1,180 @@ +/*++ + +Copyright (c) 1990-98 Microsoft Corporation All Rights Reserved + +Module Name: + + testapp.c + +Abstract: + +Environment: + + Win32 console multi-threaded application + +--*/ +#include <windows.h> +#include <winioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strsafe.h> +#include "..\sys\sdma.h" + + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ); + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ); + +char OutputBuffer[100]; +char InputBuffer[100]; + +VOID __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + HANDLE hDevice; + BOOL bRc; + ULONG bytesReturned; + DWORD errNum = 0; + TCHAR driverLocation[MAX_PATH]; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + // + // open the device + // + + if ((hDevice = CreateFile( "\\\\.\\DmaTest", + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + + errNum = GetLastError(); + + if (errNum != ERROR_FILE_NOT_FOUND) { + + printf("CreateFile failed! ERROR_FILE_NOT_FOUND = %d\n", (int)errNum); + + return ; + } + + // + // The driver is not started yet so let us the install the driver. + // First setup full path to driver name. + // + + if (!SetupDriverName(driverLocation, sizeof(driverLocation))) { + + return ; + } + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + printf("Unable to install driver. \n"); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return; + } + + hDevice = CreateFile( "\\\\.\\DmaTest", + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if ( hDevice == INVALID_HANDLE_VALUE ){ + printf ( "Error: CreatFile Failed : %d\n", (int)GetLastError()); + return; + } + + } + +#if 0 + // + // Printing Input & Output buffer pointers and size + // + + printf("InputBuffer Pointer = %p, BufLength = %d\n", (ULONG *)InputBuffer, + sizeof(InputBuffer)); + printf("OutputBuffer Pointer = %p BufLength = %d\n", (ULONG *)OutputBuffer, + sizeof(OutputBuffer)); +#endif + + // + // Performing METHOD_BUFFERED + // + + StringCbCopy(InputBuffer, sizeof(InputBuffer), + "This String is from User Application; using METHOD_BUFFERED"); + + printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n"); + + memset(OutputBuffer, 0, sizeof(OutputBuffer)); + + bRc = DeviceIoControl ( hDevice, + (DWORD) IOCTL_SDMA_WRITE, + &InputBuffer, + (DWORD) strlen ( InputBuffer )+1, + &OutputBuffer, + sizeof( OutputBuffer), + &bytesReturned, + NULL + ); + + if ( !bRc ) + { + printf ( "Error in DeviceIoControl : %d", (int)GetLastError()); + return; + + } + printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); + + CloseHandle ( hDevice ); + + // + // Unload the driver. Ignore any errors. + // + + driverLocation[ 259 ] = '\0'; + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + + // + // close the handle to the device. + // + +} + + diff --git a/general/SystemDma/wdm/sys/SDma.vcxproj b/general/SystemDma/wdm/sys/SDma.vcxproj new file mode 100644 index 00000000..fb50d847 --- /dev/null +++ b/general/SystemDma/wdm/sys/SDma.vcxproj @@ -0,0 +1,140 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{42AC88BC-11CC-4FC0-B2EF-50B6CA8DDBCE}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{BB0473B0-289C-4FA0-9E81-C6EA8C79707D}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SDma</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SDma</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SDma</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SDma</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="sdma.c" /> + <ResourceCompile Include="sdma.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/SystemDma/wdm/sys/SDma.vcxproj.Filters b/general/SystemDma/wdm/sys/SDma.vcxproj.Filters new file mode 100644 index 00000000..259eadd5 --- /dev/null +++ b/general/SystemDma/wdm/sys/SDma.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{7F208255-EDD4-4E3B-83EC-EBB1682D21C8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{B5677F44-0B89-43F0-91FB-984AB0713883}</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>{82A0D909-8651-4045-8729-2AF8321AB2BB}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{7D13F81D-2971-47FA-9382-E4CF95208FA4}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="sdma.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="sdma.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/SystemDma/wdm/sys/sdma.c b/general/SystemDma/wdm/sys/sdma.c new file mode 100644 index 00000000..629d43d5 --- /dev/null +++ b/general/SystemDma/wdm/sys/sdma.c @@ -0,0 +1,1364 @@ +/*++ + +Copyright (c) 2011 Microsoft Corporation All Rights Reserved + +Module Name: + + sdma.c + +Abstract: + + The purpose of this driver is to demonstrate V3 system DMA. + +Environment: + + Kernel mode only. + +--*/ + + +// +// Include files. +// + +#include <ntddk.h> // various NT definitions +#include <string.h> + +#include "sdma.h" + +#define NT_DEVICE_NAME L"\\Device\\SDMA" +#define DOS_DEVICE_NAME L"\\DosDevices\\DmaTest" + +#if DBG +#define SDMA_KDPRINT(_x_) \ + DbgPrint("SDMA.SYS: ");\ + DbgPrint _x_; + +#else +#define SDMA_KDPRINT(_x_) +#endif + +// +// These are the states a PDO or FDO transition upon +// receiving a specific PnP Irp. Refer to the PnP Device States +// diagram in DDK documentation for better understanding. +// + +typedef enum _DEVICE_PNP_STATE { + + NotStarted = 0, // Not started yet + Started, // Device has received the START_DEVICE IRP + StopPending, // Device has received the QUERY_STOP IRP + Stopped, // Device has received the STOP_DEVICE IRP + RemovePending, // Device has received the QUERY_REMOVE IRP + SurpriseRemovePending, // Device has received the SURPRISE_REMOVE IRP + Deleted, // Device has received the REMOVE_DEVICE IRP + UnKnown // Unknown state + +} DEVICE_PNP_STATE; + +typedef struct _COMMON_DEVICE_DATA +{ + // A back pointer to the device object for which this is the extension + + PDEVICE_OBJECT Self; + + // This flag helps distinguish between PDO and FDO + + BOOLEAN IsFDO; + + // We track the state of the device with every PnP Irp + // that affects the device through these two variables. + + DEVICE_PNP_STATE DevicePnPState; + + DEVICE_PNP_STATE PreviousPnPState; + + + ULONG DebugLevel; + + // Stores the current system power state + + SYSTEM_POWER_STATE SystemPowerState; + + // Stores current device power state + + DEVICE_POWER_STATE DevicePowerState; + + ULONG ulVariationFlags; + +} COMMON_DEVICE_DATA, *PCOMMON_DEVICE_DATA; + +// +// The device extension of the bus itself. From whence the PDO's are born. +// + +typedef struct _FDO_DEVICE_DATA +{ + COMMON_DEVICE_DATA CommonData; + + PDEVICE_OBJECT UnderlyingPDO; + + // The underlying bus PDO and the actual device object to which our + // FDO is attached + + PDEVICE_OBJECT NextLowerDriver; + + // List of PDOs created so far + + LIST_ENTRY ListOfPDOs; + + // The PDOs currently enumerated. + + ULONG NumPDOs; + + // A synchronization for access to the device extension. + + FAST_MUTEX Mutex; + + // + // The number of IRPs sent from the bus to the underlying device object + // + + ULONG OutstandingIO; // Biased to 1 + + // + // On remove device plug & play request we must wait until all outstanding + // requests have been completed before we can actually delete the device + // object. This event is when the Outstanding IO count goes to zero + // + + KEVENT RemoveEvent; + + // + // This event is set when the Outstanding IO count goes to 1. + // + + KEVENT StopEvent; + + // The name returned from IoRegisterDeviceInterface, + // which is used as a handle for IoSetDeviceInterfaceState. + + UNICODE_STRING InterfaceName; + +} FDO_DEVICE_DATA, *PFDO_DEVICE_DATA; + +// +// Define minimum and maximum macros. +// + +#define Minimum(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#define Maximum(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) + +// +// Define the structure that we'll use to communicate with our +// AllocateAdapterChannel callback. +// + +typedef struct _SDMA_CALLBACK_CONTEXT { + IO_ALLOCATION_ACTION Action; + ULONG NumberOfMapRegisters; + PVOID MapRegisterBase; + KEVENT CallBackEvent; + KEVENT CompletionEvent; +} SDMA_CALLBACK_CONTEXT, *PSDMA_CALLBACK_CONTEXT; + +// +// Device driver routine declarations. +// + +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH SDmaCreateClose; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH SDmaDeviceControl; + +DRIVER_UNLOAD SDmaUnloadDriver; + +VOID +PrintIrpInfo( + PIRP Irp + ); +VOID +PrintChars( + _In_reads_(CountChars) PCHAR BufferAddress, + _In_ size_t CountChars + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, DriverEntry ) +#pragma alloc_text( PAGE, SDmaCreateClose) +#pragma alloc_text( PAGE, SDmaDeviceControl) +#pragma alloc_text( PAGE, SDmaUnloadDriver) +#pragma alloc_text( PAGE, PrintIrpInfo) +#pragma alloc_text( PAGE, PrintChars) +#endif // ALLOC_PRAGMA + + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + This routine is called by the Operating System to initialize the driver. + + It creates the device object, fills in the dispatch entry points and + completes the initialization. + +Arguments: + DriverObject - a pointer to the object that represents this device + driver. + + RegistryPath - a pointer to our Services key in the registry. + +Return Value: + STATUS_SUCCESS if initialized; an error otherwise. + +--*/ + +{ + NTSTATUS ntStatus; + UNICODE_STRING ntUnicodeString; // NT Device Name "\Device\SDMA" + UNICODE_STRING ntWin32NameString; // Win32 Name "\DosDevices\DmaTest" + PDEVICE_OBJECT deviceObject = NULL; // ptr to device object + + UNREFERENCED_PARAMETER(RegistryPath); + + RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME ); + + ntStatus = IoCreateDevice( + DriverObject, // Our Driver Object + 0, // We don't use a device extension + &ntUnicodeString, // Device name "\Device\SDMA" + FILE_DEVICE_UNKNOWN, // Device type + FILE_DEVICE_SECURE_OPEN, // Device characteristics + FALSE, // Not an exclusive device + &deviceObject ); // Returned ptr to Device Object + + if ( !NT_SUCCESS( ntStatus ) ) + { + SDMA_KDPRINT(("Couldn't create the device object\n")); + return ntStatus; + } + + // + // Initialize the driver object with this driver's entry points. + // + + DriverObject->MajorFunction[IRP_MJ_CREATE] = SDmaCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = SDmaCreateClose; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SDmaDeviceControl; + DriverObject->DriverUnload = SDmaUnloadDriver; + + // + // Initialize a Unicode String containing the Win32 name + // for our device. + // + + RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME ); + + // + // Create a symbolic link between our device name and the Win32 name + // + + ntStatus = IoCreateSymbolicLink( + &ntWin32NameString, &ntUnicodeString ); + + if ( !NT_SUCCESS( ntStatus ) ) + { + // + // Delete everything that this routine has allocated. + // + SDMA_KDPRINT(("Couldn't create symbolic link\n")); + IoDeleteDevice( deviceObject ); + } + + + return ntStatus; +} + + +NTSTATUS +SDmaCreateClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + This routine is called by the I/O system when the driver is opened or + closed. + + No action is performed other than completing the request successfully. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE(); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + +VOID +SDmaUnloadDriver( + _In_ PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + This routine is called by the I/O system to unload the driver. + + Any resources previously allocated must be freed. + +Arguments: + + DriverObject - a pointer to the object that represents our driver. + +Return Value: + + None +--*/ + +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + + PAGED_CODE(); + + // + // Create counted string version of our Win32 device name. + // + + RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); + + + // + // Delete the link from our device name to a name in the Win32 namespace. + // + + IoDeleteSymbolicLink( &uniWin32NameString ); + + if ( deviceObject != NULL ) + { + IoDeleteDevice( deviceObject ); + } + + + +} + +// +// These helper routines allow MDL creation and destruction +// as well as providing simple DMA callback routines for +// channel allocation and DMA completion. +// + +ULONG +MDL_SPAN( + _In_ PMDL Mdl, + _In_ PVOID CurrentVa, + ULONG Length + ) + +/*++ + +Routine Description: + + This function determines the number of pages spanned by the given MDL. + We have to account for the case where the MDL is actually the head of + a chain. + +Arguments: + + Mdl - Supplies the MDL being checked. + + CurrentVa - Provides our starting address within the first MDL. + + Length - Supplies the total number of bytes from the given MDL chain that + are associated with this transfer. + +Return Value: + + This function returns the number of pages spanned by the specified + transfer. + +--*/ + +{ + PVOID VirtualAddress; + ULONG Span; + ULONG RemainingLength; + ULONG ChunkLength; + ULONG MdlOffset; + + if (Length == 0) + { + return 0; + } + + if (Mdl->Next == NULL) + { + return ADDRESS_AND_SIZE_TO_SPAN_PAGES(CurrentVa, Length); + } + + Span = 0; + RemainingLength = Length; + VirtualAddress = CurrentVa; + + MdlOffset = (ULONG) (((ULONG_PTR) CurrentVa) + - ((ULONG_PTR) MmGetMdlVirtualAddress(Mdl))); + + while (Mdl != NULL) + { + ChunkLength = Minimum(MmGetMdlByteCount(Mdl) - MdlOffset, + RemainingLength); + + Span += ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ChunkLength); + + Mdl = Mdl->Next; + MdlOffset = 0; + RemainingLength -= ChunkLength; + + if (Mdl != NULL) + { + VirtualAddress = MmGetMdlVirtualAddress(Mdl); + } + + } + + return Span; +} + +VOID +SDmaFreeMdl( + _In_opt_ PMDL MdlHead + ) + +/*++ + +Routine Description: + + This function frees an MDL that was allocated earlier with a call to + DmaUnitAllocateMdl. + +Arguments: + + MdlHead - Supplies the MDL to free. This could be the head of a chain + of MDLs. + +Return Value: + + None. + +--*/ + +{ + PMDL Mdl; + PMDL NextMdl; + + Mdl = MdlHead; + + while (Mdl != NULL) + { + if ((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != 0) + { + MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); + } + + MmFreePagesFromMdl(Mdl); + + NextMdl = Mdl->Next; + ExFreePool(Mdl); + + Mdl = NextMdl; + } + + return; +} + +VOID SDmaFillMdl( + _In_ PMDL Mdl, + _In_ PVOID CurrentVa, + _In_ ULONG Length, + _In_ UCHAR Fill + ) + +/*++ + +Routine Description: + + This function fills an MDL with a data byte. + +Arguments: + + Mdl - Supplies the MDL that describes the system pages associated with + this transfer. + + CurrentVa - Provides the starting address of the transfer within + the given MDL. + + Length - Supplies the length of the transfer in bytes. + + Fill - The byte to write into the MDL. + +Return Value: + + None + +--*/ + +{ + ULONG MdlOffset; + ULONG PageOffset; + ULONG ChunkLength; + PCHAR VirtualAddress; + ULONG RemainingLength; + + RemainingLength = Length; + while (Mdl != NULL) + { + + MdlOffset = (ULONG) (((ULONG_PTR) CurrentVa) + - ((ULONG_PTR) MmGetMdlVirtualAddress(Mdl))); + + ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != 0); + + PageOffset = BYTE_OFFSET(CurrentVa); + VirtualAddress = PAGE_ALIGN(((PCHAR) Mdl->MappedSystemVa) + MdlOffset); + + while ((MdlOffset != MmGetMdlByteCount(Mdl)) + && (RemainingLength != 0)) + { + + ChunkLength = Minimum(MmGetMdlByteCount(Mdl) - MdlOffset, + RemainingLength); + + ChunkLength = Minimum(ChunkLength, PAGE_SIZE - PageOffset); + + ASSERT((PageOffset + ChunkLength) <= PAGE_SIZE); + + RtlFillMemory(((PCHAR) VirtualAddress) + PageOffset, ChunkLength, + Fill); + + PageOffset = 0; + RemainingLength -= ChunkLength; + MdlOffset += ChunkLength; + VirtualAddress = VirtualAddress + ChunkLength; + } + + Mdl = Mdl->Next; + } +} + +VOID SDmaPrintMdl( + _In_ PMDL Mdl, + _In_ PVOID CurrentVa, + _In_ ULONG Length, + _In_ PCHAR TitleStr + ) + +/*++ + +Routine Description: + + This function prints MDL information to the debugger. + +Arguments: + + Mdl - Supplies the MDL to be displayed. + + CurrentVa - Provides the starting address of the transfer within + the given MDL. + + Length - Supplies the length of the transfer in bytes. + + TitleStr - A text tile to print describing this MDL. + +Return Value: + + None + +--*/ + +{ + ULONG MdlOffset; + PCHAR VirtualAddress; + ULONG MdlCount = 0; + ULONG TotalLength = 0; + PPFN_NUMBER PageFrame; + ULONG NumPages = 0; + ULONG PageCount = 0; + PMDL MdlHead; + PHYSICAL_ADDRESS PageAddress; + ULONG RemainingLength; + ULONG ChunkLength; + + MdlOffset = (ULONG) (((ULONG_PTR) CurrentVa) + - ((ULONG_PTR) MmGetMdlVirtualAddress(Mdl))); + + MdlHead = Mdl; + NumPages = MDL_SPAN(MdlHead, CurrentVa, Length); + while (Mdl != NULL) + { + + TotalLength += Minimum(MmGetMdlByteCount(Mdl) - MdlOffset, + Length); + + Mdl = Mdl->Next; + MdlCount++; + } + + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "########### %s ########\n", + TitleStr == NULL ? "MDL" : TitleStr ); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "Mdl Head = 0x%p\n", MdlHead); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "Mdl Count = %d\n", MdlCount); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "Total Byte Count = %d\n", TotalLength); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "Total Physical Pages = %d\n", NumPages); + + Mdl = MdlHead; + MdlCount = 0; + RemainingLength = Length; + while (Mdl != NULL) + { + + MdlOffset = (ULONG) (((ULONG_PTR) CurrentVa) + - ((ULONG_PTR) MmGetMdlVirtualAddress(Mdl))); + + ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) != 0); + + VirtualAddress = PAGE_ALIGN(((PCHAR) Mdl->MappedSystemVa) + MdlOffset); + ChunkLength = Minimum(MmGetMdlByteCount(Mdl) - MdlOffset, + RemainingLength); + + NumPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress, ChunkLength); + + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "########################################\n"); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "Mdl #%d: 0x%p\n", MdlCount, Mdl); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, " Mdl Offset = %d\n", MdlOffset); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, " Mdl Length = %d\n", Mdl->ByteCount); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, " Mdl Base VA = 0x%p\n", VirtualAddress); + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "------------ PHYSICAL PAGES ------------\n"); + PageFrame = MmGetMdlPfnArray( Mdl ); + + for (PageCount = 0; PageCount < NumPages; PageCount++) + { + PageAddress.QuadPart = (ULONGLONG)(*(PageFrame + PageCount)) << PAGE_SHIFT; + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, " Page #%d: 0x%I64x\n", PageCount, PageAddress.QuadPart); + } + + Mdl = Mdl->Next; + RemainingLength -= ChunkLength; + MdlCount++; + } + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "########################################\n"); +} + +PMDL +SDmaAllocateMdl( + _Out_ PVOID *CurrentVa, + _Out_ PULONG Length, + _In_ BOOLEAN ForceContiguous + ) + +/*++ + +Routine Description: + + This function allocates a single MDL. + +Arguments: + + CurrentVa - Supplies the location where we should store the starting + virtual address of the transfer within the allocated MDL. + + Length - Supplies the location where we should store the length of + the requested transfer. + +Return Value: + + This function returns a pointer to a single MDL. + +--*/ + +{ + PMDL MdlHead; + PMDL Mdl; + ULONG Span; + ULONG RequestBytes; + PHYSICAL_ADDRESS LowAddress; + PHYSICAL_ADDRESS HighAddress; + PHYSICAL_ADDRESS SkipAddress; + PVOID MappingAddress; + ULONG TransferLength; + ULONG Offset; + + *Length = 0; + *CurrentVa = NULL; + LowAddress.QuadPart = 0; + HighAddress.QuadPart = 0xffffffffffffffffI64; + SkipAddress.QuadPart = 0; + + // + // Add one MDL. + // + + MdlHead = NULL; + TransferLength = 0; + + { + Span = 2; + RequestBytes = Span << PAGE_SHIFT; + + if (ForceContiguous) + { + Mdl = MmAllocatePagesForMdlEx(LowAddress, + HighAddress, + SkipAddress, + RequestBytes, + MmCached, + MM_ALLOCATE_REQUIRE_CONTIGUOUS_CHUNKS + ); + } + else + { + Mdl = MmAllocatePagesForMdl(LowAddress, + HighAddress, + SkipAddress, + RequestBytes + ); + } + + if (Mdl == NULL) + { + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "MmAllocatePagesForMdl failed. \n" ); + goto Cleanup; + } + + if (MmGetMdlByteCount(Mdl) < RequestBytes) + { + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "MmAllocatePagesForMdl allocated less than requested bytes. \n" ); + goto Cleanup; + } + + // + // Set the byte count and byte offset appropriately for this MDL. + // Note that this is safe since we allocated enough memory to cover + // the entire page span up above. + // + + Mdl->ByteCount = RequestBytes; + Mdl->ByteOffset = 0; + + MappingAddress = MmMapLockedPagesSpecifyCache( + Mdl, + KernelMode, + MmCached, + NULL, + FALSE, + HighPagePriority); + + if (MappingAddress == NULL) + { + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "MmMapLockedPagesSpecifyCache failed. \n" ); + goto Cleanup; + } + + if (MdlHead == NULL) + { + MdlHead = Mdl; + } + + TransferLength += RequestBytes; + } + + Offset = 0; + + *CurrentVa = + (PVOID) (((ULONG_PTR) MmGetMdlVirtualAddress(MdlHead)) + Offset); + + *Length = TransferLength - Offset; + + return MdlHead; + + // + // We'll branch to this point when we need to free the active MDL and + // the MDL that we've built up to this point. + // + +Cleanup: + + if (Mdl != NULL) + { + MmFreePagesFromMdl(Mdl); + ExFreePool(Mdl); + } + + if (MdlHead != NULL) + { + SDmaFreeMdl(MdlHead); + } + + return NULL; +} + +_Function_class_(DRIVER_CONTROL) +IO_ALLOCATION_ACTION +SDmaAdapterControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID MapRegisterBase, + IN PVOID Context + ) + +/*++ + +Routine Description: + + This is the AdapterControl routine that we'll use to complete calls + to AllocateAdapterChannelEx. + +Arguments: + + DeviceObject - Supplies the FDO associated with this AllocateAdapterChannelEx + call. + + Irp - Unused. + + MapRegisterBase - Supplies the handle to our allocated map registers. + + Context - Supplies the callback context that was passed to + AllocateAdapterChannelEx. In our case this will be a + context structure. + +Return Value: + + This function returns the Action parameter from the given callback + context structure. + +Environment: + + DISPATCH_LEVEL. + +--*/ + +{ + IO_ALLOCATION_ACTION Action; + PSDMA_CALLBACK_CONTEXT CallbackContext; + + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(DeviceObject); + + CallbackContext = (PSDMA_CALLBACK_CONTEXT) Context; + + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "AllocateAdapterChannelEx called back." + " MapRegisterBase = 0x%IX\n", (ULONG_PTR)MapRegisterBase + ); + + // + // Make a note of the allocated map register base and return the handle + // associated with this map register allocation to the caller. + // + CallbackContext->MapRegisterBase = MapRegisterBase; + + Action = CallbackContext->Action; + + KeSetEvent(&(CallbackContext->CallBackEvent), IO_NO_INCREMENT, FALSE); + + return Action; +} + +_Function_class_(DMA_COMPLETION_ROUTINE) +VOID +SDmaCompletion( + IN PDMA_ADAPTER DmaAdapter, + IN PDEVICE_OBJECT DeviceObject, + IN PVOID Context, + IN DMA_COMPLETION_STATUS Status + ) + +/*++ + +Routine Description: + + This is the DMA completion routine that we'll use to complete calls + to MapTransferEx. + +Arguments: + + DeviceObject - Supplies the FDO associated with this MapTransferEx + call. + + Context - Supplies the callback context that was passed to + MapTransferEx. In our case this will be a + context structure. + +Return Value: + + None. + +Environment: + + DISPATCH_LEVEL. + +--*/ + +{ + PSDMA_CALLBACK_CONTEXT CallbackContext; + + UNREFERENCED_PARAMETER(DmaAdapter); + UNREFERENCED_PARAMETER(DeviceObject); + + CallbackContext = (PSDMA_CALLBACK_CONTEXT) Context; + + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "MapTransferEx called back. Status = %d\n", + Status + ); + + KeSetEvent(&(CallbackContext->CompletionEvent), IO_NO_INCREMENT, FALSE); +} + +NTSTATUS +SDmaWrite( + _In_ PFDO_DEVICE_DATA pFdoData + ) + +/*++ + +Routine Description: + + This function initiates simple system DMA against a + non-existent DMA controller. The code is provided + only for example purposes and is not intended as product + code. + +Arguments: + + pFdoData - Supplies the FDO extension + +Return Value: + + This function returns a NTSTATUS value. + +--*/ + +{ + KIRQL Irql; + ULONG DmaRequestLine = 0x1000; + NTSTATUS Status = STATUS_SUCCESS; + PDMA_ADAPTER pWriteAdapter = NULL; + ULONG AllocatableMapRegisters = 0, RequestedMapRegisters = 2; + DEVICE_DESCRIPTION Description; + SDMA_CALLBACK_CONTEXT WriteContext; + CHAR WriteDmaTransferContext[ DMA_TRANSFER_CONTEXT_SIZE_V1 ]; + PMDL Mdl0 = NULL; + PVOID CurrentVa = NULL; + ULONG Length = 0; + + // + // Allocate a system DMA adapter to write data to a device + // (for instance the Tx register of a UART) using system DMA. + // + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + RtlZeroMemory(&Description, sizeof(Description)); + Description.Version = DEVICE_DESCRIPTION_VERSION3; + Description.DmaAddressWidth = 32; + Description.DmaRequestLine = DmaRequestLine; + Description.DmaChannel = DmaRequestLine; + Description.InterfaceType = ACPIBus; + Description.Master = FALSE; + Description.ScatterGather = TRUE; + Description.MaximumLength = RequestedMapRegisters << PAGE_SHIFT; + + pWriteAdapter = IoGetDmaAdapter(pFdoData->UnderlyingPDO, + &Description, + &AllocatableMapRegisters); + + // + // This is the expected return path on all systems, since no + // system DMA controller supports request line 0x1000. + // + if ( pWriteAdapter == NULL ) + { + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, "IoGetDmaAdapter failed for request line %d. \n", Description.DmaRequestLine ); + Status = STATUS_NO_MATCH; + goto Exit; + } + + RtlZeroMemory( &WriteContext, sizeof( WriteContext ) ); + WriteContext.Action = KeepObject; + WriteContext.NumberOfMapRegisters = AllocatableMapRegisters; + KeInitializeEvent(&(WriteContext.CallBackEvent), NotificationEvent, FALSE); + KeInitializeEvent(&(WriteContext.CompletionEvent), NotificationEvent, FALSE); + + pWriteAdapter->DmaOperations->InitializeDmaTransferContext( + pWriteAdapter, + (PVOID)&(WriteDmaTransferContext)); + + DbgPrintEx(DPFLTR_IHVBUS_ID, 0, + "%p WRITE V3 System DmaAdapter created: 32 bit, Scatter-Gather capable, %d MapRegs (%d requested)\n", + pWriteAdapter, AllocatableMapRegisters, RequestedMapRegisters + ); + + // + // Call AllocateAdapterChannelEx for the write adapter. + // + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + + Status = pWriteAdapter->DmaOperations->AllocateAdapterChannelEx( + pWriteAdapter, + pFdoData->CommonData.Self, + &(WriteDmaTransferContext), + AllocatableMapRegisters, + 0, + SDmaAdapterControl, + (PVOID) &WriteContext, + NULL); + KeLowerIrql(Irql); + + if (Status != STATUS_SUCCESS) + { + goto Exit; + } + + // + // Wait for the channel to be allocated to our driver. A real driver would + // not block this IRP to wait for AllocateAdapterChannelEx to call + // back the AdapterControl routine. Instead all the steps below (including + // the MapTransferEx) would be staged from with the AdapterControl + // routine. + // + + KeWaitForSingleObject(&(WriteContext.CallBackEvent), Executive, KernelMode, FALSE, NULL); + + // + // We have acquired a channel for Write adapter successfully. + // + + // + // Build a fake MDL to represent user data. + // Mdl0 is the address for the Write channel, and is the + // data (likely from usermode in real world scenarios) that + // will be written to the device address (this address may + // be the Tx register of a UART device for instance). + // + + Mdl0 = SDmaAllocateMdl(&CurrentVa, &Length, FALSE); + + // + // Fill the MDL with 0xDA bytes. + // + + SDmaPrintMdl( Mdl0, CurrentVa, Length, "Mdl0" ); + SDmaFillMdl( Mdl0, CurrentVa, Length, 0xDA ); + + // + // Signal the DMA engine to write the entire length of the + // MDL using V3 system DMA. + // We just use a 0 offset since our CurrentVa starts at the + // beginning of the MDL. + // + + pWriteAdapter->DmaOperations->MapTransferEx( + pWriteAdapter, + Mdl0, + WriteContext.MapRegisterBase, + 0, + 0x70006200, // Physical address of hardware + // device + // (e.g. UART Tx register) + &Length, + TRUE, + NULL, + 0, + SDmaCompletion, + &WriteContext); + + // + // Wait for DMA to complete on the channel. A real driver + // would not block this IRP to wait but would instead handle the + // FlushAdapterBuffersEx/FreeAdapterChannel steps during the DMA + // completion routine. + // + + KeWaitForSingleObject(&(WriteContext.CompletionEvent), Executive, KernelMode, FALSE, NULL); + + // + // Copy the data in the map buffers (if any) back to the MDL. + // + + pWriteAdapter->DmaOperations->FlushAdapterBuffersEx( + pWriteAdapter, + Mdl0, + WriteContext.MapRegisterBase, + 0, + Length, + TRUE); + + // + // Now we can free the MDL associated with this transfer. + // + + SDmaFreeMdl(Mdl0); + + // + // Return the channel back to the HAL. If this action is + // not taken, then nothing else in the OS will be able to + // use this channel again until it is freed. This includes + // our own driver handling another IOCTL. + // + + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + pWriteAdapter->DmaOperations->FreeAdapterChannel( pWriteAdapter ); + KeLowerIrql(Irql); + +Exit: + + // + // Free the DMA adapter. Typically a driver will not Get and Put + // a DMA adapter for each DMA transaction, but instead will perform + // these actions once upon device driver construction and destruction. + // + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + if (pWriteAdapter != NULL) + { + pWriteAdapter->DmaOperations->PutDmaAdapter(pWriteAdapter); + } + + // + // Send our return status. + // + + return Status; +} + +NTSTATUS +SDmaDeviceControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine is called by the I/O system to perform a device I/O + control function. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + PIO_STACK_LOCATION irpSp;// Pointer to current stack location + NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success + ULONG inBufLength; // Input buffer length + ULONG outBufLength; // Output buffer length + PCHAR inBuf; // pointer to Input buffer + PCHAR data = "This String is from Device Driver !!!"; + size_t datalen = strlen(data)+1;//Length of data including null + PFDO_DEVICE_DATA fdoData; + + PAGED_CODE(); + + fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension; + irpSp = IoGetCurrentIrpStackLocation( Irp ); + inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; + outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + + if (!inBufLength || !outBufLength) + { + ntStatus = STATUS_INVALID_PARAMETER; + goto End; + } + + // + // Determine which I/O control code was specified. + // + + switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) + { + case IOCTL_SDMA_WRITE: + + // + // In this method the I/O manager allocates a buffer large enough to + // to accommodate larger of the user input buffer and output buffer, + // assigns the address to Irp->AssociatedIrp.SystemBuffer, and + // copies the content of the user input buffer into this SystemBuffer + // + + SDMA_KDPRINT(("Called IOCTL_SDMA_WRITE\n")); + PrintIrpInfo(Irp); + + // + // Input buffer and output buffer is same in this case, read the + // content of the buffer before writing to it + // + + inBuf = Irp->AssociatedIrp.SystemBuffer; +#if 0 + outBuf = Irp->AssociatedIrp.SystemBuffer; +#endif + + // + // Read the data from the buffer + // + + SDMA_KDPRINT(("\tData from User :")); + // + // We are using the following function to print characters instead + // of DebugPrint with %s format because the string we get may or + // may not be null terminated. + // + PrintChars(inBuf, inBufLength); + + // + // Call the example V3 system DMA routine. The routine + // is expected to fail because no system DMA controller + // will match the one requested within the routine. + // + + SDmaWrite( fdoData ); + +#if 0 + // + // Write to the buffer over-writes the input buffer content + // + + RtlCopyBytes(outBuf, data, outBufLength); + + SDMA_KDPRINT(("\tData to User : ")); + PrintChars(outBuf, datalen ); +#endif + + // + // Assign the length of the data copied to IoStatus.Information + // of the Irp and complete the Irp. + // + + Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); + + // + // When the Irp is completed the content of the SystemBuffer + // is copied to the User output buffer and the SystemBuffer is + // is freed. + // + + break; + + default: + + // + // The specified I/O control code is unrecognized by this driver. + // + + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + SDMA_KDPRINT(("ERROR: unrecognized IOCTL %x\n", + irpSp->Parameters.DeviceIoControl.IoControlCode)); + break; + } + +End: + // + // Finish the I/O operation by simply completing the packet and returning + // the same status as in the packet itself. + // + + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return ntStatus; +} + +VOID +PrintIrpInfo( + PIRP Irp) +{ + PIO_STACK_LOCATION irpSp; + irpSp = IoGetCurrentIrpStackLocation( Irp ); + + PAGED_CODE(); + + SDMA_KDPRINT(("\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n", + Irp->AssociatedIrp.SystemBuffer)); + SDMA_KDPRINT(("\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer)); + SDMA_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n", + irpSp->Parameters.DeviceIoControl.Type3InputBuffer)); + SDMA_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n", + irpSp->Parameters.DeviceIoControl.InputBufferLength)); + SDMA_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n", + irpSp->Parameters.DeviceIoControl.OutputBufferLength )); + + UNREFERENCED_PARAMETER(irpSp); + return; +} + +VOID +PrintChars( + _In_reads_(CountChars) PCHAR BufferAddress, + _In_ size_t CountChars + ) +{ + PAGED_CODE(); + + if (CountChars) { + + while (CountChars--) { + + if (*BufferAddress > 31 + && *BufferAddress != 127) { + + KdPrint (( "%c", *BufferAddress) ); + + } else { + + KdPrint(( ".") ); + + } + BufferAddress++; + } + KdPrint (("\n")); + } + return; +} + + diff --git a/general/SystemDma/wdm/sys/sdma.h b/general/SystemDma/wdm/sys/sdma.h new file mode 100644 index 00000000..d59b4077 --- /dev/null +++ b/general/SystemDma/wdm/sys/sdma.h @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) 2011 Microsoft Corporation + +Module Name: + + SDMA.H + +Abstract: + + + Defines the IOCTL codes that will be used by this driver. The IOCTL code + contains a command identifier, plus other information about the device, + the type of access with which the file must have been opened, + and the type of buffering. + +Environment: + + Kernel mode only. + +--*/ + +// +// Device type -- in the "User Defined" range." +// +#define SDMA_TYPE 40000 +// +// The IOCTL function codes from 0x800 to 0xFFF are for customer use. +// + +#define IOCTL_SDMA_WRITE \ + CTL_CODE( SDMA_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 + +#define DRIVER_NAME "SDMA" + diff --git a/general/SystemDma/wdm/sys/sdma.rc b/general/SystemDma/wdm/sys/sdma.rc new file mode 100644 index 00000000..42cb81b9 --- /dev/null +++ b/general/SystemDma/wdm/sys/sdma.rc @@ -0,0 +1,10 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Sample V3 System DMA Driver" +#define VER_INTERNALNAME_STR "SDMA.sys" + +#include "common.ver" diff --git a/general/cancel/ReadMe.md b/general/cancel/ReadMe.md new file mode 100644 index 00000000..5baab9b9 --- /dev/null +++ b/general/cancel/ReadMe.md @@ -0,0 +1,27 @@ +Cancel-Safe IRP Queue Sample +============================ + +This sample demonstrates the use of the cancel-safe queue routines [**IoCsqInitialize**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549054), [**IoCsqInsertIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549066), [**IoCsqRemoveIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549070), [**IoCsqRemoveNextIrp**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff549072). These routines were introduced in Windows XP for queuing IRPs in the driver's internal device queue. By using these routines, driver developers do not have to worry about IRP cancellation race conditions. A common problem with cancellation of IRPs in a driver is synchronization between the cancel lock or the InterlockedExchange in the I/O Manager with the driver's queue lock. The **IoCsq*Xxx*** routines abstract the cancel logic while allowing the driver to implement the queue and associated synchronization. + +The sample is accompanied by a simple multithreaded Win32 console application to stress-test the driver's cancel and cleanup routines. + +This driver is written for an hypothetical data-acquisition device that requires polling at a regular interval. The device has some settling period between two successive reads. On a user request, the driver reads data and records the time. When the next read request comes in, the driver checks the interval to see if it's reading the device too soon. If so, it pends the IRP and sleeps for a while, and then tries again. On arrival, IRPs are queued in a cancel-safe queue and a semaphore is signaled. A polling thread that waits indefinitely on the semaphore wakes up to the signal and processes queued IRPs sequentially. + +The building and installation instructions given here apply to Windows 2000 and later versions of Windows. + +This sample driver is not a Plug and Play driver. This is a minimal driver meant to demonstrate a feature of the operating system. Neither this driver nor its sample programs are intended for use in a production environment. Instead, they are intended for educational purposes and as a skeleton driver. + +Look in the Startio directory for another version of the sample driver that shows how to use cancel-safe IRP queues to implement I/O queuing functionality similar to the [**IoStartPacket**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550370) and [**IoStartNextPacket**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff550358) routines. The same test application works with this driver as well. + +For more information, see [Cancel-Safe IRP Queues](http://msdn.microsoft.com/en-us/library/windows/hardware/ff540755). + + +Run the sample +-------------- + +To test this driver, run Testapp.exe, which is a simple Win32 multithreaded console application. The driver will automatically load and start. When you exit the application, the driver will stop and be removed. + +`Usage: testapp <NumberOfThreads>` + +**Note** The `NumberOfThreads` command-line parameter is limited to a maximum of 10 threads; the default value if no parameter is specified is 1. The main thread waits for user input. If you press Q, the application exits gracefully; otherwise, it exits the process abruptly and forces all the threads to be terminated and all pending I/O operations to be canceled. Other threads perform I/O asynchronously in a loop. After every overlapped read, the thread goes into an alertable sleep and wakes as soon as the completion routine runs, which occurs when the driver completes the read IRP. You should run multiple instances of the application to stress test the driver. + diff --git a/general/cancel/cancel.sln b/general/cancel/cancel.sln new file mode 100644 index 00000000..a9836742 --- /dev/null +++ b/general/cancel/cancel.sln @@ -0,0 +1,59 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{DBD7C2B7-C00F-4FFE-84D4-B05886013873}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{0B6A483D-D5F5-4F95-96E7-281FD7EA600F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Startio", "Startio", "{234DCAD4-F351-4964-9C3B-0B59C944B70D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "sys\cancel.vcxproj", "{3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "canclapp", "exe\canclapp.vcxproj", "{C8925B47-FB65-4E3E-89E4-2B45E3C10509}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cancel", "startio\cancel.vcxproj", "{1392C861-BA6F-4423-8C33-A8C771BAF473}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.ActiveCfg = Debug|Win32 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|Win32.Build.0 = Debug|Win32 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.ActiveCfg = Release|Win32 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|Win32.Build.0 = Release|Win32 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.ActiveCfg = Debug|x64 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Debug|x64.Build.0 = Debug|x64 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.ActiveCfg = Release|x64 + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}.Release|x64.Build.0 = Release|x64 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.ActiveCfg = Debug|Win32 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|Win32.Build.0 = Debug|Win32 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.ActiveCfg = Release|Win32 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|Win32.Build.0 = Release|Win32 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.ActiveCfg = Debug|x64 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Debug|x64.Build.0 = Debug|x64 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.ActiveCfg = Release|x64 + {C8925B47-FB65-4E3E-89E4-2B45E3C10509}.Release|x64.Build.0 = Release|x64 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.ActiveCfg = Debug|Win32 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|Win32.Build.0 = Debug|Win32 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.ActiveCfg = Release|Win32 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|Win32.Build.0 = Release|Win32 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.ActiveCfg = Debug|x64 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Debug|x64.Build.0 = Debug|x64 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.ActiveCfg = Release|x64 + {1392C861-BA6F-4423-8C33-A8C771BAF473}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3363DCA3-7873-4ECB-BA98-F243C2E8FDA0} = {DBD7C2B7-C00F-4FFE-84D4-B05886013873} + {C8925B47-FB65-4E3E-89E4-2B45E3C10509} = {0B6A483D-D5F5-4F95-96E7-281FD7EA600F} + {1392C861-BA6F-4423-8C33-A8C771BAF473} = {234DCAD4-F351-4964-9C3B-0B59C944B70D} + EndGlobalSection +EndGlobal diff --git a/general/cancel/exe/canclapp.vcxproj b/general/cancel/exe/canclapp.vcxproj new file mode 100644 index 00000000..63333b9c --- /dev/null +++ b/general/cancel/exe/canclapp.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{C8925B47-FB65-4E3E-89E4-2B45E3C10509}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{1EB28B67-703E-42CB-AEEF-4871909ACBE4}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>canclapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>canclapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>canclapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>canclapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x0400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x0400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x0400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary> + <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x0400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.c" /> + <ClCompile Include="testapp.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/cancel/exe/canclapp.vcxproj.Filters b/general/cancel/exe/canclapp.vcxproj.Filters new file mode 100644 index 00000000..fa02af34 --- /dev/null +++ b/general/cancel/exe/canclapp.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{8E80D4A1-56AB-4705-840F-3971E3C35CC4}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F05A42DC-3C1C-4B0B-BB8A-980D8BDD8C12}</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>{DB77EDC2-6072-41D9-B58F-42B9EECC5702}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="testapp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/cancel/exe/install.c b/general/cancel/exe/install.c new file mode 100644 index 00000000..f19ff558 --- /dev/null +++ b/general/cancel/exe/install.c @@ -0,0 +1,480 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + +--*/ + + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "testapp.h" + + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("CreateService failed! Error = %d \n", err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + printf("Invalid Driver or Service provided to ManageDriver() \n"); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + printf("Open SC Manager failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + printf("Unknown ManageDriver() function. \n"); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + if (schSCManager) { + + CloseServiceHandle(schSCManager); + } + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("DeleteService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("StartService failure! Error = %d \n", err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("ControlService failed! Error = %d \n", GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle (schService); + } + + return rCode; + +} // StopDriver + + + + diff --git a/general/cancel/exe/testapp.c b/general/cancel/exe/testapp.c new file mode 100644 index 00000000..f6c27fe9 --- /dev/null +++ b/general/cancel/exe/testapp.c @@ -0,0 +1,333 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + testapp.c + +Abstract: + +Environment: + + User mode Win32 console application + +--*/ + +// +// Annotation to indicate to prefast that this is nondriver user-mode code. +// + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#include <windows.h> +#include <winioctl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <strsafe.h> + +#include "testapp.h" + +// +// Globals +// + +HANDLE hDevice; +BOOLEAN ExitFlag = FALSE; +HANDLE hThreads[MAXTHREADS]; + +// +// function prototypes +// + +VOID CALLBACK CompletionRoutine( + DWORD errorcode, + DWORD bytesTransfered, + LPOVERLAPPED ov + ); + +DWORD +WINAPI Reader( + PVOID + ); + +BOOLEAN +SetupDriverName( + _Inout_updates_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ); + +// +// Main function +// + +VOID __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + ULONG i, Id; + ULONG NumberOfThreads = 1; + DWORD errNum = 0; + TCHAR driverLocation[MAX_PATH] = {'\0'}; + + + if (argc >= 2 && (argv[1][0] == '-' || isalpha((unsigned char)argv[1][0]))) + { + puts("Usage:testapp <NumberOfThreads>\n"); + return; + } + else if (argc >= 2 && ((NumberOfThreads = atoi(argv[1])) > MAXTHREADS)) + { + printf("Invalid option:Only a maximun of %d threads allowed.\n", + MAXTHREADS); + return; + + } + + // + // Try to connect to driver. If this fails, try to load the driver + // dynamically. + // + + if ((hDevice = CreateFile("\\\\.\\CancelSamp", + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL + )) == INVALID_HANDLE_VALUE) { + + errNum = GetLastError(); + + if (errNum != ERROR_FILE_NOT_FOUND) { + + printf("CreateFile failed! Error = %d\n", errNum); + + return ; + } + + // + // Setup full path to driver name. + // + + if (!SetupDriverName(driverLocation, sizeof(driverLocation))) { + + return ; + } + + + // + // Install driver. + // + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + printf("Unable to install driver. \n"); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return; + } + // + // Try to open the newly installed driver. + // + + hDevice = CreateFile( "\\\\.\\CancelSamp", + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL); + + if ( hDevice == INVALID_HANDLE_VALUE ){ + printf ( "Error: CreatFile Failed : %d\n", GetLastError()); + return; + } + } + + printf("Number of threads : %d\n", NumberOfThreads); + + + printf("Enter 'q' to exit gracefully:"); + + for(i=0; i < NumberOfThreads; i++) + { + hThreads[i] = CreateThread( NULL, // security attributes + 0, // initial stack size + Reader, // Main() function + NULL, // arg to Reader thread + 0, // creation flags + (LPDWORD)&Id); // returned thread id + + if ( NULL == hThreads[i] ) { + printf( " Error CreateThread[%d] Failed: %d\n", i, GetLastError()); + ExitProcess ( 1 ); + } + + } + + + if (getchar() == 'q') + { + ExitFlag = TRUE; + + WaitForMultipleObjects( NumberOfThreads, hThreads, TRUE, INFINITE); + + for(i=0; i < NumberOfThreads; i++) + CloseHandle(hThreads[i]); + + } + + CloseHandle(hDevice); + + // + // Unload the driver. Ignore any errors. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + ExitProcess(1); + +} + + +DWORD WINAPI Reader(PVOID dummy ) +{ + ULONG data; + OVERLAPPED ov; + + UNREFERENCED_PARAMETER(dummy); + + while(!ExitFlag) + { + ZeroMemory( &ov, sizeof(ov) ); + ov.Offset = 0; + ov.OffsetHigh = 0; + + if (!ReadFileEx(hDevice, (PVOID)&data, sizeof(ULONG), &ov, CompletionRoutine)) + { + printf ( "Error: Read Failed: %d\n", GetLastError()); + ExitProcess ( 1 ); + } + SleepEx(INFINITE, TRUE); + } + + printf("Exiting thread %d \n", GetCurrentThreadId()); + ExitThread(0); +} + + +VOID CALLBACK CompletionRoutine( + DWORD errorcode, + DWORD bytesTransfered, + LPOVERLAPPED ov + ) +{ + + UNREFERENCED_PARAMETER(errorcode); + UNREFERENCED_PARAMETER(ov); + + fprintf(stdout, "Thread %d read: %d bytes\n", + GetCurrentThreadId(), bytesTransfered); + return; +} + + +BOOLEAN +SetupDriverName( + _Inout_updates_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ) +{ + HANDLE fileHandle; + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(BufferLength, + DriverLocation + ); + + if (driverLocLen == 0) { + + printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Setup path name to driver file. + // + if (FAILED( StringCbCat(DriverLocation, BufferLength, "\\"DRIVER_NAME".sys") )) { + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + printf("%s.sys is not loaded.\n", DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName + + + diff --git a/general/cancel/exe/testapp.h b/general/cancel/exe/testapp.h new file mode 100644 index 00000000..fa63d0b9 --- /dev/null +++ b/general/cancel/exe/testapp.h @@ -0,0 +1,14 @@ + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 + +#define MAXTHREADS 10 +#define DRIVER_NAME "cancel" + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ); + diff --git a/general/cancel/startio/cancel.c b/general/cancel/startio/cancel.c new file mode 100644 index 00000000..808a8941 --- /dev/null +++ b/general/cancel/startio/cancel.c @@ -0,0 +1,965 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + cancel.c + +Abstract: Demonstrates the use of new Cancel-Safe queue + APIs to perform queuing of IRPs without worrying about + any synchronization issues between cancel lock in the I/O + manager and the driver's queue lock. + + This driver is written for an hypothetical data acquisition + device that requires polling at a regular interval. + The device has some settling period between two reads. + Upon user request the driver reads data and records the time. + When the next read request comes in, it checks the interval + to see if it's reading the device too soon. If so, it pends + the IRP and sleeps for while and tries again. + +Environment: + + Kernel mode + +--*/ + +#include "cancel.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(PAGE, CsampCreateClose) +#pragma alloc_text(PAGE, CsampUnload) +#pragma alloc_text(PAGE, CsampRead) +#endif // ALLOC_PRAGMA + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + registryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING unicodeDeviceName; + UNICODE_STRING unicodeDosDeviceName; + PDEVICE_OBJECT deviceObject; + PDEVICE_EXTENSION devExtension; + UNICODE_STRING sddlString; + + UNREFERENCED_PARAMETER (RegistryPath); + + CSAMP_KDPRINT(("DriverEntry Enter \n")); + + + (void) RtlInitUnicodeString(&unicodeDeviceName, CSAMP_DEVICE_NAME_U); + + // + // We will create a secure deviceobject so that only processes running + // in admin and local system account can access the device. Refer + // "Security Descriptor String Format" section in the platform + // SDK documentation to understand the format of the sddl string. + // We need to do because this is a legacy driver and there is no INF + // involved in installing the driver. For PNP drivers, security descriptor + // is typically specified for the FDO in the INF file. + // + + (void) RtlInitUnicodeString(&sddlString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)"); + + status = IoCreateDeviceSecure( + DriverObject, + sizeof(DEVICE_EXTENSION), + &unicodeDeviceName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + (BOOLEAN) FALSE, + &sddlString, + (LPCGUID)&GUID_DEVCLASS_CANCEL_SAMPLE, + &deviceObject + ); + + + if (!NT_SUCCESS(status)) + { + return status; + } + + // + // Allocate and initialize a Unicode String containing the Win32 name + // for our device. + // + + (void)RtlInitUnicodeString(&unicodeDosDeviceName, CSAMP_DOS_DEVICE_NAME_U); + + + status = IoCreateSymbolicLink( + (PUNICODE_STRING) &unicodeDosDeviceName, + (PUNICODE_STRING) &unicodeDeviceName + ); + + if (!NT_SUCCESS(status)) + { + IoDeleteDevice(deviceObject); + return status; + } + + devExtension = deviceObject->DeviceExtension; + + DriverObject->MajorFunction[IRP_MJ_CREATE]= + DriverObject->MajorFunction[IRP_MJ_CLOSE] = CsampCreateClose; + DriverObject->MajorFunction[IRP_MJ_READ] = CsampRead; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CsampCleanup; + + DriverObject->DriverUnload = CsampUnload; + + // + // Set the flag signifying that we will do buffered I/O. This causes NT + // to allocate a buffer on a ReadFile operation which will then be copied + // back to the calling application by the I/O subsystem + // + + deviceObject->Flags |= DO_BUFFERED_IO; + + // + // Initialize the spinlock. This is used to serailize + // access to the device. + // + + KeInitializeSpinLock(&devExtension->DeviceLock); + + // + // This is used to serailize access to the queue. + // + + KeInitializeSpinLock(&devExtension->QueueLock); + + + // + //Initialize the Dpc object + // + + KeInitializeDpc(&devExtension->PollingDpc, + CsampPollingTimerDpc, + (PVOID)deviceObject); + + // + // Initialize the timer object + // + + KeInitializeTimer(&devExtension->PollingTimer); + + // + // Initialize the pending Irp devicequeue + // + + InitializeListHead(&devExtension->PendingIrpQueue); + + // + // 10 is multiplied because system time is specified in 100ns units + // + + devExtension->PollingInterval.QuadPart = Int32x32To64( + CSAMP_RETRY_INTERVAL, -10); + // + // Note down system time + // + + KeQuerySystemTime (&devExtension->LastPollTime); + + IoCsqInitializeEx(&devExtension->CancelSafeQueue, + CsampInsertIrp, + CsampRemoveIrp, + CsampPeekNextIrp, + CsampAcquireLock, + CsampReleaseLock, + CsampCompleteCanceledIrp); + + CSAMP_KDPRINT(("DriverEntry Exit = %x\n", status)); + + ASSERT(NT_SUCCESS(status)); + + return status; +} + + +_Use_decl_annotations_ +NTSTATUS +CsampCreateClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + Process the Create and close IRPs sent to this device. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT Status code + +--*/ +{ + PIO_STACK_LOCATION irpStack; + NTSTATUS status = STATUS_SUCCESS; + PFILE_CONTEXT fileContext; + + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE (); + + CSAMP_KDPRINT(("CsampCreateClose Enter\n")); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + switch(irpStack->MajorFunction) + { + case IRP_MJ_CREATE: + + // + // The dispatch routine for IRP_MJ_CREATE is called when a + // file object associated with the device is created. + // This is typically because of a call to CreateFile() in + // a user-mode program or because a higher-level driver is + // layering itself over a lower-level driver. A driver is + // required to supply a dispatch routine for IRP_MJ_CREATE. + // + + fileContext = ExAllocatePoolWithQuotaTag(NonPagedPool, + sizeof(FILE_CONTEXT), + TAG); + + if (NULL == fileContext) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + IoInitializeRemoveLock(&fileContext->FileRundownLock, TAG, 0, 0); + + // + // Make sure nobody is using the FsContext scratch area. + // + ASSERT(irpStack->FileObject->FsContext == NULL); + + // + // Store the context in the FileObject's scratch area. + // + irpStack->FileObject->FsContext = (PVOID) fileContext; + + CSAMP_KDPRINT(("IRP_MJ_CREATE\n")); + break; + + case IRP_MJ_CLOSE: + + // + // The IRP_MJ_CLOSE dispatch routine is called when a file object + // opened on the driver is being removed from the system; that is, + // all file object handles have been closed and the reference count + // of the file object is down to 0. Certain types of drivers do not + // need to handle IRP_MJ_CLOSE, mainly drivers of devices that must + // be available for the system to continue running. In general, this + // is the place that a driver should "undo" whatever has been done + // in the routine for IRP_MJ_CREATE. + // + + fileContext = irpStack->FileObject->FsContext; + + ExFreePoolWithTag(fileContext, TAG); + + CSAMP_KDPRINT(("IRP_MJ_CLOSE\n")); + break; + + default: + CSAMP_KDPRINT((" Invalid CreateClose Parameter\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Save Status for return and complete Irp + // + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + CSAMP_KDPRINT((" CsampCreateClose Exit = %x\n", status)); + + return status; +} + +_Use_decl_annotations_ +NTSTATUS +CsampRead( + PDEVICE_OBJECT DeviceObject, + PIRP Irp +) + /*++ + Routine Description: + + Read disptach routine + + Arguments: + + DeviceObject - pointer to a device object. + Irp - pointer to current Irp + + Return Value: + + NT status code. +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION devExtension; + PIO_STACK_LOCATION irpStack; + LARGE_INTEGER currentTime; + PVOID readBuffer; + PFILE_CONTEXT fileContext; + BOOLEAN inCriticalRegion; + + PAGED_CODE(); + + CSAMP_KDPRINT(("--->CsampReadReport irp 0x%p\n", Irp)); + + // + // Get a pointer to the device extension. + // + devExtension = DeviceObject->DeviceExtension; + inCriticalRegion = FALSE; + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + if (!NT_SUCCESS(status)) { + // + // Lock is in a removed state. That means we have already received + // cleaned up request for this handle. + // + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + // + // First make sure there is enough room. + // + if (irpStack->Parameters.Read.Length < sizeof(INPUT_DATA)) + { + Irp->IoStatus.Status = status = STATUS_BUFFER_TOO_SMALL; + Irp->IoStatus.Information = 0; + IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); + IoCompleteRequest (Irp, IO_NO_INCREMENT); + return status; + } + + // + // Simple little random polling time generator. + // FOR TESTING: + // Initialize the data to mod 2 of some random number. + // With this value you can control the number of times the + // Irp will be queued before completion. Check + // CsampPollDevice routine to know how this works. + // + + KeQuerySystemTime(¤tTime); + + readBuffer = Irp->AssociatedIrp.SystemBuffer; + + *((PULONG)readBuffer) = ((currentTime.LowPart/13)%2); + + // + // If the thread is suspended right after the queue is marked busy due to + // insert, it will prevent I/Os from other threads being processed leading + // to denial of service (DOS) attack. So disable thread suspension by + // entering critical region. + // + ASSERT(KeGetCurrentIrql() <= APC_LEVEL); + KeEnterCriticalRegion(); + inCriticalRegion = TRUE; + + // + // Try inserting the IRP in the queue. If the device is busy, + // the IRP will get queued and the following function will + // return SUCCESS. If the device is not busy, it will set the + // IRP to DeviceExtension->CurrentIrp and return UNSUCCESSFUL. + // + if (!NT_SUCCESS(IoCsqInsertIrpEx(&devExtension->CancelSafeQueue, + Irp, NULL, NULL))) { + IoMarkIrpPending(Irp); + + CsampInitiateIo(DeviceObject); + } else { + // + // Do not touch the IRP once it has been queued because another thread + // could remove the IRP and complete it before this one gets to run. + // + // DO_NOTHING(); + } + if (inCriticalRegion == TRUE) { + KeLeaveCriticalRegion(); + } + // + // We don't hold the lock for IRP that's pending in the list because this + // lock is meant to rundown currently dispatching threads when the cleanup + // is handled. + // + IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); + + CSAMP_KDPRINT(("<---CsampReadReport\n")); + + return STATUS_PENDING; +} + +VOID +CsampInitiateIo( + _In_ PDEVICE_OBJECT DeviceObject +) + /*++ + Routine Description: + + Performs the actual I/O operations. + + Arguments: + + DeviceObject - pointer to a device object. + + Return Value: + + NT status code. + + +--*/ + +{ + NTSTATUS status; + PDEVICE_EXTENSION devExtension = DeviceObject->DeviceExtension; + PIRP irp = NULL; + + CSAMP_KDPRINT(("--> CsampInitiateIo\n")); + + irp = devExtension->CurrentIrp; + + for(;;) { + + ASSERT(irp != NULL && irp == devExtension->CurrentIrp); + + status = CsampPollDevice(DeviceObject, irp); + if (status == STATUS_PENDING) + { + // + // Oops, polling too soon. Start the timer to retry the operation. + // + KeSetTimer(&devExtension->PollingTimer, + devExtension->PollingInterval, + &devExtension->PollingDpc); + break; + } + else + { + // + // Read device is successful. Now complete the IRP and service + // the next one from the queue. + // + irp->IoStatus.Status = status; + CSAMP_KDPRINT(("completing irp :0x%p\n", irp)); + IoCompleteRequest (irp, IO_NO_INCREMENT); + + irp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, NULL); + + if (irp == NULL) { + break; + } + } + + } + + CSAMP_KDPRINT(("<---CsampInitiateIo\n")); + + return; +} + +_Use_decl_annotations_ +VOID +CsampPollingTimerDpc( + PKDPC Dpc, + PVOID Context, + PVOID SystemArgument1, + PVOID SystemArgument2 +) + /*++ + Routine Description: + + CustomTimerDpc routine to process Irp that are + waiting in the PendingIrpQueue + + Arguments: + + DeviceObject - pointer to DPC object + Context - pointer to device object + SystemArgument1 - undefined + SystemArgument2 - undefined + + Return Value: +--*/ +{ + PDEVICE_OBJECT deviceObject; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + CSAMP_KDPRINT(("---> CsampPollingTimerDpc\n")); + + _Analysis_assume_(Context != NULL); + + deviceObject = (PDEVICE_OBJECT)Context; + + CsampInitiateIo(deviceObject); + + CSAMP_KDPRINT(("<--- CsampPollingTimerDpc\n")); +} + +_Use_decl_annotations_ +NTSTATUS +CsampCleanup( + PDEVICE_OBJECT DeviceObject, + PIRP Irp +) +/*++ + +Routine Description: + This dispatch routine is called when the last handle (in + the whole system) to a file object is closed. In other words, the open + handle count for the file object goes to 0. A driver that holds pending + IRPs internally must implement a routine for IRP_MJ_CLEANUP. When the + routine is called, the driver should cancel all the pending IRPs that + belong to the file object identified by the IRP_MJ_CLEANUP call. In other + words, it should cancel all the IRPs that have the same file-object pointer + as the one supplied in the current I/O stack location of the IRP for the + IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should + not be canceled. Also, if an outstanding IRP is completed immediately, the + driver does not have to cancel it. + +Arguments: + + DeviceObject -- pointer to the device object + Irp -- pointer to the requesing Irp + +Return Value: + + STATUS_SUCCESS -- if the poll succeeded, +--*/ +{ + + PDEVICE_EXTENSION devExtension; + PIRP pendingIrp; + PIO_STACK_LOCATION irpStack; + PFILE_CONTEXT fileContext; + NTSTATUS status; + + CSAMP_KDPRINT(("--->CsampCleanupIrp\n")); + + devExtension = DeviceObject->DeviceExtension; + + irpStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + // + // This acquire cannot fail because you cannot get more than one + // cleanup for the same handle. + // + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + ASSERT(NT_SUCCESS(status)); + + // + // Wait for all the threads that are currently dispatching to exit and + // prevent any threads dispatching I/O on the same handle beyond this point. + // + IoReleaseRemoveLockAndWait(&fileContext->FileRundownLock, Irp); + + pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, + irpStack->FileObject); + while(pendingIrp) + { + // + // Cancel the IRP + // + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + + pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, + irpStack->FileObject); + } + + // + // Finally complete the cleanup IRP + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + CSAMP_KDPRINT(("<---CsampCleanupIrp\n")); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +CsampPollDevice( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + Pools for data + +Arguments: + + DeviceObject -- pointer to the device object + Irp -- pointer to the requesing Irp + + +Return Value: + + STATUS_SUCCESS -- if the poll succeeded, + STATUS_TIMEOUT -- if the poll failed (timeout), + or the checksum was incorrect + STATUS_PENDING -- if polled too soon + +--*/ +{ + PINPUT_DATA pInput; + + UNREFERENCED_PARAMETER(DeviceObject); + + pInput = (PINPUT_DATA)Irp->AssociatedIrp.SystemBuffer; + +#ifdef REAL + + RtlZeroMemory(pInput, sizeof(INPUT_DATA)); + + // + // If currenttime is less than the lasttime polled plus + // minimum time required for the device to settle + // then don't poll and return STATUS_PENDING + // + + KeQuerySystemTime(¤tTime); + if (currentTime->QuadPart < (TimeBetweenPolls + + devExtension->LastPollTime.QuadPart)) + { + return STATUS_PENDING; + } + + // + // Read/Write to the port here. + // Fill the INPUT structure + // + + // + // Note down the current time as the last polled time + // + + KeQuerySystemTime(&devExtension->LastPollTime); + + + return STATUS_SUCCESS; +#else + + // + // With this conditional statement + // you can control the number of times the + // irp should be queued before completing. + // + + if (pInput->Data-- <= 0) + { + Irp->IoStatus.Information = sizeof(INPUT_DATA); + return STATUS_SUCCESS; + } + return STATUS_PENDING; + + #endif + +} + +VOID +CsampUnload( + _In_ PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + Free all the allocated resources, etc. + +Arguments: + + DriverObject - pointer to a driver object. + +Return Value: + + VOID +--*/ +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + PDEVICE_EXTENSION devExtension = deviceObject->DeviceExtension; + + PAGED_CODE(); + + CSAMP_KDPRINT(("--->CsampUnload\n")); + + // + // The OS (XP and beyond) forces any DPCs that are already + // running to run to completion, even after the driver unload , + // routine returns, but before unmapping the driver image from + // memory. + // This driver makes an assumption that I/O request are going to + // come only from usermode app and as long as there are active + // IRPs in the driver, the driver will not get unloaded. + // NOTE: If a driver can get I/O request directly from another + // driver without having an explicit handle, you should wait on an + // event signalled by the DPC to make sure that DPC doesn't access + // the resources that you are going to free here. + // + KeCancelTimer(&devExtension->PollingTimer); + + + // + // Create counted string version of our Win32 device name. + // + + RtlInitUnicodeString(&uniWin32NameString, CSAMP_DOS_DEVICE_NAME_U); + + // + // Delete the link from our device name to a name in the Win32 namespace. + // + + IoDeleteSymbolicLink(&uniWin32NameString); + + IoDeleteDevice(deviceObject); + + CSAMP_KDPRINT(("<---CsampUnload\n")); + return; +} + +NTSTATUS CsampInsertIrp ( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID InsertContext + ) +{ + PDEVICE_EXTENSION devExtension; + + UNREFERENCED_PARAMETER(InsertContext); + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + // + // Suppressing because the address below csq is valid since it's + // part of DEVICE_EXTENSION structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->CurrentIrp") + if (!devExtension->CurrentIrp) { + devExtension->CurrentIrp = Irp; + return STATUS_UNSUCCESSFUL; + } + + + InsertTailList(&devExtension->PendingIrpQueue, + &Irp->Tail.Overlay.ListEntry); + return STATUS_SUCCESS; +} + +VOID CsampRemoveIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(Csq); + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + + +PIRP CsampPeekNextIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID PeekContext + ) +{ + PDEVICE_EXTENSION devExtension; + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + PIO_STACK_LOCATION irpStack; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + + listHead = &devExtension->PendingIrpQueue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if (Irp == NULL) { + nextEntry = listHead->Flink; + } else { + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + + + while(nextEntry != listHead) { + + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + irpStack = IoGetCurrentIrpStackLocation(nextIrp); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + + if (PeekContext) { + if (irpStack->FileObject == (PFILE_OBJECT) PeekContext) { + break; + } + } else { + break; + } + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + // + // Check if this is from start packet. + // + + if (PeekContext == NULL) { + devExtension->CurrentIrp = nextIrp; + } + + return nextIrp; +} + +// +// CsampAcquireLock modifies the execution level of the current processor. +// +// KeAcquireSpinLock raises the execution level to Dispatch Level and stores +// the current execution level in the Irql parameter to be restored at a later +// time. KeAcqurieSpinLock also requires us to be running at no higher than +// Dispatch level when it is called. +// +// The annotations reflect these changes and requirments. +// + +_IRQL_raises_(DISPATCH_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID CsampAcquireLock( + _In_ PIO_CSQ Csq, + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql + ) +{ + PDEVICE_EXTENSION devExtension; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + // + // Suppressing because the address below csq is valid since it's + // part of DEVICE_EXTENSION structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'") + KeAcquireSpinLock(&devExtension->QueueLock, Irql); +} + +// +// CsampReleaseLock modifies the execution level of the current processor. +// +// KeReleaseSpinLock assumes we already hold the spin lock and are therefore +// running at Dispatch level. It will use the Irql parameter saved in a +// previous call to KeAcquireSpinLock to return the thread back to it's original +// execution level. +// +// The annotations reflect these changes and requirments. +// + +_IRQL_requires_(DISPATCH_LEVEL) +_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID CsampReleaseLock( + _In_ PIO_CSQ Csq, + _In_ _IRQL_restores_ KIRQL Irql + ) +{ + PDEVICE_EXTENSION devExtension; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + // + // Suppressing because the address below csq is valid since it's + // part of DEVICE_EXTENSION structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'") + KeReleaseSpinLock(&devExtension->QueueLock, Irql); +} + +VOID CsampCompleteCanceledIrp( + _In_ PIO_CSQ pCsq, + _In_ PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(pCsq); + + CSAMP_KDPRINT(("Cancelled IRP: 0x%p\n", Irp)); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + diff --git a/general/cancel/startio/cancel.h b/general/cancel/startio/cancel.h new file mode 100644 index 00000000..8f04ab75 --- /dev/null +++ b/general/cancel/startio/cancel.h @@ -0,0 +1,166 @@ +#ifndef __CANCEL_H +#define __CANCEL_H + +#include <initguid.h> + +// +// Since this driver is a legacy driver and gets installed as a service +// (without an INF file), we will define a class guid for use in +// IoCreateDeviceSecure function. This would allow the system to store +// Security, DeviceType, Characteristics and Exclusivity information of the +// deviceobject in the registery under +// HKLM\SYSTEM\CurrentControlSet\Control\Class\ClassGUID\Properties. +// This information can be overrided by an Administrators giving them the ability +// to control access to the device beyond what is initially allowed +// by the driver developer. +// + + +// {5D006E1A-2631-466c-B8A0-32FD498E4424} - generated using guidgen.exe +DEFINE_GUID (GUID_DEVCLASS_CANCEL_SAMPLE, + 0x5d006e1a, 0x2631, 0x466c, 0xb8, 0xa0, 0x32, 0xfd, 0x49, 0x8e, 0x44, 0x24); + +// +// GUID definition are required to be outside of header inclusion pragma to +// avoid error during precompiled headers. +// +#include <ntddk.h> +#include <wdmsec.h> // for IoCreateDeviceSecure +#include <dontuse.h> + +// Debugging macros + +#if DBG +#define CSAMP_KDPRINT(_x_) \ + DbgPrint("CANCEL.SYS: ");\ + DbgPrint _x_; + +#define TRAP() DbgBreakPoint() + +#else + +#define CSAMP_KDPRINT(_x_) + +#define TRAP() + +#endif + +#define CSAMP_DEVICE_NAME_U L"\\Device\\CANCELSAMP" +#define CSAMP_DOS_DEVICE_NAME_U L"\\DosDevices\\CancelSamp" +#define CSAMP_RETRY_INTERVAL 500*1000 //500 ms +#define TAG (ULONG)'MASC' + +typedef struct _INPUT_DATA{ + + ULONG Data; //device data is stored here + +} INPUT_DATA, *PINPUT_DATA; + +typedef struct _DEVICE_EXTENSION{ + + // Irps waiting to be processed are queued here + LIST_ENTRY PendingIrpQueue; + + // SpinLock to protect access to the queue + KSPIN_LOCK QueueLock; + + // SpinLock to provide exclusive access to the port + KSPIN_LOCK DeviceLock; + + // Pointer to current device IRP. Exclusive access to this + // field is also provided by the QueueLock. + PIRP CurrentIrp; + + // Customtimer DPC object + KDPC PollingDpc; + + // Time at which the device was last polled + LARGE_INTEGER LastPollTime; + + // Polling timer object + KTIMER PollingTimer; + + // Polling interval (retry interval) + LARGE_INTEGER PollingInterval; + + IO_CSQ CancelSafeQueue; + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +typedef struct _FILE_CONTEXT{ + // + // Lock to rundown threads that are dispatching I/Os on a file handle + // while the cleanup for that handle is in progress. + // + IO_REMOVE_LOCK FileRundownLock; +} FILE_CONTEXT, *PFILE_CONTEXT; + +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH CsampCreateClose; + +_Dispatch_type_(IRP_MJ_CLEANUP) +DRIVER_DISPATCH CsampCleanup; + +_Dispatch_type_(IRP_MJ_READ) +DRIVER_DISPATCH CsampRead; + +DRIVER_DISPATCH CsampPollDevice; + +DRIVER_UNLOAD CsampUnload; + +KDEFERRED_ROUTINE CsampPollingTimerDpc; + +VOID +CsampInitiateIo( + _In_ PDEVICE_OBJECT DeviceObject +); + +NTSTATUS +CsampInsertIrp ( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID InsertContext + ); + +VOID +CsampRemoveIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ); + +PIRP +CsampPeekNextIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID PeekContext + ); + +_IRQL_raises_(DISPATCH_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID +CsampAcquireLock( + _In_ PIO_CSQ Csq, + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql + ); + +_IRQL_requires_(DISPATCH_LEVEL) +_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID +CsampReleaseLock( + _In_ PIO_CSQ Csq, + _In_ _IRQL_restores_ KIRQL Irql + ); + +VOID +CsampCompleteCanceledIrp( + _In_ PIO_CSQ pCsq, + _In_ PIRP Irp + ); + +#endif + + diff --git a/general/cancel/startio/cancel.rc b/general/cancel/startio/cancel.rc new file mode 100644 index 00000000..2bd08155 --- /dev/null +++ b/general/cancel/startio/cancel.rc @@ -0,0 +1,10 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Sample Cancel Driver" +#define VER_INTERNALNAME_STR "cancel.sys" + +#include "common.ver" diff --git a/general/cancel/startio/cancel.vcxproj b/general/cancel/startio/cancel.vcxproj new file mode 100644 index 00000000..8cdbf0ce --- /dev/null +++ b/general/cancel/startio/cancel.vcxproj @@ -0,0 +1,152 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{1392C861-BA6F-4423-8C33-A8C771BAF473}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{2FA77D27-524D-4C63-81CD-62E054676D96}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="cancel.c" /> + <ResourceCompile Include="cancel.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/cancel/startio/cancel.vcxproj.Filters b/general/cancel/startio/cancel.vcxproj.Filters new file mode 100644 index 00000000..015f96b7 --- /dev/null +++ b/general/cancel/startio/cancel.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{DBC52094-6726-43E4-8D3A-1E52EB8592CA}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{12A618AD-2EC7-4EF1-B1F8-F14652DE50D0}</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>{01F4B40C-7AC7-4573-A236-526D211FE249}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{C63E5134-5856-4331-9141-C85F75D697B9}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="cancel.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="cancel.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/cancel/sys/cancel.c b/general/cancel/sys/cancel.c new file mode 100644 index 00000000..58bf72e9 --- /dev/null +++ b/general/cancel/sys/cancel.c @@ -0,0 +1,945 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + cancel.c + +Abstract: Demonstrates the use of new Cancel-Safe queue + APIs to perform queuing of IRPs without worrying about + any synchronization issues between cancel lock in the I/O + manager and the driver's queue lock. + + This driver is written for an hypothetical data acquisition + device that requires polling at a regular interval. + The device has some settling period between two reads. + Upon user request the driver reads data and records the time. + When the next read request comes in, it checks the interval + to see if it's reading the device too soon. If so, it pends + the IRP and sleeps for while and tries again. + + Upon arrival, IRPs are queued in a cancel-safe queue and a + semaphore is signaled. A polling thread indefinitely waits on the + semaphore to process queued IRPs sequentially. + + This sample is adapted from the original cancel + sample (KB Q188276) available in MSDN. + +Environment: + + Kernel mode + +--*/ + +#include "cancel.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, DriverEntry ) +#pragma alloc_text( PAGE, CsampCreateClose) +#pragma alloc_text( PAGE, CsampUnload) +#pragma alloc_text( PAGE, CsampRead) +#endif // ALLOC_PRAGMA + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + registryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING unicodeDeviceName; + UNICODE_STRING unicodeDosDeviceName; + PDEVICE_OBJECT deviceObject; + PDEVICE_EXTENSION devExtension; + HANDLE threadHandle; + UNICODE_STRING sddlString; + + UNREFERENCED_PARAMETER (RegistryPath); + + CSAMP_KDPRINT(("DriverEntry Enter \n")); + + + (void) RtlInitUnicodeString(&unicodeDeviceName, CSAMP_DEVICE_NAME_U); + + (void) RtlInitUnicodeString( &sddlString, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)"); + + // + // We will create a secure deviceobject so that only processes running + // in admin and local system account can access the device. Refer + // "Security Descriptor String Format" section in the platform + // SDK documentation to understand the format of the sddl string. + // We need to do because this is a legacy driver and there is no INF + // involved in installing the driver. For PNP drivers, security descriptor + // is typically specified for the FDO in the INF file. + // + + status = IoCreateDeviceSecure( + DriverObject, + sizeof(DEVICE_EXTENSION), + &unicodeDeviceName, + FILE_DEVICE_UNKNOWN, + FILE_DEVICE_SECURE_OPEN, + (BOOLEAN) FALSE, + &sddlString, + (LPCGUID)&GUID_DEVCLASS_CANCEL_SAMPLE, + &deviceObject + ); + if (!NT_SUCCESS(status)) + { + return status; + } + + DbgPrint("DeviceObject %p\n", deviceObject); + + // + // Allocate and initialize a Unicode String containing the Win32 name + // for our device. + // + + (void)RtlInitUnicodeString( &unicodeDosDeviceName, CSAMP_DOS_DEVICE_NAME_U ); + + + status = IoCreateSymbolicLink( + (PUNICODE_STRING) &unicodeDosDeviceName, + (PUNICODE_STRING) &unicodeDeviceName + ); + + if (!NT_SUCCESS(status)) + { + IoDeleteDevice(deviceObject); + return status; + } + + devExtension = deviceObject->DeviceExtension; + + DriverObject->MajorFunction[IRP_MJ_CREATE]= + DriverObject->MajorFunction[IRP_MJ_CLOSE] = CsampCreateClose; + DriverObject->MajorFunction[IRP_MJ_READ] = CsampRead; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = CsampCleanup; + + DriverObject->DriverUnload = CsampUnload; + + // + // Set the flag signifying that we will do buffered I/O. This causes NT + // to allocate a buffer on a ReadFile operation which will then be copied + // back to the calling application by the I/O subsystem + // + + deviceObject->Flags |= DO_BUFFERED_IO; + + // + // This is used to serailize access to the queue. + // + + KeInitializeSpinLock(&devExtension->QueueLock); + + KeInitializeSemaphore(&devExtension->IrpQueueSemaphore, 0, MAXLONG ); + + // + // Initialize the pending Irp devicequeue + // + + InitializeListHead( &devExtension->PendingIrpQueue ); + + // + // Initialize the cancel safe queue + // + IoCsqInitialize( &devExtension->CancelSafeQueue, + CsampInsertIrp, + CsampRemoveIrp, + CsampPeekNextIrp, + CsampAcquireLock, + CsampReleaseLock, + CsampCompleteCanceledIrp ); + // + // 10 is multiplied because system time is specified in 100ns units + // + + devExtension->PollingInterval.QuadPart = Int32x32To64( + CSAMP_RETRY_INTERVAL, -10); + // + // Note down system time + // + + KeQuerySystemTime (&devExtension->LastPollTime); + + // + // Start the polling thread. + // + + devExtension->ThreadShouldStop = FALSE; + + status = PsCreateSystemThread(&threadHandle, + (ACCESS_MASK)0, + NULL, + (HANDLE) 0, + NULL, + CsampPollingThread, + deviceObject ); + + if ( !NT_SUCCESS( status )) + { + IoDeleteSymbolicLink( &unicodeDosDeviceName ); + IoDeleteDevice( deviceObject ); + return status; + } + + // + // Convert the Thread object handle into a pointer to the Thread object + // itself. Then close the handle. + // + + ObReferenceObjectByHandle(threadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &devExtension->ThreadObject, + NULL ); + + ZwClose(threadHandle); + + CSAMP_KDPRINT(("DriverEntry Exit = %x\n", status)); + + ASSERT(NT_SUCCESS(status)); + + return status; +} + + +_Use_decl_annotations_ +NTSTATUS +CsampCreateClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + Process the Create and close IRPs sent to this device. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT Status code + +--*/ +{ + PIO_STACK_LOCATION irpStack; + NTSTATUS status = STATUS_SUCCESS; + PFILE_CONTEXT fileContext; + + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE (); + + CSAMP_KDPRINT(("CsampCreateClose Enter\n")); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + switch(irpStack->MajorFunction) + { + case IRP_MJ_CREATE: + + // + // The dispatch routine for IRP_MJ_CREATE is called when a + // file object associated with the device is created. + // This is typically because of a call to CreateFile() in + // a user-mode program or because a another driver is + // layering itself over a this driver. A driver is + // required to supply a dispatch routine for IRP_MJ_CREATE. + // + fileContext = ExAllocatePoolWithQuotaTag(NonPagedPool, + sizeof(FILE_CONTEXT), + TAG); + + if (NULL == fileContext) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + IoInitializeRemoveLock(&fileContext->FileRundownLock, TAG, 0, 0); + + // + // Make sure nobody is using the FsContext scratch area. + // + ASSERT(irpStack->FileObject->FsContext == NULL); + + // + // Store the context in the FileObject's scratch area. + // + irpStack->FileObject->FsContext = (PVOID) fileContext; + + CSAMP_KDPRINT(("IRP_MJ_CREATE\n")); + break; + + case IRP_MJ_CLOSE: + // + // The IRP_MJ_CLOSE dispatch routine is called when a file object + // opened on the driver is being removed from the system; that is, + // all file object handles have been closed and the reference count + // of the file object is down to 0. + // + fileContext = irpStack->FileObject->FsContext; + + ExFreePoolWithTag(fileContext, TAG); + + CSAMP_KDPRINT(("IRP_MJ_CLOSE\n")); + break; + + default: + CSAMP_KDPRINT((" Invalid CreateClose Parameter\n")); + status = STATUS_INVALID_PARAMETER; + break; + } + + // + // Save Status for return and complete Irp + // + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + CSAMP_KDPRINT((" CsampCreateClose Exit = %x\n", status)); + + return status; +} + + +_Use_decl_annotations_ +NTSTATUS +CsampRead( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + /*++ + Routine Description: + + Read disptach routine + + Arguments: + + DeviceObject - pointer to a device object. + Irp - pointer to current Irp + + Return Value: + + NT status code. + +--*/ +{ + NTSTATUS status; + PDEVICE_EXTENSION devExtension; + PIO_STACK_LOCATION irpStack; + LARGE_INTEGER currentTime; + PFILE_CONTEXT fileContext; + PVOID readBuffer; + BOOLEAN inCriticalRegion; + + PAGED_CODE(); + + CSAMP_KDPRINT(("CsampRead Enter:0x%p\n", Irp)); + + devExtension = DeviceObject->DeviceExtension; + inCriticalRegion = FALSE; + + irpStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + if (!NT_SUCCESS(status)) { + // + // Lock is in a removed state. That means we have already received + // cleaned up request for this handle. + // + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + // + // First make sure there is enough room. + // + if (irpStack->Parameters.Read.Length < sizeof(INPUT_DATA)) + { + Irp->IoStatus.Status = status = STATUS_BUFFER_TOO_SMALL; + Irp->IoStatus.Information = 0; + IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); + IoCompleteRequest (Irp, IO_NO_INCREMENT); + return status; + } + + // + // FOR TESTING: + // Initialize the data to mod 2 of some random number. + // With this value you can control the number of times the + // Irp will be queued before completion. Check + // CsampPollDevice routine to know how this works. + // + + KeQuerySystemTime(¤tTime); + + readBuffer = Irp->AssociatedIrp.SystemBuffer; + + *((PULONG)readBuffer) = ((currentTime.LowPart/13)%2); + + // + // To avoid the thread from being suspended after it has queued the IRP and + // before it signalled the semaphore, we will enter critical region. + // + ASSERT(KeGetCurrentIrql() <= APC_LEVEL); + KeEnterCriticalRegion(); + inCriticalRegion = TRUE; + + // + // Queue the IRP and return STATUS_PENDING after signalling the + // polling thread. + // Note: IoCsqInsertIrp marks the IRP pending. + // + IoCsqInsertIrp(&devExtension->CancelSafeQueue, Irp, NULL); + + // + // Do not touch the IRP once it has been queued because another thread + // could remove the IRP and complete it before this one gets to run. + // + + // + // A semaphore remains signaled as long as its count is greater than + // zero, and non-signaled when the count is zero. Following function + // increments the semaphore count by 1. + // + + KeReleaseSemaphore(&devExtension->IrpQueueSemaphore, + 0,// No priority boost + 1,// Increment semaphore by 1 + FALSE );// No WaitForXxx after this call + if (inCriticalRegion == TRUE) { + KeLeaveCriticalRegion(); + } + // + // We don't hold the lock for IRP that's pending in the list because this + // lock is meant to rundown currently dispatching threads when the cleanup + // is handled. + // + IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); + + return STATUS_PENDING; +} + +VOID +CsampPollingThread( + _In_ PVOID Context + ) +/*++ + +Routine Description: + + This is the main thread that removes IRP from the queue + and peforms I/O on it. + +Arguments: + + Context -- pointer to the device object + +--*/ +{ + PDEVICE_OBJECT DeviceObject = Context; + PDEVICE_EXTENSION DevExtension = DeviceObject->DeviceExtension; + PIRP Irp; + NTSTATUS Status; + + KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY ); + + // + // Now enter the main IRP-processing loop + // + for(;;) + { + // + // Wait indefinitely for an IRP to appear in the work queue or for + // the Unload routine to stop the thread. Every successful return + // from the wait decrements the semaphore count by 1. + // + KeWaitForSingleObject(&DevExtension->IrpQueueSemaphore, + Executive, + KernelMode, + FALSE, + NULL ); + + // + // See if thread was awakened because driver is unloading itself... + // + + if ( DevExtension->ThreadShouldStop ) { + PsTerminateSystemThread( STATUS_SUCCESS ); + } + + // + // Remove a pending IRP from the queue. + // + Irp = IoCsqRemoveNextIrp(&DevExtension->CancelSafeQueue, NULL); + + if (!Irp) { + CSAMP_KDPRINT(("Oops, a queued irp got cancelled\n")); + continue; // go back to waiting + } + + for(;;) { + // + // Perform I/O + // + Status = CsampPollDevice(DeviceObject, Irp); + if (Status == STATUS_PENDING) { + + // + // Device is not ready, so sleep for a while and try again. + // + KeDelayExecutionThread(KernelMode, FALSE, + &DevExtension->PollingInterval); + + } else { + + // + // I/O is successful, so complete the Irp. + // + Irp->IoStatus.Status = Status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + break; + } + + } + // + // Go back to the top of the loop to see if there's another request waiting. + // + } // end of while-loop +} + +_Use_decl_annotations_ +NTSTATUS +CsampPollDevice( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + Polls for data + +Arguments: + + DeviceObject -- pointer to the device object + Irp -- pointer to the requesing Irp + + +Return Value: + + STATUS_SUCCESS -- if the poll succeeded, + STATUS_TIMEOUT -- if the poll failed (timeout), + or the checksum was incorrect + STATUS_PENDING -- if polled too soon + +--*/ +{ + PINPUT_DATA pInput; + + UNREFERENCED_PARAMETER( DeviceObject ); + + pInput = (PINPUT_DATA)Irp->AssociatedIrp.SystemBuffer; + +#ifdef REAL + + RtlZeroMemory( pInput, sizeof(INPUT_DATA) ); + + // + // If currenttime is less than the lasttime polled plus + // minimum time required for the device to settle + // then don't poll and return STATUS_PENDING + // + + KeQuerySystemTime(¤tTime); + if (currentTime->QuadPart < (TimeBetweenPolls + + devExtension->LastPollTime.QuadPart)) + { + return STATUS_PENDING; + } + + // + // Read/Write to the port here. + // Fill the INPUT structure + // + + // + // Note down the current time as the last polled time + // + + KeQuerySystemTime(&devExtension->LastPollTime); + + + return STATUS_SUCCESS; +#else + + // + // With this conditional statement + // you can control the number of times the + // i/o should be retried before completing. + // + + if (pInput->Data-- <= 0) + { + Irp->IoStatus.Information = sizeof(INPUT_DATA); + return STATUS_SUCCESS; + } + return STATUS_PENDING; + + #endif + +} + +_Use_decl_annotations_ +NTSTATUS +CsampCleanup( + PDEVICE_OBJECT DeviceObject, + PIRP Irp +) +/*++ + +Routine Description: + This dispatch routine is called when the last handle (in + the whole system) to a file object is closed. In other words, the open + handle count for the file object goes to 0. A driver that holds pending + IRPs internally must implement a routine for IRP_MJ_CLEANUP. When the + routine is called, the driver should cancel all the pending IRPs that + belong to the file object identified by the IRP_MJ_CLEANUP call. In other + words, it should cancel all the IRPs that have the same file-object pointer + as the one supplied in the current I/O stack location of the IRP for the + IRP_MJ_CLEANUP call. Of course, IRPs belonging to other file objects should + not be canceled. Also, if an outstanding IRP is completed immediately, the + driver does not have to cancel it. + +Arguments: + + DeviceObject -- pointer to the device object + Irp -- pointer to the requesing Irp + +Return Value: + + STATUS_SUCCESS -- if the poll succeeded, +--*/ +{ + + PDEVICE_EXTENSION devExtension; + PIRP pendingIrp; + PIO_STACK_LOCATION irpStack; + PFILE_CONTEXT fileContext; + NTSTATUS status; + + CSAMP_KDPRINT(("CsampCleanupIrp enter\n")); + + devExtension = DeviceObject->DeviceExtension; + + irpStack = IoGetCurrentIrpStackLocation(Irp); + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + // + // This acquire cannot fail because you cannot get more than one + // cleanup for the same handle. + // + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + ASSERT(NT_SUCCESS(status)); + + // + // Wait for all the threads that are currently dispatching to exit and + // prevent any threads dispatching I/O on the same handle beyond this point. + // + IoReleaseRemoveLockAndWait(&fileContext->FileRundownLock, Irp); + + pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, + irpStack->FileObject); + + while(pendingIrp) + { + // + // Cancel the IRP + // + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + CSAMP_KDPRINT(("Cleanup cancelled irp\n")); + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + + pendingIrp = IoCsqRemoveNextIrp(&devExtension->CancelSafeQueue, + irpStack->FileObject); + } + + // + // Finally complete the cleanup IRP + // + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + CSAMP_KDPRINT(("CsampCleanupIrp exit\n")); + + return STATUS_SUCCESS; + +} + +VOID +CsampUnload( + _In_ PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + Free all the allocated resources, etc. + +Arguments: + + DriverObject - pointer to a driver object. + +Return Value: + + VOID +--*/ +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + PDEVICE_EXTENSION devExtension = deviceObject->DeviceExtension; + + PAGED_CODE(); + + CSAMP_KDPRINT(("CsampUnload Enter\n")); + + // + // Set the Stop flag + // + devExtension->ThreadShouldStop = TRUE; + + // + // Make sure the thread wakes up + // +#pragma prefast(suppress: __WARNING_ERROR, "Passing TRUE as last parameter of KeReleaseSemaphore is just a hint that a wait is next.") + KeReleaseSemaphore(&devExtension->IrpQueueSemaphore, + 0, // No priority boost + 1, // Increment semaphore by 1 + TRUE );// WaitForXxx after this call + + // + // Wait for the thread to terminate + // + KeWaitForSingleObject(devExtension->ThreadObject, + Executive, + KernelMode, + FALSE, + NULL ); + + ObDereferenceObject(devExtension->ThreadObject); + + // + // Create counted string version of our Win32 device name. + // + + RtlInitUnicodeString( &uniWin32NameString, CSAMP_DOS_DEVICE_NAME_U ); + + IoDeleteSymbolicLink( &uniWin32NameString ); + + IoDeleteDevice( deviceObject ); + + CSAMP_KDPRINT(("CsampUnload Exit\n")); + return; +} + +VOID CsampInsertIrp ( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ) +{ + PDEVICE_EXTENSION devExtension; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + + InsertTailList(&devExtension->PendingIrpQueue, + &Irp->Tail.Overlay.ListEntry); +} + +VOID CsampRemoveIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ) +{ + UNREFERENCED_PARAMETER(Csq); + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); +} + + +PIRP CsampPeekNextIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID PeekContext + ) +{ + PDEVICE_EXTENSION devExtension; + PIRP nextIrp = NULL; + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + PIO_STACK_LOCATION irpStack; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + + listHead = &devExtension->PendingIrpQueue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if (Irp == NULL) { + nextEntry = listHead->Flink; + } else { + nextEntry = Irp->Tail.Overlay.ListEntry.Flink; + } + + while(nextEntry != listHead) { + + nextIrp = CONTAINING_RECORD(nextEntry, IRP, Tail.Overlay.ListEntry); + + irpStack = IoGetCurrentIrpStackLocation(nextIrp); + + // + // If context is present, continue until you find a matching one. + // Else you break out as you got next one. + // + + if (PeekContext) { + if (irpStack->FileObject == (PFILE_OBJECT) PeekContext) { + break; + } + } else { + break; + } + nextIrp = NULL; + nextEntry = nextEntry->Flink; + } + + return nextIrp; + +} + +// +// CsampAcquireLock modifies the execution level of the current processor. +// +// KeAcquireSpinLock raises the execution level to Dispatch Level and stores +// the current execution level in the Irql parameter to be restored at a later +// time. KeAcqurieSpinLock also requires us to be running at no higher than +// Dispatch level when it is called. +// +// The annotations reflect these changes and requirments. +// + +_IRQL_raises_(DISPATCH_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID CsampAcquireLock( + _In_ PIO_CSQ Csq, + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql + ) +{ + PDEVICE_EXTENSION devExtension; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + // + // Suppressing because the address below csq is valid since it's + // part of DEVICE_EXTENSION structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'") + KeAcquireSpinLock(&devExtension->QueueLock, Irql); +} + +// +// CsampReleaseLock modifies the execution level of the current processor. +// +// KeReleaseSpinLock assumes we already hold the spin lock and are therefore +// running at Dispatch level. It will use the Irql parameter saved in a +// previous call to KeAcquireSpinLock to return the thread back to it's original +// execution level. +// +// The annotations reflect these changes and requirments. +// + +_IRQL_requires_(DISPATCH_LEVEL) +_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID CsampReleaseLock( + _In_ PIO_CSQ Csq, + _In_ _IRQL_restores_ KIRQL Irql + ) +{ + PDEVICE_EXTENSION devExtension; + + devExtension = CONTAINING_RECORD(Csq, + DEVICE_EXTENSION, CancelSafeQueue); + // + // Suppressing because the address below csq is valid since it's + // part of DEVICE_EXTENSION structure. + // +#pragma prefast(suppress: __WARNING_BUFFER_UNDERFLOW, "Underflow using expression 'devExtension->QueueLock'") + KeReleaseSpinLock(&devExtension->QueueLock, Irql); +} + +VOID CsampCompleteCanceledIrp( + _In_ PIO_CSQ pCsq, + _In_ PIRP Irp + ) +{ + + UNREFERENCED_PARAMETER(pCsq); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + CSAMP_KDPRINT(("cancelled irp\n")); + IoCompleteRequest(Irp, IO_NO_INCREMENT); +} + diff --git a/general/cancel/sys/cancel.h b/general/cancel/sys/cancel.h new file mode 100644 index 00000000..4f63d2af --- /dev/null +++ b/general/cancel/sys/cancel.h @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + cancel.h + +Abstract: + +Environment: + + Kernel mode only. + + +Revision History: + +--*/ + +#include <initguid.h> + +// +// Since this driver is a legacy driver and gets installed as a service +// (without an INF file), we will define a class guid for use in +// IoCreateDeviceSecure function. This would allow the system to store +// Security, DeviceType, Characteristics and Exclusivity information of the +// deviceobject in the registery under +// HKLM\SYSTEM\CurrentControlSet\Control\Class\ClassGUID\Properties. +// This information can be overrided by an Administrators giving them the ability +// to control access to the device beyond what is initially allowed +// by the driver developer. +// + +// {5D006E1A-2631-466c-B8A0-32FD498E4424} - generated using guidgen.exe +DEFINE_GUID (GUID_DEVCLASS_CANCEL_SAMPLE, + 0x5d006e1a, 0x2631, 0x466c, 0xb8, 0xa0, 0x32, 0xfd, 0x49, 0x8e, 0x44, 0x24); + +// +// GUID definition are required to be outside of header inclusion pragma to avoid +// error during precompiled headers. +// + +#ifndef __CANCEL_H +#define __CANCEL_H + +// +// GUID definition are required to be outside of header inclusion pragma to +// avoid error during precompiled headers. +// +#include <ntddk.h> +#include <wdmsec.h> // for IoCreateDeviceSecure +#include <dontuse.h> + +// Debugging macros + +#if DBG +#define CSAMP_KDPRINT(_x_) \ + DbgPrint("CANCEL.SYS: ");\ + DbgPrint _x_; +#else + +#define CSAMP_KDPRINT(_x_) + +#endif + +#define CSAMP_DEVICE_NAME_U L"\\Device\\CANCELSAMP" +#define CSAMP_DOS_DEVICE_NAME_U L"\\DosDevices\\CancelSamp" +#define CSAMP_RETRY_INTERVAL 500*1000 //500 ms +#define TAG (ULONG)'MASC' + +typedef struct _INPUT_DATA{ + + ULONG Data; //device data is stored here + +} INPUT_DATA, *PINPUT_DATA; + +typedef struct _DEVICE_EXTENSION{ + + BOOLEAN ThreadShouldStop; + + // Irps waiting to be processed are queued here + LIST_ENTRY PendingIrpQueue; + + // SpinLock to protect access to the queue + KSPIN_LOCK QueueLock; + + IO_CSQ CancelSafeQueue; + + // Time at which the device was last polled + LARGE_INTEGER LastPollTime; + + // Polling interval (retry interval) + LARGE_INTEGER PollingInterval; + + KSEMAPHORE IrpQueueSemaphore; + + PETHREAD ThreadObject; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +typedef struct _FILE_CONTEXT{ + // + // Lock to rundown threads that are dispatching I/Os on a file handle + // while the cleanup for that handle is in progress. + // + IO_REMOVE_LOCK FileRundownLock; +} FILE_CONTEXT, *PFILE_CONTEXT; + +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH CsampCreateClose; + +_Dispatch_type_(IRP_MJ_CLEANUP) +DRIVER_DISPATCH CsampCleanup; + +_Dispatch_type_(IRP_MJ_READ) +DRIVER_DISPATCH CsampRead; + +DRIVER_DISPATCH CsampPollDevice; + +DRIVER_UNLOAD CsampUnload; + +KSTART_ROUTINE CsampPollingThread; + +VOID +CsampPollingThread( + _In_ PVOID Context + ); + +VOID +CsampInsertIrp ( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ); + +VOID +CsampRemoveIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp + ); + +PIRP +CsampPeekNextIrp( + _In_ PIO_CSQ Csq, + _In_ PIRP Irp, + _In_ PVOID PeekContext + ); + +_IRQL_raises_(DISPATCH_LEVEL) +_IRQL_requires_max_(DISPATCH_LEVEL) +_Acquires_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID +CsampAcquireLock( + _In_ PIO_CSQ Csq, + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql + ); + +_IRQL_requires_(DISPATCH_LEVEL) +_Releases_lock_(CONTAINING_RECORD(Csq,DEVICE_EXTENSION, CancelSafeQueue)->QueueLock) +VOID +CsampReleaseLock( + _In_ PIO_CSQ Csq, + _In_ _IRQL_restores_ KIRQL Irql + ); + +VOID +CsampCompleteCanceledIrp( + _In_ PIO_CSQ pCsq, + _In_ PIRP Irp + ); + +#endif + + + diff --git a/general/cancel/sys/cancel.rc b/general/cancel/sys/cancel.rc new file mode 100644 index 00000000..2bd08155 --- /dev/null +++ b/general/cancel/sys/cancel.rc @@ -0,0 +1,10 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Sample Cancel Driver" +#define VER_INTERNALNAME_STR "cancel.sys" + +#include "common.ver" diff --git a/general/cancel/sys/cancel.vcxproj b/general/cancel/sys/cancel.vcxproj new file mode 100644 index 00000000..6227a13d --- /dev/null +++ b/general/cancel/sys/cancel.vcxproj @@ -0,0 +1,152 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{3363DCA3-7873-4ECB-BA98-F243C2E8FDA0}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{3003AE7E-3AA2-458A-B349-64E4A921061B}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>cancel</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib</AdditionalDependencies> + </Link> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="cancel.c" /> + <ResourceCompile Include="cancel.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/cancel/sys/cancel.vcxproj.Filters b/general/cancel/sys/cancel.vcxproj.Filters new file mode 100644 index 00000000..bdf2e015 --- /dev/null +++ b/general/cancel/sys/cancel.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{6BC3B1BF-F875-48B1-9E49-07CB6AE2FED1}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{646CC6F7-384E-44CB-B55D-2CF7427232F2}</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>{A3ADD9F6-E06C-4974-AD86-F265759792E2}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{4BC75BD1-ADE8-40F5-91AF-0002A740EF8C}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="cancel.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="cancel.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/kmdf/ReadMe.md b/general/echo/kmdf/ReadMe.md new file mode 100644 index 00000000..05f41f49 --- /dev/null +++ b/general/echo/kmdf/ReadMe.md @@ -0,0 +1,84 @@ +KMDF Echo Sample +================ + +The ECHO (KMDF) sample demonstrates how to use a sequential queue to serialize read and write requests presented to the driver. + +It also shows how to synchronize execution of these events with other asynchronous events such as request cancellation and DPC. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + +Related technologies +-------------------- + +[Kernel-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544396) + +Code Tour +--------- + +DriverEntry - Creates a framework driver object. + +EvtDeviceAdd: Creates a device and registers self managed I/O callbacks so that it can start and stop the periodic timer when the device is entering and leaving D0 state. It registers a device interface so that application can find the device and send I/O. For managing I/O requests, the driver creates a default queue to receive only read & write requests. All other requests sent to the driver will be failed by the framework. Then the driver creates a periodic timer to simulate asynchronous event. The purpose of this timer would be to complete the currently pending request. + +In the AutoSync version of the sample, the queue is created with WdfSynchronizationScopeQueue so that I/O callbacks including cancel routine are synchronized with a queue-level lock. Since timer is parented to queue and by default timer objects are created with AutomaticSerialization set to **TRUE**, timer DPC callbacks will be serialized with EvtIoRead, EvtIoWrite and Cancel Routine. + +In the DriverSync version of the sample, the queue is created with WdfSynchronizationScopeNone, so that the framework does not provide any synchronization. The driver synchronizes the I/O callbacks, cancel routine and the timer DPC using a spinlock that it creates for this purpose. + +EvtIoWrite: Allocates an internal buffer as big as the size of buffer in the write request and copies the data from the request buffer to internal buffer. The internal buffer address is saved in the queue context. If the driver receives another write request, it will free this one and allocate a new buffer to match the size of the incoming request. After copying the data, it will mark the request cancelable and return. The request will be eventually completed either by the timer or by the cancel routine if the application exits. + +EvtIoRead: Retrieves request memory buffer and copies the data from the buffer created by the write handler to the request buffer, and marks the request cancelable. The request will be completed by the timer DPC callback. + +Since the queue is a sequential queue, only one request is outstanding in the driver. + +Testing +------- + +**Usage:** + +Echoapp.exe --- Send single write and read request synchronously + +Echoapp.exe -Async --- Send 100 reads and writes asynchronously + +Exit the app anytime by pressing Ctrl-C + +File Manifest +------------- + +File + +Description + +Echo.htm + +Documentation for this sample (this file). + +***(The AutoSync and DriverSync versions of the sample each have their own version of the following files)*** + +Driver.h, Driver.c + +DriverEntry and Events on the Driver Object. + +Device.h, Device.c + +Events on the Device Object. + +Queue.h, Queue.c + +Contains Events on the I/O Queue Objects. + +Echo.inx + +File that describes the installation of this driver. The build process converts this into an INF file. + +Makefile.inc + +A makefile that defines custom build actions. This includes the conversion of the .INX file into a .INF file + +Makefile + +This file merely redirects to the real makefile that is shared by all the driver components of the Windows NT DDK. + +Sources + +Generic file that lists source files and all the build options. + diff --git a/general/echo/kmdf/driver/AutoSync/device.c b/general/echo/kmdf/driver/AutoSync/device.c new file mode 100644 index 00000000..ee20447f --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/device.c @@ -0,0 +1,210 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.c - Device handling events for example driver. + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, EchoDeviceCreate) +#pragma alloc_text (PAGE, EchoEvtDeviceSelfManagedIoSuspend) +#endif + + +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + Worker routine called to create a device and its software resources. + +Arguments: + + DeviceInit - Pointer to an opaque init structure. Memory for this + structure will be freed by the framework when the WdfDeviceCreate + succeeds. So don't access the structure after that point. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES deviceAttributes; + PDEVICE_CONTEXT deviceContext; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDFDEVICE device; + NTSTATUS status; + + PAGED_CODE(); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Register pnp/power callbacks so that we can start and stop the timer as the device + // gets started and stopped. + // + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; + pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; + + #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") + pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; + + // + // Register the PnP and power callbacks. Power policy related callbacks will be registered + // later in SotwareInit. + // + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); + + if (NT_SUCCESS(status)) { + // + // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an + // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the + // device.h header file. This function will do the type checking and return + // the device context. If you pass a wrong object handle + // it will return NULL and assert if run under framework verifier mode. + // + deviceContext = WdfObjectGet_DEVICE_CONTEXT(device); + deviceContext->PrivateDeviceData = 0; + + // + // Create a device interface so that application can find and talk + // to us. + // + status = WdfDeviceCreateDeviceInterface( + device, + &GUID_DEVINTERFACE_ECHO, + NULL // ReferenceString + ); + + if (NT_SUCCESS(status)) { + // + // Initialize the I/O Package and any Queues + // + status = EchoQueueInitialize(device); + } + } + + return status; +} + + +NTSTATUS +EchoEvtDeviceSelfManagedIoStart( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is started + or restarted after a suspend operation. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + LARGE_INTEGER DueTime; + + KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n")); + + // + // Restart the queue and the periodic timer. We stopped them before going + // into low power state. + // + WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device)); + + DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); + + WdfTimerStart(queueContext->Timer, DueTime.QuadPart); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n")); + + return STATUS_SUCCESS; +} + +NTSTATUS +EchoEvtDeviceSelfManagedIoSuspend( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is stopped + for resource rebalance or suspended when the system is entering + Sx state. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - The driver is not allowed to fail this function. If it does, the + device stack will be torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + + PAGED_CODE(); + + KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n")); + + // + // Before we stop the timer we should make sure there are no outstanding + // i/o. We need to do that because framework cannot suspend the device + // if there are requests owned by the driver. There are two ways to solve + // this issue: 1) We can wait for the outstanding I/O to be complete by the + // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge + // the request to inform the framework that it's okay to suspend the device + // with outstanding I/O. In this sample we will use the 1st approach + // because it's pretty easy to do. We will restart the queue when the + // device is restarted. + // + WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device)); + + // + // Stop the watchdog timer and wait for DPC to run to completion if it's already fired. + // + WdfTimerStop(queueContext->Timer, TRUE); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n")); + + return STATUS_SUCCESS; +} + + + diff --git a/general/echo/kmdf/driver/AutoSync/device.h b/general/echo/kmdf/driver/AutoSync/device.h new file mode 100644 index 00000000..f29c7908 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/device.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "public.h" + +// +// The device context performs the same job as +// a WDM device extension in the driver frameworks +// +typedef struct _DEVICE_CONTEXT +{ + ULONG PrivateDeviceData; // just a placeholder + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +// +// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT +// which will be used to get a pointer to the device context memory +// in a type safe manner. +// +WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT) + +// +// Function to initialize the device and its callbacks +// +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ); + +// +// Device events +// +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart; +EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend; + diff --git a/general/echo/kmdf/driver/AutoSync/driver.c b/general/echo/kmdf/driver/AutoSync/driver.c new file mode 100644 index 00000000..60a02692 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/driver.c @@ -0,0 +1,202 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.c + +Abstract: + + This driver demonstrates use of a default I/O Queue, its + request start events, cancellation event, and a synchronized DPC. + + To demonstrate asynchronous operation, the I/O requests are not completed + immediately, but stored in the drivers private data structure, and a timer + DPC will complete it next time the DPC runs. + + During the time the request is waiting for the DPC to run, it is + made cancellable by the call WdfRequestMarkCancelable. This + allows the test program to cancel the request and exit instantly. + + This rather complicated set of events is designed to demonstrate + the driver frameworks synchronization of access to a device driver + data structure, and a pointer which can be a proxy for device hardware + registers or resources. + + This common data structure, or resource is accessed by new request + events arriving, the DPC that completes it, and cancel processing. + + Notice the lack of specific lock/unlock operations. + + Even though this example utilizes a serial queue, a parallel queue + would not need any additional explicit synchronization, just a + strategy for managing multiple requests outstanding. + +--*/ + +#include "driver.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (INIT, EchoPrintDriverVersion) +#pragma alloc_text (PAGE, EchoEvtDeviceAdd) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + WDF_DRIVER_CONFIG_INIT(&config, + EchoEvtDeviceAdd + ); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status)); + return status; + } + +#if DBG + EchoPrintDriverVersion(); +#endif + + return status; +} + +NTSTATUS +EchoEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + KdPrint(("Enter EchoEvtDeviceAdd\n")); + + status = EchoDeviceCreate(DeviceInit); + + return status; +} + +NTSTATUS +EchoPrintDriverVersion( + ) +/*++ +Routine Description: + + This routine shows how to retrieve framework version string and + also how to find out to which version of framework library the + client driver is bound to. + +Arguments: + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFSTRING string; + UNICODE_STRING us; + WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver; + + // + // 1) Retreive version string and print that in the debugger. + // + status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfStringCreate failed 0x%x\n", status)); + return status; + } + + status = WdfDriverRetrieveVersionString(WdfGetDriver(), string); + if (!NT_SUCCESS(status)) { + // + // No need to worry about delete the string object because + // by default it's parented to the driver and it will be + // deleted when the driverobject is deleted when the DriverEntry + // returns a failure status. + // + KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status)); + return status; + } + + WdfStringGetUnicodeString(string, &us); + KdPrint(("Echo Sample %wZ\n", &us)); + + WdfObjectDelete(string); + string = NULL; // To avoid referencing a deleted object. + + // + // 2) Find out to which version of framework this driver is bound to. + // + WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0); + if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) { + KdPrint(("Yes, framework version is 1.0\n")); + }else { + KdPrint(("No, framework verison is not 1.0\n")); + } + + return STATUS_SUCCESS; +} + diff --git a/general/echo/kmdf/driver/AutoSync/driver.h b/general/echo/kmdf/driver/AutoSync/driver.h new file mode 100644 index 00000000..9398ab30 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/driver.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#define INITGUID + +#include <ntddk.h> +#include <wdf.h> + +#include "device.h" +#include "queue.h" + +// +// WDFDRIVER Events +// + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd; + +NTSTATUS +EchoPrintDriverVersion( + ); + diff --git a/general/echo/kmdf/driver/AutoSync/echo.inx b/general/echo/kmdf/driver/AutoSync/echo.inx new file mode 100644 index 00000000..fa0e4f6e --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/echo.inx @@ -0,0 +1,104 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +;Module Name: +; ECHO.INF +; +;Abstract: +; INF file for installing the Driver Frameworks ECHO Driver +; +;Installation Notes: +; Using Devcon: Type "devcon install ECHO.inf root\ECHO" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +ECHO.sys = 1,, + +;***************************************** +; ECHO Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +[Standard.NT$ARCH$] +%ECHO.DeviceDesc%=ECHO_Device, root\ECHO + +[ECHO_Device.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +ECHO.sys + + +;-------------- Service installation +[ECHO_Device.NT.Services] +AddService = ECHO,%SPSVCINST_ASSOCSERVICE%, ECHO_Service_Inst + +; -------------- ECHO driver install sections +[ECHO_Service_Inst] +DisplayName = %ECHO.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\ECHO.sys + +; +;--- ECHO_Device Coinstaller installation ------ +; + +[DestinationDirs] +ECHO_Device_CoInstaller_CopyFiles = 11 + +[ECHO_Device.NT.CoInstallers] +AddReg=ECHO_Device_CoInstaller_AddReg +CopyFiles=ECHO_Device_CoInstaller_CopyFiles + +[ECHO_Device_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[ECHO_Device_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[ECHO_Device.NT.Wdf] +KmdfService = ECHO, ECHO_wdfsect +[ECHO_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample ECHO Installation Disk #1" +ECHO.DeviceDesc = "Sample WDF ECHO Driver" +ECHO.SVCDESC = "Sample WDF ECHO Service" +ClassName = "Sample Device" diff --git a/general/echo/kmdf/driver/AutoSync/echo.vcxproj b/general/echo/kmdf/driver/AutoSync/echo.vcxproj new file mode 100644 index 00000000..fcaaf0ac --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj @@ -0,0 +1,168 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{C8F9A776-3675-459B-A0A3-BA17D003C70B}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{8063717F-2826-44B9-BCF2-23ACCAF2C1FA}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\echo.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\echo.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="device.c" /> + <ClCompile Include="driver.c" /> + <ClCompile Include="queue.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters new file mode 100644 index 00000000..ba649423 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/echo.vcxproj.Filters @@ -0,0 +1,40 @@ +<?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>{C301082A-56B5-43D9-AF50-C90CDBB830DA}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{E8E22922-FDB4-496F-9D8B-0E5930795BAC}</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>{78CA938F-ABD5-4BA1-A021-7E751E09B367}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{A5E77DC1-258D-4E61-AA8D-1879410AE785}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\echo.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\echo.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/kmdf/driver/AutoSync/queue.c b/general/echo/kmdf/driver/AutoSync/queue.c new file mode 100644 index 00000000..cb02a965 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/queue.c @@ -0,0 +1,532 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.c + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, EchoQueueInitialize) +#pragma alloc_text (PAGE, EchoTimerCreate) +#endif + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE Device + ) +/*++ + +Routine Description: + + + The I/O dispatch callbacks for the frameworks device object + are configured in this function. + + A single default I/O Queue is configured for serial request + processing, and a driver context memory allocation is created + to hold our structure QUEUE_CONTEXT. + + This memory may be used by the driver automatically synchronized + by the Queue's presentation lock. + + The lifetime of this memory is tied to the lifetime of the I/O + Queue object, and we register an optional destructor callback + to release any private allocations, and/or resources. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS + +--*/ +{ + WDFQUEUE queue; + NTSTATUS status; + PQUEUE_CONTEXT queueContext; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES queueAttributes; + + PAGED_CODE(); + + // + // Configure a default queue so that requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto + // other queues get dispatched here. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, + WdfIoQueueDispatchSequential + ); + + queueConfig.EvtIoRead = EchoEvtIoRead; + queueConfig.EvtIoWrite = EchoEvtIoWrite; + + // + // Fill in a callback for destroy, and our QUEUE_CONTEXT size + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT); + + // + // Set synchronization scope on queue and have the timer to use queue as + // the parent object so that queue and timer callbacks are synchronized + // with the same lock. + // + queueAttributes.SynchronizationScope = WdfSynchronizationScopeQueue; + + queueAttributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy; + + status = WdfIoQueueCreate( + Device, + &queueConfig, + &queueAttributes, + &queue + ); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); + return status; + } + + // Get our Driver Context memory from the returned Queue handle + queueContext = QueueGetContext(queue); + + queueContext->Buffer = NULL; + queueContext->Timer = NULL; + + queueContext->CurrentRequest = NULL; + queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST; + + // + // Create the Queue timer + // + status = EchoTimerCreate(&queueContext->Timer, TIMER_PERIOD, queue); + if (!NT_SUCCESS(status)) { + KdPrint(("Error creating timer 0x%x\n",status)); + return status; + } + + return status; +} + + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* Timer, + IN ULONG Period, + IN WDFQUEUE Queue + ) +/*++ + +Routine Description: + + Subroutine to create periodic timer. By associating the timerobject with + the queue, we are basically telling the framework to serialize the queue + callbacks with the dpc callback. By doing so, we don't have to worry + about protecting queue-context structure from multiple threads accessing + it simultaneously. + +Arguments: + + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status; + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + + PAGED_CODE(); + + // + // Create a WDFTIMER object + // + WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, EchoEvtTimerFunc, Period); + + timerConfig.AutomaticSerialization = FALSE; + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue + + Status = WdfTimerCreate(&timerConfig, + &timerAttributes, + Timer // Output handle + ); + + return Status; +} + + + +VOID +EchoEvtIoQueueContextDestroy( + WDFOBJECT Object +) +/*++ + +Routine Description: + + This is called when the Queue that our driver context memory + is associated with is destroyed. + +Arguments: + + Context - Context that's being freed. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(Object); + + // + // Release any resources pointed to in the queue context. + // + // The body of the queue context will be released after + // this callback handler returns + // + + // + // If Queue context has an I/O buffer, release it + // + if( queueContext->Buffer != NULL ) { + ExFreePool(queueContext->Buffer); + } + + return; +} + + +VOID +EchoEvtRequestCancel( + IN WDFREQUEST Request + ) +/*++ + +Routine Description: + + + Called when an I/O request is cancelled after the driver has marked + the request cancellable. This callback is automatically synchronized + with the I/O callbacks since we have chosen to use frameworks Device + level locking. + +Arguments: + + Request - Request being cancelled. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfRequestGetIoQueue(Request)); + + KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request)); + + // + // The following is race free by the callside or DPC side + // synchronizing completion by calling + // WdfRequestMarkCancelable(Queue, Request, FALSE) before + // completion and not calling WdfRequestComplete if the + // return status == STATUS_CANCELLED. + // + WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L); + + // + // This book keeping is synchronized by the common + // Queue presentation lock + // + ASSERT(queueContext->CurrentRequest == Request); + queueContext->CurrentRequest = NULL; + + return; +} + +VOID +EchoEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_READ request. + It will copy the content from the queue-context buffer to the request buffer. + If the driver hasn't received any write request earlier, the read returns zero. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + WDFMEMORY memory; + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + // + // No data to read + // + if( (queueContext->Buffer == NULL) ) { + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L); + return; + } + _Analysis_assume_(queueContext->Length > 0); + + // + // Read what we have + // + if( queueContext->Length < Length ) { + Length = queueContext->Length; + } + + // + // Get the request memory + // + Status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestCompleteWithInformation(Request, Status, 0L); + return; + } + + // Copy the memory out + Status = WdfMemoryCopyFromBuffer( memory, // destination + 0, // offset into the destination memory + queueContext->Buffer, + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status)); + WdfRequestComplete(Request, Status); + return; + } + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + // Mark the request is cancelable + WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); + + + // Defer the completion to another thread from the timer dpc + queueContext->CurrentRequest = Request; + queueContext->CurrentStatus = Status; + + return; +} + +VOID +EchoEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is invoked when the framework receives IRP_MJ_WRITE request. + This routine allocates memory buffer, copies the data from the request to it, + and stores the buffer pointer in the queue-context with the length variable + representing the buffers length. The actual completion of the request + is defered to the periodic timer dpc. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + WDFMEMORY memory; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + + if( Length > MAX_WRITE_LENGTH ) { + KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", + Length,MAX_WRITE_LENGTH)); + WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); + return; + } + + // Get the memory buffer + Status = WdfRequestRetrieveInputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n", + Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestComplete(Request, Status); + return; + } + + // Release previous buffer if set + if( queueContext->Buffer != NULL ) { + ExFreePool(queueContext->Buffer); + queueContext->Buffer = NULL; + queueContext->Length = 0L; + } + + queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1'); + if( queueContext->Buffer == NULL ) { + KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length)); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return; + } + + + // Copy the memory in + Status = WdfMemoryCopyToBuffer( memory, + 0, // offset into the source memory + queueContext->Buffer, + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status)); + WdfVerifierDbgBreakPoint(); + + ExFreePool(queueContext->Buffer); + queueContext->Buffer = NULL; + queueContext->Length = 0L; + + WdfRequestComplete(Request, Status); + return; + } + + + queueContext->Length = (ULONG) Length; + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + // Specify the request is cancelable + WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); + + // Defer the completion to another thread from the timer dpc + queueContext->CurrentRequest = Request; + queueContext->CurrentStatus = Status; + + return; +} + + +VOID +EchoEvtTimerFunc( + IN WDFTIMER Timer + ) +/*++ + +Routine Description: + + This is the TimerDPC the driver sets up to complete requests. + This function is registered when the WDFTIMER object is created, and + will automatically synchronize with the I/O Queue callbacks + and cancel routine. + +Arguments: + + Timer - Handle to a framework Timer object. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + WDFREQUEST Request; + WDFQUEUE queue; + PQUEUE_CONTEXT queueContext ; + + queue = WdfTimerGetParentObject(Timer); + queueContext = QueueGetContext(queue); + + // + // DPC is automatically synchronized to the Queue lock, + // so this is race free without explicit driver managed locking. + // + Request = queueContext->CurrentRequest; + if( Request != NULL ) { + + // + // Attempt to remove cancel status from the request. + // + // The request is not completed if it is already cancelled + // since the EchoEvtIoCancel function has run, or is about to run + // and we are racing with it. + // + Status = WdfRequestUnmarkCancelable(Request); + if( Status != STATUS_CANCELLED ) { + + queueContext->CurrentRequest = NULL; + Status = queueContext->CurrentStatus; + + KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status)); + + WdfRequestComplete(Request, Status); + } + else { + KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n", + Request)); + } + } + + return; +} + + diff --git a/general/echo/kmdf/driver/AutoSync/queue.h b/general/echo/kmdf/driver/AutoSync/queue.h new file mode 100644 index 00000000..a20e0375 --- /dev/null +++ b/general/echo/kmdf/driver/AutoSync/queue.h @@ -0,0 +1,64 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +// Set max write length for testing +#define MAX_WRITE_LENGTH 1024*40 + +// Set timer period in ms +#define TIMER_PERIOD 1000*2 + +// +// This is the context that can be placed per queue +// and would contain per queue information. +// +typedef struct _QUEUE_CONTEXT { + + // Here we allocate a buffer from a test write so it can be read back + PVOID Buffer; + ULONG Length; + + // Timer DPC for this queue + WDFTIMER Timer; + + // Virtual I/O + WDFREQUEST CurrentRequest; + NTSTATUS CurrentStatus; + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE hDevice + ); + +EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy; + +// +// Events from the IoQueue object +// +EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel; +EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite; + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* pTimer, + IN ULONG Period, + IN WDFQUEUE Queue + ); + +EVT_WDF_TIMER EchoEvtTimerFunc; diff --git a/general/echo/kmdf/driver/DriverSync/device.c b/general/echo/kmdf/driver/DriverSync/device.c new file mode 100644 index 00000000..eb37eaf2 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/device.c @@ -0,0 +1,223 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.c - Device handling events for example driver. + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, EchoDeviceCreate) +#pragma alloc_text (PAGE, EchoEvtDeviceSelfManagedIoSuspend) +#endif + + +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + Worker routine called to create a device and its software resources. + +Arguments: + + DeviceInit - Pointer to an opaque init structure. Memory for this + structure will be freed by the framework when the WdfDeviceCreate + succeeds. So don't access the structure after that point. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES attributes; + PDEVICE_CONTEXT deviceContext; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDFDEVICE device; + NTSTATUS status; + + PAGED_CODE(); + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Register pnp/power callbacks so that we can start and stop the timer as the device + // gets started and stopped. + // + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; + pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; + #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") + pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; + + // + // Register the PnP and power callbacks. Power policy related callbacks will be registered + // later in SotwareInit. + // + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, REQUEST_CONTEXT); + WdfDeviceInitSetRequestAttributes(DeviceInit, &attributes); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); + + // + // By not setting the synchronization scope and using the default, there is + // no locking between any of the callbacks in this driver. + // + // We will create a sequential queue so all of the EvtIoXxx callbacks are + // serialized against each other (at least until the request is completed), + // but the cancel routine and the timer DPC are not synchronized against the + // queue's EvtIoXxx callbacks. + // + // attributes.SynchronizationScope = ... + + status = WdfDeviceCreate(&DeviceInit, &attributes, &device); + + if (NT_SUCCESS(status)) { + // + // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an + // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the + // device.h header file. This function will do the type checking and return + // the device context. If you pass a wrong object handle + // it will return NULL and assert if run under framework verifier mode. + // + deviceContext = WdfObjectGet_DEVICE_CONTEXT(device); + deviceContext->PrivateDeviceData = 0; + + // + // Create a device interface so that application can find and talk + // to us. + // + status = WdfDeviceCreateDeviceInterface( + device, + &GUID_DEVINTERFACE_ECHO, + NULL // ReferenceString + ); + + if (NT_SUCCESS(status)) { + // + // Initialize the I/O Package and any Queues + // + status = EchoQueueInitialize(device); + } + } + + return status; +} + + +NTSTATUS +EchoEvtDeviceSelfManagedIoStart( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is started + or restarted after a suspend operation. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + LARGE_INTEGER DueTime; + + KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n")); + + // + // Restart the queue and the periodic timer. We stopped them before going + // into low power state. + // + WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device)); + + DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); + + WdfTimerStart(queueContext->Timer, DueTime.QuadPart); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n")); + + return STATUS_SUCCESS; +} + +NTSTATUS +EchoEvtDeviceSelfManagedIoSuspend( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is stopped + for resource rebalance or suspended when the system is entering + Sx state. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - The driver is not allowed to fail this function. If it does, the + device stack will be torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + + PAGED_CODE(); + + KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n")); + + // + // Before we stop the timer we should make sure there are no outstanding + // i/o. We need to do that because framework cannot suspend the device + // if there are requests owned by the driver. There are two ways to solve + // this issue: 1) We can wait for the outstanding I/O to be complete by the + // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge + // the request to inform the framework that it's okay to suspend the device + // with outstanding I/O. In this sample we will use the 1st approach + // because it's pretty easy to do. We will restart the queue when the + // device is restarted. + // + WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device)); + + // + // Stop the watchdog timer and wait for DPC to run to completion if it's already fired. + // + WdfTimerStop(queueContext->Timer, TRUE); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n")); + + return STATUS_SUCCESS; +} + + + diff --git a/general/echo/kmdf/driver/DriverSync/device.h b/general/echo/kmdf/driver/DriverSync/device.h new file mode 100644 index 00000000..f29c7908 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/device.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "public.h" + +// +// The device context performs the same job as +// a WDM device extension in the driver frameworks +// +typedef struct _DEVICE_CONTEXT +{ + ULONG PrivateDeviceData; // just a placeholder + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +// +// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT +// which will be used to get a pointer to the device context memory +// in a type safe manner. +// +WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT) + +// +// Function to initialize the device and its callbacks +// +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ); + +// +// Device events +// +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart; +EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend; + diff --git a/general/echo/kmdf/driver/DriverSync/driver.c b/general/echo/kmdf/driver/DriverSync/driver.c new file mode 100644 index 00000000..f1e216f2 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/driver.c @@ -0,0 +1,201 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.c + +Abstract: + + This driver demonstrates use of a default I/O Queue, its + request start events, cancellation event, and a synchronized DPC. + + To demonstrate asynchronous operation, the I/O requests are not completed + immediately, but stored in the drivers private data structure, and a timer + DPC will complete it next time the DPC runs. + + During the time the request is waiting for the DPC to run, it is + made cancellable by the call WdfRequestMarkCancelable. This + allows the test program to cancel the request and exit instantly. + + This rather complicated set of events is designed to demonstrate + the driver frameworks synchronization of access to a device driver + data structure, and a pointer which can be a proxy for device hardware + registers or resources. + + This common data structure, or resource is accessed by new request + events arriving, the DPC that completes it, and cancel processing. + + Notice the lack of specific lock/unlock operations. + + Even though this example utilizes a serial queue, a parallel queue + would not need any additional explicit synchronization, just a + strategy for managing multiple requests outstanding. + +--*/ + +#include "driver.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (INIT, EchoPrintDriverVersion) +#pragma alloc_text (PAGE, EchoEvtDeviceAdd) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + WDF_DRIVER_CONFIG_INIT(&config, + EchoEvtDeviceAdd + ); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status)); + return status; + } + +#if DBG + EchoPrintDriverVersion(); +#endif + + return status; +} + +NTSTATUS +EchoEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + KdPrint(("Enter EchoEvtDeviceAdd\n")); + + status = EchoDeviceCreate(DeviceInit); + + return status; +} + +NTSTATUS +EchoPrintDriverVersion( + ) +/*++ +Routine Description: + + This routine shows how to retrieve framework version string and + also how to find out to which version of framework library the + client driver is bound to. + +Arguments: + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFSTRING string; + UNICODE_STRING us; + WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver; + + // + // 1) Retreive version string and print that in the debugger. + // + status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfStringCreate failed 0x%x\n", status)); + return status; + } + + status = WdfDriverRetrieveVersionString(WdfGetDriver(), string); + if (!NT_SUCCESS(status)) { + // + // No need to worry about delete the string object because + // by default it's parented to the driver and it will be + // deleted when the driverobject is deleted when the DriverEntry + // returns a failure status. + // + KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status)); + return status; + } + + WdfStringGetUnicodeString(string, &us); + KdPrint(("Echo Sample %wZ\n", &us)); + + WdfObjectDelete(string); + string = NULL; // To avoid referencing a deleted object. + + // + // 2) Find out to which version of framework this driver is bound to. + // + WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0); + if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) { + KdPrint(("Yes, framework version is 1.0\n")); + }else { + KdPrint(("No, framework verison is not 1.0\n")); + } + + return STATUS_SUCCESS; +} + diff --git a/general/echo/kmdf/driver/DriverSync/driver.h b/general/echo/kmdf/driver/DriverSync/driver.h new file mode 100644 index 00000000..5bf8853f --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/driver.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#define INITGUID + +#include <ntddk.h> +#include <wdf.h> + +#include "device.h" +#include "queue.h" + +typedef struct _REQUEST_CONTEXT { + // + // Count to use when trying to claim completion ownership of a cancelable + // request when clearing the cancel routine. If the caller can clear the + // cancel routine successfully, the caller is *NOT* responsible for decrementing + // the count if the request is going to be completed immediately (and a + // cancel routine is not going to be set in the future). + // + LONG CancelCompletionOwnershipCount; + +} REQUEST_CONTEXT, *PREQUEST_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, RequestGetContext); + +// +// WDFDRIVER Events +// + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd; + +NTSTATUS +EchoPrintDriverVersion( + ); + diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.inx b/general/echo/kmdf/driver/DriverSync/echo_2.inx new file mode 100644 index 00000000..af09757f --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/echo_2.inx @@ -0,0 +1,105 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +;Module Name: +; ECHO_2.INF +; +;Abstract: +; INF file for installing the Driver Frameworks ECHO Driver (DriverSync version) +; +;Installation Notes: +; Using Devcon: Type "devcon install ECHO_2.inf root\ECHO_2" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +ECHO_2.sys = 1,, + +;***************************************** +; ECHO Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +[Standard.NT$ARCH$] +%ECHO.DeviceDesc%=ECHO_Device, root\ECHO_2 + +[ECHO_Device.NT] +CopyFiles=Drivers_Dir + +[Drivers_Dir] +ECHO_2.sys + + +;-------------- Service installation +[ECHO_Device.NT.Services] +AddService = ECHO_2,%SPSVCINST_ASSOCSERVICE%, ECHO_Service_Inst + +; -------------- ECHO driver install sections +[ECHO_Service_Inst] +DisplayName = %ECHO.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\ECHO_2.sys + +; +;--- ECHO_Device Coinstaller installation ------ +; + +[DestinationDirs] +ECHO_Device_CoInstaller_CopyFiles = 11 + +[ECHO_Device.NT.CoInstallers] +AddReg=ECHO_Device_CoInstaller_AddReg +CopyFiles=ECHO_Device_CoInstaller_CopyFiles + +[ECHO_Device_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[ECHO_Device_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[ECHO_Device.NT.Wdf] +KmdfService = ECHO_2, ECHO_wdfsect + +[ECHO_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample ECHO Installation Disk #1 (DriverSync)" +ECHO.DeviceDesc = "Sample WDF ECHO Driver (DriverSync)" +ECHO.SVCDESC = "Sample WDF ECHO Service (DriverSync)" +ClassName = "Sample Device" diff --git a/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj new file mode 100644 index 00000000..a96b9b73 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{0F2B6094-D739-411B-B15C-D0ABD3ACF20E}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\echo_2.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\echo_2.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echo_2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echo_2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echo_2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echo_2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="device.c" /> + <ClCompile Include="driver.c" /> + <ClCompile Include="queue.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters new file mode 100644 index 00000000..2fac5833 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/echo_2.vcxproj.Filters @@ -0,0 +1,40 @@ +<?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>{5AF6C435-D6C0-4812-A1B9-A231D60FF6A3}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{52F80479-DCAD-49B9-9A2F-BB7363EEEBAF}</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>{1EC49F54-AC4E-447D-B4EA-B9859C16E917}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{9CFF80B0-15ED-408B-B629-91208E5966C3}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\echo_2.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\echo_2.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/kmdf/driver/DriverSync/queue.c b/general/echo/kmdf/driver/DriverSync/queue.c new file mode 100644 index 00000000..89d47fa2 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/queue.c @@ -0,0 +1,816 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.c + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, EchoQueueInitialize) +#pragma alloc_text (PAGE, EchoTimerCreate) +#endif + +LONG +EchoInterlockedIncrementFloor( + LONG volatile *Target, + LONG Floor + ) +/*++ + +Routine Description: + This routine will interlock increment a value only if the current value + is greater then the floor value. + + The volatile keyword on the Target pointer is absolutely required, otherwise + the compiler might rearrange pointer dereferences and that cannot happen. + +Arguments: + Target - the value that will be pontetially incrmented + + Floor - the value in which the Target value must be greater then if it is + to be incremented + +Return Value: + The current value of Target. To detect failure, the return value will be + <= Floor + 1. It is +1 because we cannot increment from the Floor value + itself, so Floor+1 cannot be a successful return value. + + --*/ +{ + LONG oldValue, currentValue; + + currentValue = *Target; + + do { + if (currentValue <= Floor) { + return currentValue; + } + + oldValue = currentValue; + + // + // currentValue will be the value that used to be Target if the exchange + // was made or its current value if the exchange was not made. + // + currentValue = InterlockedCompareExchange(Target, oldValue + 1, oldValue); + + // + // If oldValue == currentValue, then no one updated Target in between + // the deref at the top and the InterlockecCompareExchange afterward + // and we have successfully incremented the value and can exit the loop. + // + } while (oldValue != currentValue); + + // + // Since InterlockedIncrement returns the new incremented value of Target, + // we should do the same here. + // + return oldValue + 1; +} + +FORCEINLINE +LONG +EchoInterlockedIncrementGTZero( + IN OUT LONG volatile *Target + ) +/*++ + +Routine Description: + Increment the value only if it is currently > 0. + +Arguments: + Target - the value to be incremented. NOTE: the volatile keyword is requreid + +Return Value: + Upon success, a value > 0. Upon failure, a value <= 0. + + --*/ +{ + return EchoInterlockedIncrementFloor(Target, 0); +} + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE Device + ) +/*++ + +Routine Description: + + + The I/O dispatch callbacks for the frameworks device object + are configured in this function. + + A single default I/O Queue is configured for serial request + processing, and a driver context memory allocation is created + to hold our structure QUEUE_CONTEXT. + + This memory may be used by the driver automatically synchronized + by the Queue's presentation lock. + + The lifetime of this memory is tied to the lifetime of the I/O + Queue object, and we register an optional destructor callback + to release any private allocations, and/or resources. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS + +--*/ +{ + WDFQUEUE queue; + NTSTATUS status; + PQUEUE_CONTEXT queueContext; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + // + // Configure a default queue so that requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto + // other queues get dispatched here. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, + WdfIoQueueDispatchSequential + ); + + queueConfig.EvtIoRead = EchoEvtIoRead; + queueConfig.EvtIoWrite = EchoEvtIoWrite; + + // + // Fill in a callback for destroy, and our QUEUE_CONTEXT size + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, QUEUE_CONTEXT); + attributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy; + + status = WdfIoQueueCreate( + Device, + &queueConfig, + &attributes, + &queue + ); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); + return status; + } + + // Get our Driver Context memory from the returned Queue handle + queueContext = QueueGetContext(queue); + + queueContext->Buffer = NULL; + queueContext->Timer = NULL; + + queueContext->CurrentRequest = NULL; + queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST; + + // + // Create the SpinLock. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = queue; + + status = WdfSpinLockCreate(&attributes, &queueContext->SpinLock); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfSpinLockCreate failed 0x%x\n",status)); + return status; + } + + // + // Create the Queue timer + // + status = EchoTimerCreate(&queueContext->Timer, TIMER_PERIOD, queue); + if (!NT_SUCCESS(status)) { + KdPrint(("Error creating timer 0x%x\n",status)); + return status; + } + + return status; +} + + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* Timer, + IN ULONG Period, + IN WDFQUEUE Queue + ) +/*++ + +Routine Description: + + Subroutine to create periodic timer. + +Arguments: + + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status; + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + + PAGED_CODE(); + + // + // Create a WDFTIMER object + // + WDF_TIMER_CONFIG_INIT_PERIODIC(&timerConfig, EchoEvtTimerFunc, Period); + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + + // + // We are explicitly *not* serializing against the queue's lock, we will do + // that on our own. + // + timerAttributes.ParentObject = Queue; + + Status = WdfTimerCreate( + &timerConfig, + &timerAttributes, + Timer // Output handle + ); + + return Status; +} + + + +VOID +EchoEvtIoQueueContextDestroy( + WDFOBJECT Object +) +/*++ + +Routine Description: + + This is called when the Queue that our driver context memory + is associated with is destroyed. + +Arguments: + + Context - Context that's being freed. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(Object); + + // + // Release any resources pointed to in the queue context. + // + // The body of the queue context will be released after + // this callback handler returns + // + + // + // If Queue context has an I/O buffer, release it + // + if( queueContext->Buffer != NULL ) { + ExFreePool(queueContext->Buffer); + queueContext->Buffer = NULL; + } + + return; +} + +BOOLEAN +EchoDecrementRequestCancelOwnershipCount( + PREQUEST_CONTEXT RequestContext + ) +/*++ + +Routine Description: + Decrements the cancel ownership count for the request. When the count + reaches zero ownership has been acquired. + +Arguments: + RequestContext - the context which holds the count + +Return Value: + TRUE if the caller can complete the request, FALSE otherwise + + --*/ +{ + LONG result; + + result = InterlockedDecrement( + &RequestContext->CancelCompletionOwnershipCount + ); + + ASSERT(result >= 0); + + if (result == 0) { + return TRUE; + } + else { + return FALSE; + } +} + +BOOLEAN +EchoIncrementRequestCancelOwnershipCount( + PREQUEST_CONTEXT RequestContext + ) +/*++ + +Routine Description: + Attempts to increment the request ownership count so that it cannot be + completed until the count has been decremented + +Arguments: + RequestContext - context which holds the count + +Return Value: + TRUE if the count was incremented, FALSE otherwise + + --*/ +{ + // + // See comments in EchoInterlockedIncrementFloor as to why <= 1 is failure + // + if (EchoInterlockedIncrementGTZero( + &RequestContext->CancelCompletionOwnershipCount + ) <= 1) { + return FALSE; + } + else { + return TRUE; + } +} + +VOID +EchoEvtRequestCancel( + IN WDFREQUEST Request + ) +/*++ + +Routine Description: + + + Called when an I/O request is cancelled after the driver has marked + the request cancellable. This callback is not automatically synchronized + with the I/O callbacks since we have chosen not to use frameworks Device + or Queue level locking. + +Arguments: + + Request - Request being cancelled. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext; + PREQUEST_CONTEXT requestContext; + WDFQUEUE queue; + BOOLEAN completeRequest; + + KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request)); + + queue = WdfRequestGetIoQueue(Request); + + requestContext = RequestGetContext(Request); + queueContext = QueueGetContext(queue); + + // + // This book keeping is synchronized by the common + // Queue presentation lock which we are now acquiring + // + WdfSpinLockAcquire(queueContext->SpinLock); + + completeRequest = EchoDecrementRequestCancelOwnershipCount(requestContext); + + if (completeRequest) { + ASSERT(queueContext->CurrentRequest == Request); + queueContext->CurrentRequest = NULL; + } + else { + queueContext->CurrentStatus = STATUS_CANCELLED; + } + + WdfSpinLockRelease(queueContext->SpinLock); + + // + // Complete the request outside of holding any locks + // + if (completeRequest) { + WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L); + } + + return; +} + +VOID +EchoSetCurrentRequest( + WDFREQUEST Request, + WDFQUEUE Queue + ) +{ + NTSTATUS status; + PQUEUE_CONTEXT queueContext; + PREQUEST_CONTEXT requestContext; + + requestContext = RequestGetContext(Request); + queueContext = QueueGetContext(Queue); + + // + // Set the ownership count to one. When a caller wants to claim ownership, + // they will interlock decrement the count. When the count reaches zero, + // ownership has been acquired and the caller may complete the request. + // + requestContext->CancelCompletionOwnershipCount = 1; + + // + // Defer the completion to another thread from the timer dpc + // + WdfSpinLockAcquire(queueContext->SpinLock); + + queueContext->CurrentRequest = Request; + queueContext->CurrentStatus = STATUS_SUCCESS; + + // + // Set the cancel routine under the lock, otherwise if we set it outside + // of the lock, the timer could run and attempt to mark the request + // uncancelable before we can mark it cancelable on this thread. Use + // WdfRequestMarkCancelableEx here to prevent to deadlock with ourselves + // (cancel routine tries to acquire the queue object lock). + // + status = WdfRequestMarkCancelableEx(Request, EchoEvtRequestCancel); + if (!NT_SUCCESS(status)) { + queueContext->CurrentRequest = NULL; + } + + WdfSpinLockRelease(queueContext->SpinLock); + + // + // Complete the request with an error when unable to mark it cancelable. + // + if (!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(Request, status, 0L); + } +} + +VOID +EchoEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_READ request. + It will copy the content from the queue-context buffer to the request buffer. + If the driver hasn't received any write request earlier, the read returns zero. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + WDFMEMORY memory; + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + // + // No data to read + // + if( (queueContext->Buffer == NULL) ) { + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L); + return; + } + + _Analysis_assume_(queueContext->Length > 0); + + // + // Read what we have + // + if( queueContext->Length < Length ) { + Length = queueContext->Length; + } + + // + // Get the request memory + // + Status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n",Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestCompleteWithInformation(Request, Status, 0L); + return; + } + + // Copy the memory out + Status = WdfMemoryCopyFromBuffer( memory, // destination + 0, // offset into the destination memory + queueContext->Buffer, + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status)); + WdfRequestComplete(Request, Status); + return; + } + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + // + // Mark the request is cancelable. This must be the last thing we do because + // the cancel routine can run immediately after we set it. This means that + // CurrentRequest and CurrentStatus must be initialized before we mark the + // request cancelable. + // + EchoSetCurrentRequest(Request, Queue); + + return; +} + +VOID +EchoEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is invoked when the framework receives IRP_MJ_WRITE request. + This routine allocates memory buffer, copies the data from the request to it, + and stores the buffer pointer in the queue-context with the length variable + representing the buffers length. The actual completion of the request + is defered to the periodic timer dpc. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + WDFMEMORY memory; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + + if( Length > MAX_WRITE_LENGTH ) { + KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", + Length,MAX_WRITE_LENGTH)); + WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); + return; + } + + // Get the memory buffer + Status = WdfRequestRetrieveInputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n", + Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestComplete(Request, Status); + return; + } + + // Release previous buffer if set + if( queueContext->Buffer != NULL ) { + ExFreePool(queueContext->Buffer); + queueContext->Buffer = NULL; + queueContext->Length = 0L; + } + + queueContext->Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, 'sam1'); + if( queueContext->Buffer == NULL ) { + KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n",Length)); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return; + } + + + // Copy the memory in + Status = WdfMemoryCopyToBuffer( memory, + 0, // offset into the source memory + queueContext->Buffer, + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status)); + WdfVerifierDbgBreakPoint(); + ExFreePool(queueContext->Buffer); + queueContext->Buffer = NULL; + queueContext->Length = 0L; + WdfRequestComplete(Request, Status); + return; + } + + queueContext->Length = (ULONG) Length; + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + + // + // Mark the request is cancelable. This must be the last thing we do because + // the cancel routine can run immediately after we set it. This means that + // CurrentRequest and CurrentStatus must be initialized before we mark the + // request cancelable. + // + EchoSetCurrentRequest(Request, Queue); + + return; +} + + +VOID +EchoEvtTimerFunc( + IN WDFTIMER Timer + ) +/*++ + +Routine Description: + + This is the TimerDPC the driver sets up to complete requests. + This function is registered when the WDFTIMER object is created. + + This function does *NOT* automatically synchronize with the I/O Queue + callbacks and cancel routine, we must do it ourself in the routine. + +Arguments: + + Timer - Handle to a framework Timer object. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + WDFREQUEST request; + WDFQUEUE queue; + PQUEUE_CONTEXT queueContext; + PREQUEST_CONTEXT requestContext; + BOOLEAN cancel, completeRequest; + + // + // Default to failure. status is initialized so that the compiler does not + // think we are using an uninitialized value when completing the request. + // + status = STATUS_UNSUCCESSFUL; + cancel = FALSE; + completeRequest = FALSE; + + queue = (WDFQUEUE) WdfTimerGetParentObject(Timer); + queueContext = QueueGetContext(queue); + requestContext = NULL; + + // + // We must synchronize with the cancel routine which will be taking the + // request out of the context under this lock. + // + WdfSpinLockAcquire(queueContext->SpinLock); + + request = queueContext->CurrentRequest; + + if (request != NULL) { + requestContext = RequestGetContext(request); + + if (EchoIncrementRequestCancelOwnershipCount(requestContext)) { + cancel = TRUE; + } + else { + // + // What has happened is that the cancel routine has executed and + // has already claimed cancel ownership of the request, but has not + // yet acquired the object lock and cleared the CurrentRequest field + // in queueContext. In this case, do nothing and let the cancel + // routine run to completion and complete the request. + // + } + } + + WdfSpinLockRelease(queueContext->SpinLock); + + // + // If we could not claim cancel ownership, we are done. + // + if (cancel == FALSE) { + return; + } + + // + // The request handle and requestContext are valid until we release + // the cancel ownership count we already acquired. + // + status = WdfRequestUnmarkCancelable(request); + if (status != STATUS_CANCELLED) { + KdPrint(("CustomTimerDPC successfully cleared cancel routine on " + "request 0x%p, Status 0x%x \n", request,status)); + + // + // Since we successfully removed the cancel routine (and we are not + // currently racing with it), there is no need to use an interlocked + // decrement to lower the cancel ownership count. + // + + // + // 2 is the initial count we set when we initialized CancelCompletionOwnershipCount + // plus the call to EchoIncrementRequestCancelOwnershipCount() + // + ASSERT(requestContext->CancelCompletionOwnershipCount == 2); + requestContext->CancelCompletionOwnershipCount -=2; + + completeRequest = TRUE; + } + else { + completeRequest = EchoDecrementRequestCancelOwnershipCount( + requestContext + ); + + if (completeRequest) { + KdPrint( + ("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, but " + "claimed completion ownership\n", request)); + } + else { + KdPrint( + ("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not " + "completing", request)); + } + } + + if (completeRequest) { + KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", + request,status)); + + // + // Clear the current request out of the queue context and complete + // the request. + // + WdfSpinLockAcquire(queueContext->SpinLock); + queueContext->CurrentRequest = NULL; + status = queueContext->CurrentStatus; + WdfSpinLockRelease(queueContext->SpinLock); + + WdfRequestComplete(request, status); + } +} + diff --git a/general/echo/kmdf/driver/DriverSync/queue.h b/general/echo/kmdf/driver/DriverSync/queue.h new file mode 100644 index 00000000..1985a6c7 --- /dev/null +++ b/general/echo/kmdf/driver/DriverSync/queue.h @@ -0,0 +1,67 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +// Set max write length for testing +#define MAX_WRITE_LENGTH 1024*40 + +// Set timer period in ms +#define TIMER_PERIOD 1000*10 + +// +// This is the context that can be placed per queue +// and would contain per queue information. +// +typedef struct _QUEUE_CONTEXT { + + // Here we allocate a buffer from a test write so it can be read back + PVOID Buffer; + ULONG Length; + + // Timer DPC for this queue + WDFTIMER Timer; + + // Virtual I/O + WDFREQUEST CurrentRequest; + NTSTATUS CurrentStatus; + + // SpinLock to synchronize I/O callbacks. + WDFSPINLOCK SpinLock; + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE hDevice + ); + +EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy; + +// +// Events from the IoQueue object +// +EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel; +EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite; + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* pTimer, + IN ULONG Period, + IN WDFQUEUE Queue + ); + +EVT_WDF_TIMER EchoEvtTimerFunc; diff --git a/general/echo/kmdf/exe/echoapp.cpp b/general/echo/kmdf/exe/echoapp.cpp new file mode 100644 index 00000000..9649a407 --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.cpp @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ioctl.cpp + +Abstract: + + A simple asynch test for usb driver. + + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include "public.h" + +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE (40*1024) + +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +#define MAX_DEVPATH_LENGTH 256 + +BOOLEAN G_PerformAsyncIo; +BOOLEAN G_LimitedLoops; +ULONG G_AsyncIoLoopsNum; +CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; + + +ULONG +AsyncIo( + PVOID ThreadParameter + ); + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ); + + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE th1 = NULL; + BOOLEAN result = TRUE; + + + if (argc > 1) { + if(!_strnicmp (argv[1], "-Async", 6) ) { + G_PerformAsyncIo = TRUE; + if (argc > 2) { + G_AsyncIoLoopsNum = atoi(argv[2]); + G_LimitedLoops = TRUE; + } + else { + G_LimitedLoops = FALSE; + } + + } else { + printf("Usage:\n"); + printf(" Echoapp.exe --- Send single write and read request synchronously\n"); + printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); + printf(" Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\n"); + printf("Exit the app anytime by pressing Ctrl-C\n"); + result = FALSE; + goto exit; + } + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_ECHO, + G_DevicePath, + sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) + { + result = FALSE; + goto exit; + } + + printf("DevicePath: %s\n", G_DevicePath); + + hDevice = CreateFile(G_DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + result = FALSE; + goto exit; + } + + printf("Opened device successfully\n"); + + if(G_PerformAsyncIo) { + + printf("Starting AsyncIo\n"); + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + result = FALSE; + goto exit; + } + + // + // Use this thread for peforming write. + // + result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); + + }else { + // + // Write pattern buffers and read them back, then verify them + // + result = PerformWriteReadTest(hDevice, 512); + if(!result) { + goto exit; + } + + result = PerformWriteReadTest(hDevice, 30*1024); + if(!result) { + goto exit; + } + + } + +exit: + + if (th1 != NULL) { + WaitForSingleObject(th1, INFINITE); + CloseHandle(th1); + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + return ((result == TRUE) ? 0 : 1); + +} + +PUCHAR +CreatePatternBuffer( + IN ULONG Length + ) +{ + unsigned int i; + PUCHAR p, pBuf; + + pBuf = (PUCHAR)malloc(Length); + if( pBuf == NULL ) { + printf("Could not allocate %d byte buffer\n",Length); + return NULL; + } + + p = pBuf; + + for(i=0; i < Length; i++ ) { + *p = (UCHAR)i; + p++; + } + + return pBuf; +} + +BOOLEAN +VerifyPatternBuffer( + _In_reads_bytes_(Length) PUCHAR pBuffer, + _In_ ULONG Length + ) +{ + unsigned int i; + PUCHAR p = pBuffer; + + for( i=0; i < Length; i++ ) { + + if( *p != (UCHAR)(i & 0xFF) ) { + printf("Pattern changed. SB 0x%x, Is 0x%x\n", + (UCHAR)(i & 0xFF), *p); + return FALSE; + } + + p++; + } + + return TRUE; +} + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ) +/* +*/ +{ + ULONG bytesReturned =0; + PUCHAR WriteBuffer = NULL, + ReadBuffer = NULL; + BOOLEAN result = TRUE; + + WriteBuffer = CreatePatternBuffer(TestLength); + if( WriteBuffer == NULL ) { + + result = FALSE; + goto Cleanup; + } + + ReadBuffer = (PUCHAR)malloc(TestLength); + if( ReadBuffer == NULL ) { + + printf("PerformWriteReadTest: Could not allocate %d " + "bytes ReadBuffer\n",TestLength); + + result = FALSE; + goto Cleanup; + + } + + // + // Write the pattern to the device + // + bytesReturned = 0; + + if (!WriteFile ( hDevice, + WriteBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: WriteFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes written is not test length! Written %d, " + "SB %d\n",bytesReturned, TestLength); + + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Written successfully\n", + bytesReturned); + } + + bytesReturned = 0; + + if ( !ReadFile (hDevice, + ReadBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: ReadFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes Read is not test length! Read %d, " + "SB %d\n",bytesReturned, TestLength); + + // + // Note: Is this a Failure Case?? + // + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Read successfully\n",bytesReturned); + } + + // + // Now compare + // + if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { + + printf("Verify failed\n"); + + result = FALSE; + goto Cleanup; + } + + printf("Pattern Verified successfully\n"); + +Cleanup: + + // + // Free WriteBuffer if non NULL. + // + if (WriteBuffer) { + free (WriteBuffer); + } + + // + // Free ReadBuffer if non NULL + // + if (ReadBuffer) { + free (ReadBuffer); + } + + return result; +} + + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG numberOfBytesTransferred; + OVERLAPPED *completedOv; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG_PTR key; + ULONG error; + BOOLEAN result = TRUE; + ULONG maxPendingRequests = NUM_ASYNCH_IO; + ULONG remainingRequestsToSend = 0; + ULONG remainingRequestsToReceive = 0; + + hDevice = CreateFile(G_DevicePath, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + result = FALSE; + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + result = FALSE; + goto Error; + } + + // + // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any + // time (whichever is less) + // + if (G_LimitedLoops == TRUE) { + remainingRequestsToReceive = G_AsyncIoLoopsNum; + if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { + // + // After we send the initial NUM_ASYNCH_IO, we will have additional + // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send + // + maxPendingRequests = NUM_ASYNCH_IO; + remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; + } + else { + maxPendingRequests = G_AsyncIoLoopsNum; + remainingRequestsToSend = 0; + + } + } + + pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + result = FALSE; + goto Error; + } + + buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + result = FALSE; + goto Error; + } + + ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); + ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < maxPendingRequests; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Read failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Write failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + result = FALSE; + goto Error; + } + + // + // Read successfully completed. If we're doing unlimited I/Os then Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + printf("Number of bytes read by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%dth Read failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + + printf("%dth write failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + +Error: + if(hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if(hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if(buf) { + free(buf); + } + if(pOvList) { + free(pOvList); + } + + return (ULONG)result; + +} + + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ) +{ + HDEVINFO HardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL; + ULONG Length, RequiredLength = 0; + BOOL bResult; + HRESULT hr; + + HardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed!\n"); + return FALSE; + } + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, + 0, + InterfaceGuid, + 0, + &DeviceInterfaceData); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + printf("SetupDiEnumDeviceInterfaces failed.\n"); + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + return FALSE; + } + + SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + NULL, + 0, + &RequiredLength, + NULL + ); + + DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength); + + if (DeviceInterfaceDetailData == NULL) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Failed to allocate memory.\n"); + return FALSE; + } + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Length = RequiredLength; + + bResult = SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + Length, + &RequiredLength, + NULL); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); + LocalFree(DeviceInterfaceDetailData); + LocalFree(lpMsgBuf); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath) ; + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces + LocalFree(DeviceInterfaceDetailData); + + return ( !FAILED(hr) ); // Result depends on StringCchCopy() +} + diff --git a/general/echo/kmdf/exe/echoapp.vcxproj b/general/echo/kmdf/exe/echoapp.vcxproj new file mode 100644 index 00000000..11b3eb4c --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.vcxproj @@ -0,0 +1,171 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{684264A6-91C1-4046-AD23-BD823E13EB60}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{C342DB0F-934F-4A0A-90A7-02650E906732}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/kmdf/exe/echoapp.vcxproj.Filters b/general/echo/kmdf/exe/echoapp.vcxproj.Filters new file mode 100644 index 00000000..7e14cf46 --- /dev/null +++ b/general/echo/kmdf/exe/echoapp.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{A120A502-9177-430F-BAEB-BBE51661EDDD}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{967C5907-C8A7-46F3-B2B7-E3A0BFF110EE}</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>{53BEED44-2F74-4E8F-B7B8-D0BDDB11BEB6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/kmdf/exe/public.h b/general/echo/kmdf/exe/public.h new file mode 100644 index 00000000..d632951d --- /dev/null +++ b/general/echo/kmdf/exe/public.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + + +Environment: + + user and kernel + +--*/ + +#define WHILE(a) \ +__pragma(warning(suppress:4127)) while(a) + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + diff --git a/general/echo/kmdf/kmdfecho.sln b/general/echo/kmdf/kmdfecho.sln new file mode 100644 index 00000000..b9c25c6c --- /dev/null +++ b/general/echo/kmdf/kmdfecho.sln @@ -0,0 +1,63 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{1DD2F948-0799-49E3-A880-35A6215F8479}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{B52DE63E-ED02-41DD-9DAB-53ACE0286663}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{AE9E09B7-46C1-4AA3-9411-F125D9188EFD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DriverSync", "DriverSync", "{F01C6D5C-982E-4AE2-8DDC-0666F3905135}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{684264A6-91C1-4046-AD23-BD823E13EB60}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{C8F9A776-3675-459B-A0A3-BA17D003C70B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo_2", "driver\DriverSync\echo_2.vcxproj", "{968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.ActiveCfg = Debug|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|Win32.Build.0 = Debug|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.ActiveCfg = Release|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|Win32.Build.0 = Release|Win32 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.ActiveCfg = Debug|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Debug|x64.Build.0 = Debug|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.ActiveCfg = Release|x64 + {684264A6-91C1-4046-AD23-BD823E13EB60}.Release|x64.Build.0 = Release|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.ActiveCfg = Debug|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|Win32.Build.0 = Debug|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.ActiveCfg = Release|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|Win32.Build.0 = Release|Win32 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.ActiveCfg = Debug|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Debug|x64.Build.0 = Debug|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.ActiveCfg = Release|x64 + {C8F9A776-3675-459B-A0A3-BA17D003C70B}.Release|x64.Build.0 = Release|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|Win32.Build.0 = Debug|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.ActiveCfg = Release|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|Win32.Build.0 = Release|Win32 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.ActiveCfg = Debug|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Debug|x64.Build.0 = Debug|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.ActiveCfg = Release|x64 + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {684264A6-91C1-4046-AD23-BD823E13EB60} = {1DD2F948-0799-49E3-A880-35A6215F8479} + {C8F9A776-3675-459B-A0A3-BA17D003C70B} = {B52DE63E-ED02-41DD-9DAB-53ACE0286663} + {968447B1-9A4F-4D2D-B81B-7BCB9240F5E3} = {F01C6D5C-982E-4AE2-8DDC-0666F3905135} + {B52DE63E-ED02-41DD-9DAB-53ACE0286663} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} + {F01C6D5C-982E-4AE2-8DDC-0666F3905135} = {AE9E09B7-46C1-4AA3-9411-F125D9188EFD} + EndGlobalSection +EndGlobal diff --git a/general/echo/umdf/Comsup.cpp b/general/echo/umdf/Comsup.cpp new file mode 100644 index 00000000..fd298470 --- /dev/null +++ b/general/echo/umdf/Comsup.cpp @@ -0,0 +1,344 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.cpp + +Abstract: + + This module contains implementations for the functions and methods + used for providing COM support. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "comsup.tmh" + +// +// Implementation of CUnknown methods. +// + +CUnknown::CUnknown( + VOID + ) : m_ReferenceCount(1) +/*++ + + Routine Description: + + Constructor for an instance of the CUnknown class. This simply initializes + the reference count of the object to 1. The caller is expected to + call Release() if it wants to delete the object once it has been allocated. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + // do nothing. +} + +HRESULT +STDMETHODCALLTYPE +CUnknown::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method provides the basic support for query interface on CUnknown. + If the interface requested is IUnknown it references the object and + returns an interface pointer. Otherwise it returns an error. + + Arguments: + + InterfaceId - the IID being requested + + Object - a location to store the interface pointer to return. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) + { + *Object = QueryIUnknown(); + return S_OK; + } + else + { + *Object = NULL; + return E_NOINTERFACE; + } +} + +IUnknown * +CUnknown::QueryIUnknown( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IUnknown interface. + + This allows other methods to convert a CUnknown pointer into an IUnknown + pointer without a typecast and without calling QueryInterface and dealing + with the return value. + + Arguments: + + None + + Return Value: + + A pointer to the object's IUnknown interface. + +--*/ +{ + AddRef(); + return static_cast<IUnknown *>(this); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::AddRef( + VOID + ) +/*++ + + Routine Description: + + This method adds one to the object's reference count. + + Arguments: + + None + + Return Value: + + The new reference count. The caller should only use this for debugging + as the object's actual reference count can change while the caller + examines the return value. + +--*/ +{ + return InterlockedIncrement(&m_ReferenceCount); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::Release( + VOID + ) +/*++ + + Routine Description: + + This method subtracts one to the object's reference count. If the count + goes to zero, this method deletes the object. + + Arguments: + + None + + Return Value: + + The new reference count. If the caller uses this value it should only be + to check for zero (i.e. this call caused or will cause deletion) or + non-zero (i.e. some other call may have caused deletion, but this one + didn't). + +--*/ +{ + ULONG count = InterlockedDecrement(&m_ReferenceCount); + + if (count == 0) + { + delete this; + } + return count; +} + +// +// Implementation of CClassFactory methods. +// + +// +// Define storage for the factory's static lock count variable. +// + +LONG CClassFactory::s_LockCount = 0; + +IClassFactory * +CClassFactory::QueryIClassFactory( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IClassFactory interface. + + This allows other methods to convert a CClassFactory pointer into an + IClassFactory pointer without a typecast and without dealing with the + return value QueryInterface. + + Arguments: + + None + + Return Value: + + A referenced pointer to the object's IClassFactory interface. + +--*/ +{ + AddRef(); + return static_cast<IClassFactory *>(this); +} + +HRESULT +CClassFactory::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method attempts to retrieve the requested interface from the object. + + If the interface is found then the reference count on that interface (and + thus the object itself) is incremented. + + Arguments: + + InterfaceId - the interface the caller is requesting. + + Object - a location to store the interface pointer. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + // + // This class only supports IClassFactory so check for that. + // + + if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) + { + *Object = QueryIClassFactory(); + return S_OK; + } + else + { + // + // See if the base class supports the interface. + // + + return CUnknown::QueryInterface(InterfaceId, Object); + } +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::CreateInstance( + _In_opt_ IUnknown * /* OuterObject */, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This COM method is the factory routine - it creates instances of the driver + callback class and returns the specified interface on them. + + Arguments: + + OuterObject - only used for aggregation, which our driver callback class + does not support. + + InterfaceId - the interface ID the caller would like to get from our + new object. + + Object - a location to store the referenced interface pointer to the new + object. + + Return Value: + + Status. + +--*/ +{ + HRESULT hr; + + PCMyDriver driver; + + *Object = NULL; + + hr = CMyDriver::CreateInstance(&driver); + + if (SUCCEEDED(hr)) + { + hr = driver->QueryInterface(InterfaceId, Object); + driver->Release(); + } + + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::LockServer( + _In_ BOOL Lock + ) +/*++ + + Routine Description: + + This COM method can be used to keep the DLL in memory. However since the + driver's DllCanUnloadNow function always returns false, this has little + effect. Still it tracks the number of lock and unlock operations. + + Arguments: + + Lock - Whether the caller wants to lock or unlock the "server" + + Return Value: + + S_OK + +--*/ +{ + if (Lock) + { + InterlockedIncrement(&s_LockCount); + } + else + { + InterlockedDecrement(&s_LockCount); + } + return S_OK; +} + diff --git a/general/echo/umdf/Comsup.h b/general/echo/umdf/Comsup.h new file mode 100644 index 00000000..b96fd982 --- /dev/null +++ b/general/echo/umdf/Comsup.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.h + +Abstract: + + This module contains classes and functions use for providing COM support + code. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Forward type declarations. They are here rather than in internal.h as +// you only need them if you choose to use these support classes. +// + +typedef class CUnknown *PCUnknown; +typedef class CClassFactory *PCClassFactory; + +// +// Base class to implement IUnknown. You can choose to derive your COM +// classes from this class, or simply implement IUnknown in each of your +// classes. +// + +class CUnknown : public IUnknown +{ + +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The reference count for this object. Initialized to 1 in the + // constructor. + // + + LONG m_ReferenceCount; + +// +// Protected data members and methods. These are accessible by the subclasses +// but not by other classes. +// +protected: + + // + // The constructor and destructor are protected to ensure that only the + // subclasses of CUnknown can create and destroy instances. + // + + CUnknown( + VOID + ); + + // + // The destructor MUST be virtual. Since any instance of a CUnknown + // derived class should only be deleted from within CUnknown::Release, + // the destructor MUST be virtual or only CUnknown::~CUnknown will get + // invoked on deletion. + // + // If you see that your CMyDevice specific destructor is never being + // called, make sure you haven't deleted the virtual destructor here. + // + + virtual + ~CUnknown( + VOID + ) + { + // Do nothing + } + +// +// Public Methods. These are accessible by any class. +// +public: + + IUnknown * + QueryIUnknown( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ); + + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ); + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; + +// +// Class factory support class. Create an instance of this from your +// DllGetClassObject method and modify the implementation to create +// an instance of your driver event handler class. +// + +class CClassFactory : public CUnknown, public IClassFactory +{ +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The lock count. This is shared across all instances of IClassFactory + // and can be queried through the public IsLocked method. + // + + static LONG s_LockCount; + +// +// Public Methods. These are accessible by any class. +// +public: + + IClassFactory * + QueryIClassFactory( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IClassFactory methods. + // + + virtual + HRESULT + STDMETHODCALLTYPE + CreateInstance( + _In_opt_ IUnknown *OuterObject, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + virtual + HRESULT + STDMETHODCALLTYPE + LockServer( + _In_ BOOL Lock + ); +}; diff --git a/general/echo/umdf/Device.cpp b/general/echo/umdf/Device.cpp new file mode 100644 index 00000000..77110e8e --- /dev/null +++ b/general/echo/umdf/Device.cpp @@ -0,0 +1,415 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the sample driver's + device callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "initguid.h" + +#include "device.tmh" + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + +HRESULT +CMyDevice::CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit, + _Out_ PCMyDevice *Device + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + PCMyDevice device; + HRESULT hr; + + // + // Allocate a new instance of the device class. + // + + device = new CMyDevice(); + + if (NULL == device) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + hr = device->Initialize(FxDriver, FxDeviceInit); + + if (SUCCEEDED(hr)) + { + *Device = device; + } + else + { + device->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver * FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + + Return Value: + + status. + +--*/ +{ + IWDFDevice *fxDevice = NULL; + IWDFDeviceInitialize2 *fxDeviceInit2; + HRESULT hr; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set no locking unless you need an automatic callbacks synchronization + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // TODO: If you're writing a filter driver then indicate that here. + // + // FxDeviceInit->SetFilter(); + // + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // Set retrieval mode to direct I/O. This needs to be done before the call + // to CreateDevice. + // + hr = FxDeviceInit->QueryInterface(IID_PPV_ARGS(&fxDeviceInit2)); + + if (SUCCEEDED(hr)) + { + // + // WdfDeviceIoBufferedOrDirect for read/write and ioctrl operations. + // UMDF defaults to direct-I/O when the device is not running in a shared + // wudfhost process, and it defaults to buffered-I/O otherwise. Direct I/O + // is not allowed when the device is pooled. + // + // + fxDeviceInit2->SetIoTypePreference(WdfDeviceIoBufferRetrievalDeferred, + WdfDeviceIoBufferedOrDirect, + WdfDeviceIoBufferedOrDirect); + + SAFE_RELEASE(fxDeviceInit2); + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + { + IUnknown *unknown = this->QueryIUnknown(); + + hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); + + unknown->Release(); + } + } + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + + // + // Drop the reference we got from CreateDevice. Since this object + // is partnered with the framework object they have the same + // lifespan - there is no need for an additional reference. + // + + fxDevice->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + PCMyQueue defaultQueue; + + HRESULT hr; + + hr = CMyQueue::CreateInstance(m_FxDevice, &defaultQueue); + + if (FAILED(hr)) + { + return hr; + } + + hr = defaultQueue->Configure(); + + if (SUCCEEDED(hr)) + { + // + // In case of success store defaultQueue in our member + // The reference is transferred to m_DefaultQueue + // + + m_Queue = defaultQueue; + } + else + { + // + // In case of failure release the reference + // + + defaultQueue->Release(); + } + + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_ECHO, + NULL); + } + + return hr; +} + +HRESULT +CMyDevice::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Since the sample driver doesn't support any of the device events, this + method simply calls the base class's BaseQueryInterface. + + If the sample is extended to include device event interfaces then this + method must be changed to check the IID and return pointers to them as + appropriate. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + HRESULT hr; + + if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackSelfManagedIo))) { + *Object = QueryIPnpCallbackSelfManagedIo(); + hr = S_OK; + } else { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +HRESULT +CMyDevice::OnSelfManagedIoInit( + _In_ IWDFDevice * pWdfDevice + ) +/*++ + + Routine Description: + + This method is called to allow driver to initialize any resources + that driver might need to process I/O. + + Echo driver needs a thread to process completions. We initialize + this thread here + + Arguments: + + pWdfDevice - framework device object for which to initialze resources + + Return Value: + + S_OK in case of success + HRESULT correponding to error returned by CreateThread, in case of failure + +--*/ +{ + HRESULT hr = S_OK; + + UNREFERENCED_PARAMETER(pWdfDevice); + + + m_ThreadHandle = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + CMyQueue::CompletionThread, // Thread Func + (LPVOID)m_Queue, // Arg to Thread Func is Queue + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (m_ThreadHandle == NULL) { + hr = HRESULT_FROM_WIN32(GetLastError()); + } + + return hr; +} + +void +CMyDevice::OnSelfManagedIoCleanup( + _In_ IWDFDevice * pWdfDevice + ) +/*++ + + Routine Description: + + This method is called to allow driver to cleanup any resources + that driver allocated to process I/O. + + It is critical that, in this routine driver wait for all of the + threads which it created to exit. Otherwise those threads could + continue to execute when framework unloads the driver which + would lead to a crash. + + Echo driver created a thread to handle completions. We wait for + that thread to exit in this routine + + Arguments: + + pWdfDevice - framework device object for which to cleanup resources + + Return Value: + + None + +--*/ +{ + // + // Kill the thread and + // wait for the thread to die. + // + + UNREFERENCED_PARAMETER(pWdfDevice); + + if (m_ThreadHandle) { + + // + // Ask queue to set terminate flag which will make + // the thread exit + // + m_Queue->SetExitThread(); + + // + // Wait for the thread to exit + // + + WaitForSingleObject(m_ThreadHandle, INFINITE); + + // + // Close the thread handle + // + + CloseHandle(m_ThreadHandle); + m_ThreadHandle = NULL; + } + + // + // Release the reference we took on the queue callback object + // to keep it alive until the thread exits + // + + SAFE_RELEASE(m_Queue); +} + diff --git a/general/echo/umdf/Device.h b/general/echo/umdf/Device.h new file mode 100644 index 00000000..70147c11 --- /dev/null +++ b/general/echo/umdf/Device.h @@ -0,0 +1,217 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF Echo sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#include "queue.h" + +// +// Class for the iotrace driver. +// + +class CMyDevice : + public CUnknown, + public IPnpCallbackSelfManagedIo +{ + +// +// Private data members. +// +private: + + IWDFDevice *m_FxDevice; + + // + // Completion Thread handle used by queue callback object + // + HANDLE m_ThreadHandle; + + // + // Our queue callback object + // Strong reference - since we pass it to the thread we create + // + CMyQueue *m_Queue; + +// +// Private methods. +// + +private: + + CMyDevice( + VOID + ) + { + m_FxDevice = NULL; + } + + HRESULT + Initialize( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + IPnpCallbackSelfManagedIo * + QueryIPnpCallbackSelfManagedIo( + VOID + ) + { + AddRef(); + return static_cast<IPnpCallbackSelfManagedIo *>(this); + } + + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit, + _Out_ PCMyDevice *Device + ); + + HRESULT + Configure( + VOID + ); + +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IPnpCallbackSelfManagedIo methods + // + + // + // We implement this interface to create and tear down + // our completion thread + // + // It is critical that we wait for all the threads we create + // to exit during OnSelfManagedIoCleanup, otherwise thread + // may continue to execute when framework unloads the driver, + // leading to a crash + // + // We don't manage any I/O separate from the queue, so apart + // from OnSelfManagedIoInit and OnSelfManagedIoCleanup, other + // methods have token implementations + // + + virtual + void + STDMETHODCALLTYPE + OnSelfManagedIoCleanup( + _In_ IWDFDevice * pWdfDevice + ); + + virtual + void + STDMETHODCALLTYPE + OnSelfManagedIoFlush( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoInit( + _In_ IWDFDevice * pWdfDevice + ); + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoSuspend( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoRestart( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnSelfManagedIoStop( + _In_ IWDFDevice * pWdfDevice + ) + { + UNREFERENCED_PARAMETER( pWdfDevice ); + + return S_OK; + } +}; diff --git a/general/echo/umdf/Driver.cpp b/general/echo/umdf/Driver.cpp new file mode 100644 index 00000000..1428a08a --- /dev/null +++ b/general/echo/umdf/Driver.cpp @@ -0,0 +1,220 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +HRESULT +CMyDriver::CreateInstance( + _Out_ PCMyDriver *Driver + ) +/*++ + + Routine Description: + + This static method is invoked in order to create and initialize a new + instance of the driver class. The caller should arrange for the object + to be released when it is no longer in use. + + Arguments: + + Driver - a location to store a referenced pointer to the new instance + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ +{ + PCMyDriver driver; + HRESULT hr; + + // + // Allocate the callback object. + // + + driver = new CMyDriver(); + + if (NULL == driver) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the callback object. + // + + hr = driver->Initialize(); + + if (SUCCEEDED(hr)) + { + // + // Store a pointer to the new, initialized object in the output + // parameter. + // + + *Driver = driver; + } + else + { + + // + // Release the reference on the driver object to get it to delete + // itself. + // + + driver->Release(); + } + + return hr; +} + +HRESULT +CMyDriver::Initialize( + VOID + ) +/*++ + + Routine Description: + + This method is called to initialize a newly created driver callback object + before it is returned to the creator. Unlike the constructor, the + Initialize method contains operations which could potentially fail. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + return S_OK; +} + +HRESULT +CMyDriver::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Interface + ) +/*++ + + Routine Description: + + This method returns a pointer to the requested interface on the callback + object.. + + Arguments: + + InterfaceId - the IID of the interface to query/reference + + Interface - a location to store the interface pointer. + + Return Value: + + S_OK if the interface is supported. + E_NOINTERFACE if it is not supported. + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) + { + *Interface = QueryIDriverEntry(); + return S_OK; + } + else + { + return CUnknown::QueryInterface(InterfaceId, Interface); + } +} + +HRESULT +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + HRESULT hr; + + PCMyDevice device = NULL; + + // + // TODO: Do any per-device initialization (reading settings from the + // registry for example) that's necessary before creating your + // device callback object here. Otherwise you can leave such + // initialization to the initialization of the device event + // handler. + // + + // + // Create a new instance of our device callback object + // + + hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); + + // + // TODO: Change any per-device settings that the object exposes before + // calling Configure to let it complete its initialization. + // + + // + // If that succeeded then call the device's construct method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference on the device callback object now that it's been + // associated with an fx device object. + // + + if (NULL != device) + { + device->Release(); + } + + return hr; +} diff --git a/general/echo/umdf/Driver.h b/general/echo/umdf/Driver.h new file mode 100644 index 00000000..643ea5a5 --- /dev/null +++ b/general/echo/umdf/Driver.h @@ -0,0 +1,149 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +class CMyDriver : public CUnknown, public IDriverEntry +{ +// +// Private data members. +// +private: + +// +// Private methods. +// +private: + + // + // Returns a refernced pointer to the IDriverEntry interface. + // + + IDriverEntry * + QueryIDriverEntry( + VOID + ) + { + AddRef(); + return static_cast<IDriverEntry*>(this); + } + + HRESULT + Initialize( + VOID + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _Out_ PCMyDriver *Driver + ); + +// +// COM methods +// +public: + + // + // IDriverEntry methods + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnInitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + virtual + VOID + STDMETHODCALLTYPE + OnDeinitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return; + } + + // + // IUnknown methods. + // + // We have to implement basic ones here that redirect to the + // base class becuase of the multiple inheritance. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; diff --git a/general/echo/umdf/Echo.rc b/general/echo/umdf/Echo.rc new file mode 100644 index 00000000..2a26d85c --- /dev/null +++ b/general/echo/umdf/Echo.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// Echo.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Echo User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "UMDFEcho" +#define VER_ORIGINALFILENAME_STR "UMDFEcho.dll" + +#include "common.ver" diff --git a/general/echo/umdf/Queue.cpp b/general/echo/umdf/Queue.cpp new file mode 100644 index 00000000..f366fe31 --- /dev/null +++ b/general/echo/umdf/Queue.cpp @@ -0,0 +1,545 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + + +#include "internal.h" + +// +// IUnknown implementation +// + +// +// Queue destructor. +// Free up the buffer, wait for thread to terminate and +// delete critical section. +// + + +CMyQueue::~CMyQueue( + VOID + ) +/*++ + +Routine Description: + + + IUnknown implementation of Release + +Arguments: + + +Return Value: + + ULONG (reference count after Release) + +--*/ +{ + if (m_Buffer) { + delete [] m_Buffer; + } + + if (m_InitCritSec) { + ::DeleteCriticalSection(&m_Crit); + } +} + + +// +// Initialize +HRESULT +CMyQueue::CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ PCMyQueue *Queue + ) +/*++ + +Routine Description: + + + CreateInstance creates an instance of the queue object. + +Arguments: + + ppUkwn - OUT parameter is an IUnknown interface to the queue object + +Return Value: + + HRESULT indicating success or failure + +--*/ +{ + CMyQueue *pMyQueue = new CMyQueue; + HRESULT hr; + + if (pMyQueue == NULL) { + return E_OUTOFMEMORY; + } + + hr = pMyQueue->Initialize(FxDevice); + + if (SUCCEEDED(hr)) + { + *Queue = pMyQueue; + } + else + { + pMyQueue->Release(); + } + return hr; +} + +HRESULT +CMyQueue::Initialize( + _In_ IWDFDevice *FxDevice + ) +{ + IWDFIoQueue *fxQueue; + HRESULT hr; + + // + // Initialize the critical section before we continue + // + + if (!InitializeCriticalSectionAndSpinCount(&m_Crit,0x80000400)) + { + hr = HRESULT_FROM_WIN32(GetLastError()); + goto Exit; + } + m_InitCritSec = TRUE; + + // + // Create the framework queue + // + + { + IUnknown *unknown = QueryIUnknown(); + hr = FxDevice->CreateIoQueue(unknown, + TRUE, + WdfIoQueueDispatchSequential, + TRUE, + FALSE, + &fxQueue); + unknown->Release(); + } + + if (FAILED(hr)) + { + goto Exit; + } + + m_FxQueue = fxQueue; + + fxQueue->Release(); + +Exit: + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CMyQueue::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + +Routine Description: + + + Query Interface + +Arguments: + + Follows COM specifications + +Return Value: + + HRESULT indicating success or failure + +--*/ +{ + HRESULT hr; + + + if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackWrite))) { + *Object = QueryIQueueCallbackWrite(); + hr = S_OK; + } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackRead))) { + *Object = QueryIQueueCallbackRead(); + hr = S_OK; + } else if (IsEqualIID(InterfaceId, __uuidof(IQueueCallbackDeviceIoControl))) { + *Object = QueryIQueueCallbackDeviceIoControl(); + hr = S_OK; + } else { + hr = CUnknown::QueryInterface(InterfaceId, Object); + } + + return hr; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnDeviceIoControl( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ) +/*++ + +Routine Description: + + + DeviceIoControl dispatch routine + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + ControlCode - IO Control Code + InputBufferSizeInBytes - Length of input buffer + OutputBufferSizeInBytes - Length of output buffer + + Always succeeds DeviceIoIoctl +Return Value: + + VOID + +--*/ +{ + + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(ControlCode); + UNREFERENCED_PARAMETER(InputBufferSizeInBytes); + UNREFERENCED_PARAMETER(OutputBufferSizeInBytes); + + pWdfRequest->Complete(S_OK); + return; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToWrite + ) +/*++ + +Routine Description: + + + Write dispatch routine + IQueueCallbackWrite + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToWrite - Length of bytes in the write buffer + + Allocate and copy data to local buffer +Return Value: + + VOID + +--*/ +{ + + HRESULT hr; + IWDFMemory* pRequestMemory = NULL; + IWDFIoRequest2 * pWdfRequest2 = NULL; + + UNREFERENCED_PARAMETER(pWdfQueue); + + // + // Handle Zero length writes. + // + + if (!BytesToWrite) { + pWdfRequest->CompleteWithInformation(S_OK, 0); + return; + } + + if( BytesToWrite > MAX_WRITE_LENGTH ) { + + pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_MORE_DATA), 0); + return; + } + + // Release previous buffer if set + + if( m_Buffer != NULL ) { + delete [] m_Buffer; + m_Buffer = NULL; + m_Length = 0L; + } + + // Allocate Buffer + + m_Buffer = new UCHAR[BytesToWrite]; + if (m_Buffer == NULL) { + pWdfRequest->Complete(E_OUTOFMEMORY); + m_Length = 0L; + return; + } + + // Get memory object + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2)); + + if (FAILED(hr)) { + goto Exit; + } + + hr = pWdfRequest2->RetrieveInputMemory(&pRequestMemory); + + if (FAILED(hr)) { + goto Exit; + } + + // Copy from memory object to our buffer + + hr = pRequestMemory->CopyToBuffer(0, m_Buffer, BytesToWrite); + + if (FAILED(hr)) { + goto Exit; + } + + // + // Release memory object. + // + SAFE_RELEASE(pRequestMemory); + + // + // Save the information so that we can use it + // to complete the request later. + // + + Lock(); + + m_Length = (ULONG) BytesToWrite; + m_XferredBytes = m_Length; + m_CurrentRequest = pWdfRequest2; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + if (pWdfRequest2) { + pWdfRequest2->CompleteWithInformation(hr, 0); + } + delete [] m_Buffer; + m_Buffer = NULL; + SAFE_RELEASE(pRequestMemory); + } + + // + // This is an early release. pWdfRequest2 will be released, when the request is completed + // + SAFE_RELEASE(pWdfRequest2); + + return; +} + +VOID +STDMETHODCALLTYPE +CMyQueue::OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T SizeInBytes + ) +/*++ + +Routine Description: + + + Read dispatch routine + IQueueCallbackRead + +Arguments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + SizeInBytes - Length of bytes in the read buffer + + Copy available data into the read buffer +Return Value: + + VOID + +--*/ +{ + IWDFMemory* pRequestMemory = NULL; + IWDFIoRequest2 * pWdfRequest2 = NULL; + HRESULT hr; + + UNREFERENCED_PARAMETER(pWdfQueue); + + // + // Handle Zero length reads. + // + + if (!SizeInBytes) { + pWdfRequest->CompleteWithInformation(S_OK, 0); + return; + } + + if (m_Buffer == NULL) { + pWdfRequest->CompleteWithInformation(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER), SizeInBytes); + return; + } + + if (m_Length < SizeInBytes) { + SizeInBytes = m_Length; + } + + // + // Get memory object + // + + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2)); + + if (FAILED(hr)) { + goto Exit; + } + + hr = pWdfRequest2->RetrieveOutputMemory(&pRequestMemory ); + + if (FAILED(hr)) { + goto Exit; + } + + // Copy from buffer to memory object + + hr = pRequestMemory->CopyFromBuffer(0, m_Buffer, SizeInBytes); + + if (FAILED(hr)) { + goto Exit; + } + + // + // Release memory object. + // + + SAFE_RELEASE(pRequestMemory); + + // + // Save the information so that we can use it + // to complete the request later. + // + + Lock(); + + m_CurrentRequest = pWdfRequest2; + m_XferredBytes = SizeInBytes; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + if (pWdfRequest2) { + pWdfRequest2->CompleteWithInformation(hr, 0); + } + SAFE_RELEASE(pRequestMemory); + } + + // + // This is an early release. pWdfRequest2 will be released, when the request is completed + // + SAFE_RELEASE(pWdfRequest2); + + return; +} + +DWORD +CMyQueue::CompletionThread( + PVOID ThreadParameter + ) +/*++ + +Routine Description: + + + This routine is called from the thread started to complete + I/O requests. It sleeps for TIMER_PERIOD and then completes + the current request. Note that it has to release the lock + before it calls the request complete method. + +Arguments: + + ThreadParameter - This is a pointer to the Queue object. + +Return Value: + + VOID + +--*/ +{ + CMyQueue *pQueue = (CMyQueue *)ThreadParameter; + IWDFIoRequest2 *request; + SIZE_T bytesXferred = 0; + + for (;;) { + + // + // Block for a fixed time and then complete the request. + // + + Sleep(TIMER_PERIOD); + + pQueue->Lock(); + + // + // Process the current request. + // + + request = pQueue->m_CurrentRequest; + + if (request) { + bytesXferred = pQueue->m_XferredBytes; + } + + // + // Reset values. + // + + pQueue->m_CurrentRequest = NULL; + pQueue->m_XferredBytes = 0; + + + pQueue->Unlock(); + + if (request) { + request->CompleteWithInformation(S_OK, bytesXferred); + } + + // + // If thread needs to be terminated + // + + if (pQueue->m_ExitThread) { + ExitThread(0); + } + + } + +} diff --git a/general/echo/umdf/Queue.h b/general/echo/umdf/Queue.h new file mode 100644 index 00000000..c4b28c97 --- /dev/null +++ b/general/echo/umdf/Queue.h @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) Microsoft Corporation, All Rights Reserved + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// Set max write length for testing +#define MAX_WRITE_LENGTH (40*1024) + +// Set timer period in ms +#define TIMER_PERIOD 100 + +// +// Queue Callback Object. +// + +class CMyQueue : + public IQueueCallbackDeviceIoControl, + public IQueueCallbackRead, + public IQueueCallbackWrite, + public CUnknown +{ + PVOID m_Buffer; // Current buffer + ULONG m_Length; // Length of the buffer + SIZE_T m_XferredBytes; // Amount of bytes transferred for the current request + IWDFIoRequest2 *m_CurrentRequest; // Current request + CRITICAL_SECTION m_Crit; // Lock to protect updates to CMyQueue fields + BOOLEAN m_ExitThread; // If TRUE Terminate thread. + BOOLEAN m_InitCritSec; // If TRUE lock initialized + + IWDFIoQueue *m_FxQueue; + + CMyQueue() : + m_Buffer(NULL), + m_Length (0), + m_CurrentRequest(NULL), + m_XferredBytes(0), + m_ExitThread(FALSE), + m_InitCritSec(FALSE), + m_FxQueue(NULL) + { + } + + virtual ~CMyQueue(); + + _Acquires_lock_(this->m_Crit) + __inline + void + Lock( + ) + { + ::EnterCriticalSection(&m_Crit); + } + + _Releases_lock_(this->m_Crit) + __inline + void + Unlock( + ) + { + ::LeaveCriticalSection(&m_Crit); + } + + HRESULT + Initialize( + _In_ IWDFDevice *FxDevice + ); + +public: + + // + // Completion thread routine. + // + + static DWORD CompletionThread( PVOID ThreadParameter); + + // + // Sets the flag to make thread exit + // + + void + SetExitThread() + { + m_ExitThread = TRUE; + } + + static + HRESULT + CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ PCMyQueue *Queue + ); + + HRESULT + Configure( + VOID + ) + { + return S_OK; + } + + + IQueueCallbackDeviceIoControl * + QueryIQueueCallbackDeviceIoControl( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackDeviceIoControl *>(this); + } + + IQueueCallbackRead * + QueryIQueueCallbackRead( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackRead *>(this); + } + + IQueueCallbackWrite * + QueryIQueueCallbackWrite( + VOID + ) + { + AddRef(); + return static_cast<IQueueCallbackWrite *>(this); + } + + // + // IUnknown + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) { + return CUnknown::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) { + return CUnknown::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // Wdf Callbacks + // + + // IQueueCallbackDeviceIoControl + // + virtual + VOID + STDMETHODCALLTYPE + OnDeviceIoControl( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ ULONG ControlCode, + _In_ SIZE_T InputBufferSizeInBytes, + _In_ SIZE_T OutputBufferSizeInBytes + ); + + // IQueueCallbackWrite + // + virtual + VOID + STDMETHODCALLTYPE + OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToWrite + ); + + // IQueueCallbackRead + // + virtual + VOID + STDMETHODCALLTYPE + OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T NumOfBytesToRead + ); +}; diff --git a/general/echo/umdf/ReadMe.md b/general/echo/umdf/ReadMe.md new file mode 100644 index 00000000..750d34df --- /dev/null +++ b/general/echo/umdf/ReadMe.md @@ -0,0 +1,124 @@ +Echo Sample (UMDF Version 1) +============================ + +This sample demonstrates how to use User-Mode Driver Framework (UMDF) version 1 to write a driver and demonstrates best practices. + +It also demonstrates the use of a default Serial Dispatch I/O Queue, its request start events, cancellation event, and synchronizing with another thread. The preferred I/O retrieval mode is set to Direct I/O. So, whenever a request is received by the framework, UMDF looks at the size of the buffer and determines, whether it should copy the buffer (if the length is less than 2 full pages) or map it (if the length is greater or equal to 2 full pages). + +This sample driver is a minimal driver meant to demonstrate the usage of the User-Mode Driver Framework. It is not intended for use in a production environment. + + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + +Testing +------- + +To test the Echo driver, you can run echoapp.exe which is built from src\\general\\echo\\exe. + +First install the device as described above. Then run echoapp.exe. + +``` {.syntax xml:space="preserve"} +D:\>echoapp /? +Usage: +Echoapp.exe --- Send single write and read request synchronously +Echoapp.exe -Async --- Send 100 reads and writes asynchronously +Exit the app anytime by pressing Ctrl-C + +D:\>echoapp +DevicePath: \\?\root#sample#0000#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} +Opened device successfully +512 Pattern Bytes Written successfully +512 Pattern Bytes Read successfully +Pattern Verified successfully + +D:\>echoapp -Async +DevicePath: \\?\root#sample#0000#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} +Opened device successfully +Starting AsyncIo +Number of bytes written by request number 0 is 1024 +Number of bytes read by request number 0 is 1024 +Number of bytes read by request number 1 is 1024 +Number of bytes written by request number 2 is 1024 +Number of bytes read by request number 2 is 1024 +Number of bytes written by request number 3 is 1024 +Number of bytes read by request number 3 is 1024 +Number of bytes written by request number 4 is 1024 +Number of bytes read by request number 4 is 1024 +Number of bytes written by request number 5 is 1024 +Number of bytes read by request number 5 is 1024 +Number of bytes written by request number 6 is 1024 +Number of bytes read by request number 6 is 1024 +Number of bytes written by request number 7 is 1024 +Number of bytes read by request number 7 is 1024 +Number of bytes written by request number 8 is 1024 +Number of bytes read by request number 8 is 1024 +Number of bytes written by request number 9 is 1024 +Number of bytes read by request number 9 is 1024 +Number of bytes written by request number 10 is 1024 +Number of bytes read by request number 10 is 1024 +Number of bytes written by request number 11 is 1024 +... +``` + +Note that the reads and writes are performed by independent threads in the echo test application. As a result the order of the output may not exactly match what you see above. + +File Manifest +------------- + +File + +Description + +comsup.cpp & comsup.h + +COM Support code - specifically base classes which provide implementations for the standard COM interfaces IUnknown and IClassFactory which are used throughout this sample. + +The implementation of IClassFactory is designed to create instances of the CMyDriver class. If you should change the name of your base driver class, you would also need to modify this file. + +dllsup.cpp + +DLL Support code - provides the DLL's entry point as well as the single required export (DllGetClassObject). + +These depend on comsup.cpp to perform the necessary class creation. + +exports.def + +This file lists the functions that the driver DLL exports. + +internal.h + +This is the main header file for this driver. + +Driver.cpp and Driver.h + +DriverEntry and events on the driver object. + +Device.cpp and Device.h + +The Events on the device object. + +Queue.cpp and Queue.h + +Contains Events on the I/O Queue Objects. + +Echo.rc + +Resource file for the driver. + +WUDFEchoDriver.inx + +File that describes the installation of this driver. The build process converts this into an INF file. + +makefile.inc + +A makefile that defines custom build actions. This includes the conversion of the .INX file into a .INF file + +echodriver.ctl + +This file lists the WPP trace control GUID(s) for the sample driver. This file can be used with the tracelog command's -guid flag to enable the collection of these trace events within an established trace session. + +These GUIDs must remain in sync with the trace control GUIDs defined in internal.h. + diff --git a/general/echo/umdf/WUDFEchoDriver.inx b/general/echo/umdf/WUDFEchoDriver.inx new file mode 100644 index 00000000..6279783e --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.inx @@ -0,0 +1,87 @@ +; +; WUDFEchoDriver.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFTWUDF% +CatalogFile=WUDF.cat +DriverVer=03/20/2003,5.00.3788 + +[Manufacturer] +%MSFTWUDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%EchoDeviceName%=Echo_Install,WUDF\Echo + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +WUDFEchoDriver.dll=1 +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== WUDF Echo Test Driver ================================== + +[Echo_Install.NT] +CopyFiles=UMDriverCopy + +[Echo_Install.NT.hw] + +[Echo_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[Echo_Install.NT.CoInstallers] +AddReg = CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[Echo_Install.NT.Wdf] +UmdfService=WUDFEchoDriver,WUDFEchoDriver_Install +UmdfServiceOrder=WUDFEchoDriver + +; if device can do either direct i/o or buffered transfer mode, +; umdf defaults to direct i/o if devices is not pooled. +UmdfHostProcessSharing=ProcessSharingDisabled + +[WUDFEchoDriver_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID={7AB7DCF5-D1D4-4085-9547-1DB968CCA720} +ServiceBinary=%12%\UMDF\WUDFEchoDriver.dll + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + +[CoInstallers_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\UMDF +CoInstallers_CopyFiles=11 + +[UMDriverCopy] +WUDFEchoDriver.dll + +; =================== Generic ================================== + +[Strings] +MSFTWUDF="Microsoft Internal (WUDF)" +MediaDescription="Microsoft WUDF Sample Driver Installation Media" +ClassName="Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +EchoDeviceName="Sample WUDF Echo Driver" diff --git a/general/echo/umdf/WUDFEchoDriver.vcxproj b/general/echo/umdf/WUDFEchoDriver.vcxproj new file mode 100644 index 00000000..242f1dda --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj @@ -0,0 +1,256 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{9E7A6816-063C-4560-A31F-C5472D1CE345}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{164B0F80-BB88-48C9-A03F-3F3937D8CCB6}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; comsup.cpp; driver.cpp; device.cpp; queue.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="WudfEchoDriver.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\WudfEchoDriver.inf</CopyOutput> + </Inf> + <OtherWpp Include="Echo.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>WUDFEchoDriver</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="Echo.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/umdf/WUDFEchoDriver.vcxproj.Filters b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters new file mode 100644 index 00000000..b702fb21 --- /dev/null +++ b/general/echo/umdf/WUDFEchoDriver.vcxproj.Filters @@ -0,0 +1,54 @@ +<?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>{0FBE107F-4905-4E97-BFF9-8C2A6B03AED8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{9534FE43-2493-4430-A335-97FC2BE106BD}</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>{A96A2015-2537-47ED-B43D-8C379EDEC69F}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{203FBCD2-49E2-491E-9D3F-03A028ED6CEE}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="comsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\WudfEchoDriver.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="WudfEchoDriver.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Echo.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf/dllsup.cpp b/general/echo/umdf/dllsup.cpp new file mode 100644 index 00000000..e7200a28 --- /dev/null +++ b/general/echo/umdf/dllsup.cpp @@ -0,0 +1,176 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Echo Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the echo driver uses + L"Microsoft\\UMDF\\Echo" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID /* Reserved */ + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER(ModuleHandle); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return TRUE; +} + +HRESULT +STDAPICALLTYPE +DllGetClassObject( + _In_ REFCLSID ClassId, + _In_ REFIID InterfaceId, + _Outptr_ LPVOID *Interface + ) +/*++ + + Routine Description: + + This routine is called by COM in order to instantiate the + driver callback object and do an initial query interface on it. + + This method only creates an instance of the driver's class factory, as this + is the minimum required to support UMDF. + + Arguments: + + ClassId - the CLSID of the object being "gotten" + + InterfaceId - the interface the caller wants from that object. + + Interface - a location to store the referenced interface pointer + + Return Value: + + S_OK if the function succeeds or error indicating the cause of the + failure. + +--*/ +{ + PCClassFactory factory; + + HRESULT hr = S_OK; + + *Interface = NULL; + + // + // If the CLSID doesn't match that of our "coclass" (defined in the IDL + // file) then we can't create the object the caller wants. This may + // indicate that the COM registration is incorrect, and another CLSID + // is referencing this drvier. + // + + if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Called to create instance of unrecognized class (%!GUID!)", + &ClassId + ); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + // + // Create an instance of the class factory for the caller. + // + + factory = new CClassFactory(); + + if (NULL == factory) + { + hr = E_OUTOFMEMORY; + } + + // + // Query the object we created for the interface the caller wants. After + // that we release the object. This will drive the reference count to + // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). + // In the later case the object is automatically deleted. + // + + if (SUCCEEDED(hr)) + { + hr = factory->QueryInterface(InterfaceId, Interface); + factory->Release(); + } + + return hr; +} diff --git a/general/echo/umdf/echo.sln b/general/echo/umdf/echo.sln new file mode 100644 index 00000000..853b7d55 --- /dev/null +++ b/general/echo/umdf/echo.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WUDFEchoDriver", "WUDFEchoDriver.vcxproj", "{9E7A6816-063C-4560-A31F-C5472D1CE345}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.ActiveCfg = Debug|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|Win32.Build.0 = Debug|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.ActiveCfg = Release|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|Win32.Build.0 = Release|Win32 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.ActiveCfg = Debug|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Debug|x64.Build.0 = Debug|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.ActiveCfg = Release|x64 + {9E7A6816-063C-4560-A31F-C5472D1CE345}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/echo/umdf/echodriver.ctl b/general/echo/umdf/echodriver.ctl new file mode 100644 index 00000000..a0ce2089 --- /dev/null +++ b/general/echo/umdf/echodriver.ctl @@ -0,0 +1 @@ +d93fb470-afb1-4af8-860e-75f726c66f6b WudfEchoDriverTraceGuid diff --git a/general/echo/umdf/exports.def b/general/echo/umdf/exports.def new file mode 100644 index 00000000..ec564639 --- /dev/null +++ b/general/echo/umdf/exports.def @@ -0,0 +1,10 @@ +; Echo.def : Declares the module parameters. + +; +; TODO: Change the library name here to match your binary name. +; + +LIBRARY "WUDFEchoDriver.DLL" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/general/echo/umdf/internal.h b/general/echo/umdf/internal.h new file mode 100644 index 00000000..8e5c2d60 --- /dev/null +++ b/general/echo/umdf/internal.h @@ -0,0 +1,114 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Echo + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Forward definitions of classes in the other header files. +// + +typedef class CMyDriver *PCMyDriver; +typedef class CMyDevice *PCMyDevice; +typedef class CMyQueue *PCMyQueue; + +// +// Define the tracing flags. +// +// TODO: Choose a different trace control GUID +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (d93fb470,afb1,4af8,860e,75f726c66f6b), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// +// TODO: Change these values to be appropriate for your driver. +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\Echo" +#define MYDRIVER_CLASS_ID {0x7ab7dcf5, 0xd1d4, 0x4085, {0x95, 0x47, 0x1d, 0xb9, 0x68, 0xcc, 0xa7, 0x20}} + +// +// Include the type specific headers. +// + +#include "comsup.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_TEST_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} diff --git a/general/echo/umdf2/ReadMe.md b/general/echo/umdf2/ReadMe.md new file mode 100644 index 00000000..e037a8b5 --- /dev/null +++ b/general/echo/umdf2/ReadMe.md @@ -0,0 +1,77 @@ +Echo Sample (UMDF Version 2) +============================ + +The ECHO (UMDF version 2) sample demonstrates how to use a sequential queue to serialize read and write requests presented to the driver. + +It also shows how to synchronize execution of these events with other asynchronous events such as request cancellation and DPC. + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + + +Download and extract the sample +------------------------------- + +Click the download button on this page. Click **Save**, and then click **Open Folder**. Right click the zip file, and choose **Extract All**. Specify or browse to a folder for the extracted files. For example, you could extract to c:\\umdf2echo. + +Open the driver solution in Visual Studio +----------------------------------------- + +Navigate to the folder that has the extracted sample. Double click the solution file (umdf2echo.sln). In Microsoft Visual Studio, locate Solution Explorer. (If this is not already open, choose **Solution Explorer** from the **View** menu.) In Solution Explorer, you can see one solution that contains 3 projects. There is a driver project (Driver-\>AutoSync-\>echo), an application project (Exe-\>echoapp), and a package project named **package** (lower case). + +Set the configuration and platform in Visual Studio +--------------------------------------------------- + +In Visual Studio, in Solution Explorer, right click **Solution**, and choose **Configuration Manager**. Set the configuration and the platform. Make sure that the configuration and platform are the same for both the driver project and the package project. Do not check the **Deploy** boxes. Because this solution uses UMDF version 2, you cannot select a configuration earlier than Windows 8.1. + + +Locate the built driver package +------------------------------- + +In File Explorer, navigate to the folder that contains your built driver package. The location of this folder varies depending on what you set for configuration and platform. For example, if your settings are Win8.1 Debug and x64, the package is in your solution folder under x64\\Win8.1Debug\\Package. + +Run the sample +-------------- + +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. + +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy a driver sample automatically or manually. + +### Automatic deployment (root enumerated) + +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). + +1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter **root\\ECHO** for the hardware ID. Click **OK**. +3. On the **Build** menu, choose **Build Solution**. + +### Manual deployment (root enumerated) + +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). + +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\umdf2echoPkg). +2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter the following command: + + **devcon install echoum.inf root\\ECHO** + +### View the root enumerated driver in Device Manager + +On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **Sample WDF ECHO Driver** (for example, this might be under the **Sample Device** node). + +In Device Manager, on the **View** menu, choose **Devices by connection**. Locate **Sample WDF ECHO Driver** as a child of the root node of the device tree. + +Build the sample using MSBuild +------------------------------ + +As an alternative to building the driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, umdf2echo.sln. Use the MSBuild command to build the solution. Here is an example: + +**msbuild /p:configuration=”Win8 Release” /p:platform=”Win32” umdf2echo.sln** + +For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + diff --git a/general/echo/umdf2/driver/AutoSync/device.c b/general/echo/umdf2/driver/AutoSync/device.c new file mode 100644 index 00000000..48afdb66 --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/device.c @@ -0,0 +1,202 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.c - Device handling events for example driver. + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + Worker routine called to create a device and its software resources. + +Arguments: + + DeviceInit - Pointer to an opaque init structure. Memory for this + structure will be freed by the framework when the WdfDeviceCreate + succeeds. So don't access the structure after that point. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES deviceAttributes; + PDEVICE_CONTEXT deviceContext; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDFDEVICE device; + NTSTATUS status; + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Register pnp/power callbacks so that we can start and stop the timer as the device + // gets started and stopped. + // + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart; + pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend; + + #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks") + pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart; + + // + // Register the PnP and power callbacks. Power policy related callbacks will be registered + // later in SotwareInit. + // + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT); + + status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); + + if (NT_SUCCESS(status)) { + // + // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an + // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the + // device.h header file. This function will do the type checking and return + // the device context. If you pass a wrong object handle + // it will return NULL and assert if run under framework verifier mode. + // + deviceContext = WdfObjectGet_DEVICE_CONTEXT(device); + deviceContext->PrivateDeviceData = 0; + + // + // Create a device interface so that application can find and talk + // to us. + // + status = WdfDeviceCreateDeviceInterface( + device, + &GUID_DEVINTERFACE_ECHO, + NULL // ReferenceString + ); + + if (NT_SUCCESS(status)) { + // + // Initialize the I/O Package and any Queues + // + status = EchoQueueInitialize(device); + } + } + + return status; +} + + +NTSTATUS +EchoEvtDeviceSelfManagedIoStart( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is started + or restarted after a suspend operation. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + LARGE_INTEGER DueTime; + + KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n")); + + // + // Restart the queue and the periodic timer. We stopped them before going + // into low power state. + // + WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device)); + + DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); + + WdfTimerStart(queueContext->Timer, DueTime.QuadPart); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n")); + + return STATUS_SUCCESS; +} + +NTSTATUS +EchoEvtDeviceSelfManagedIoSuspend( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + This event is called by the Framework when the device is stopped + for resource rebalance or suspended when the system is entering + Sx state. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - The driver is not allowed to fail this function. If it does, the + device stack will be torn down. + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); + + PAGED_CODE(); + + KdPrint(("--> EchoEvtDeviceSelfManagedIoSuspend\n")); + + // + // Before we stop the timer we should make sure there are no outstanding + // i/o. We need to do that because framework cannot suspend the device + // if there are requests owned by the driver. There are two ways to solve + // this issue: 1) We can wait for the outstanding I/O to be complete by the + // periodic timer 2) Register EvtIoStop callback on the queue and acknowledge + // the request to inform the framework that it's okay to suspend the device + // with outstanding I/O. In this sample we will use the 1st approach + // because it's pretty easy to do. We will restart the queue when the + // device is restarted. + // + WdfIoQueueStopSynchronously(WdfDeviceGetDefaultQueue(Device)); + + // + // Stop the watchdog timer and wait for DPC to run to completion if it's already fired. + // + WdfTimerStop(queueContext->Timer, TRUE); + + KdPrint(( "<-- EchoEvtDeviceSelfManagedIoSuspend\n")); + + return STATUS_SUCCESS; +} + + + diff --git a/general/echo/umdf2/driver/AutoSync/device.h b/general/echo/umdf2/driver/AutoSync/device.h new file mode 100644 index 00000000..f29c7908 --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/device.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + device.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "public.h" + +// +// The device context performs the same job as +// a WDM device extension in the driver frameworks +// +typedef struct _DEVICE_CONTEXT +{ + ULONG PrivateDeviceData; // just a placeholder + +} DEVICE_CONTEXT, *PDEVICE_CONTEXT; + +// +// This macro will generate an inline function called WdfObjectGet_DEVICE_CONTEXT +// which will be used to get a pointer to the device context memory +// in a type safe manner. +// +WDF_DECLARE_CONTEXT_TYPE(DEVICE_CONTEXT) + +// +// Function to initialize the device and its callbacks +// +NTSTATUS +EchoDeviceCreate( + PWDFDEVICE_INIT DeviceInit + ); + +// +// Device events +// +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT EchoEvtDeviceSelfManagedIoStart; +EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EchoEvtDeviceSelfManagedIoSuspend; + diff --git a/general/echo/umdf2/driver/AutoSync/driver.c b/general/echo/umdf2/driver/AutoSync/driver.c new file mode 100644 index 00000000..34fdd776 --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/driver.c @@ -0,0 +1,192 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.c + +Abstract: + + This driver demonstrates use of a default I/O Queue, its + request start events, cancellation event, and a synchronized DPC. + + To demonstrate asynchronous operation, the I/O requests are not completed + immediately, but stored in the drivers private data structure, and a timer + will complete it next time the Timer callback runs. + + During the time the request is waiting for the timer callback to run, it is + made cancellable by the call WdfRequestMarkCancelable. This + allows the test program to cancel the request and exit instantly. + + This rather complicated set of events is designed to demonstrate + the driver frameworks synchronization of access to a device driver + data structure, and a pointer which can be a proxy for device hardware + registers or resources. + + This common data structure, or resource is accessed by new request + events arriving, the Timer callback that completes it, and cancel processing. + + Notice the lack of specific lock/unlock operations. + + Even though this example utilizes a serial queue, a parallel queue + would not need any additional explicit synchronization, just a + strategy for managing multiple requests outstanding. + +--*/ + +#include "driver.h" + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + WDF_DRIVER_CONFIG_INIT(&config, + EchoEvtDeviceAdd + ); + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status)); + return status; + } + +#if DBG + EchoPrintDriverVersion(); +#endif + + return status; +} + +NTSTATUS +EchoEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(Driver); + + KdPrint(("Enter EchoEvtDeviceAdd\n")); + + status = EchoDeviceCreate(DeviceInit); + + return status; +} + +NTSTATUS +EchoPrintDriverVersion( + ) +/*++ +Routine Description: + + This routine shows how to retrieve framework version string and + also how to find out to which version of framework library the + client driver is bound to. + +Arguments: + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDFSTRING string; + UNICODE_STRING us; + WDF_DRIVER_VERSION_AVAILABLE_PARAMS ver; + + // + // 1) Retreive version string and print that in the debugger. + // + status = WdfStringCreate(NULL, WDF_NO_OBJECT_ATTRIBUTES, &string); + if (!NT_SUCCESS(status)) { + KdPrint(("Error: WdfStringCreate failed 0x%x\n", status)); + return status; + } + + status = WdfDriverRetrieveVersionString(WdfGetDriver(), string); + if (!NT_SUCCESS(status)) { + // + // No need to worry about delete the string object because + // by default it's parented to the driver and it will be + // deleted when the driverobject is deleted when the DriverEntry + // returns a failure status. + // + KdPrint(("Error: WdfDriverRetrieveVersionString failed 0x%x\n", status)); + return status; + } + + WdfStringGetUnicodeString(string, &us); + KdPrint(("Echo Sample %wZ\n", &us)); + + WdfObjectDelete(string); + string = NULL; // To avoid referencing a deleted object. + + // + // 2) Find out to which version of framework this driver is bound to. + // + WDF_DRIVER_VERSION_AVAILABLE_PARAMS_INIT(&ver, 1, 0); + if (WdfDriverIsVersionAvailable(WdfGetDriver(), &ver) == TRUE) { + KdPrint(("Yes, framework version is 1.0\n")); + }else { + KdPrint(("No, framework verison is not 1.0\n")); + } + + return STATUS_SUCCESS; +} + diff --git a/general/echo/umdf2/driver/AutoSync/driver.h b/general/echo/umdf2/driver/AutoSync/driver.h new file mode 100644 index 00000000..b1a5b40a --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/driver.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + driver.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#define INITGUID + +#include <windows.h> +#include <wdf.h> +#include "device.h" +#include "queue.h" + +#ifndef ASSERT +#if DBG +#define ASSERT( exp ) \ + ((!(exp)) ? \ + (KdPrint(( "\n*** Assertion failed: " #exp "\n\n")), \ + DebugBreak(), \ + FALSE) : \ + TRUE) +#else +#define ASSERT( exp ) +#endif // DBG +#endif // ASSERT + +// +// WDFDRIVER Events +// + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD EchoEvtDeviceAdd; + +NTSTATUS +EchoPrintDriverVersion( + ); + diff --git a/general/echo/umdf2/driver/AutoSync/echo.vcxproj b/general/echo/umdf2/driver/AutoSync/echo.vcxproj new file mode 100644 index 00000000..defa7b4d --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/echo.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{95360722-8B66-4DD4-957A-DF8B7CA700FB}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{F03689D2-F1BC-4D18-B99E-286CA22656D5}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\EchoUm.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\EchoUm.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echo</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="device.c" /> + <ClCompile Include="driver.c" /> + <ClCompile Include="queue.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters b/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters new file mode 100644 index 00000000..75ab6a0f --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/echo.vcxproj.Filters @@ -0,0 +1,40 @@ +<?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>{EF21C647-A675-40F9-981A-364CC77BFA4D}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{DC1E303A-60D0-45E3-AD8E-FA903A23C932}</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>{04F193A8-1C9D-45EC-ADDB-918233FB151D}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{C0846D78-C3A3-42B0-AFDD-5D33B6AAE456}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\EchoUm.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\EchoUm.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="device.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf2/driver/AutoSync/echoum.inx b/general/echo/umdf2/driver/AutoSync/echoum.inx new file mode 100644 index 00000000..287c05df --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/echoum.inx @@ -0,0 +1,89 @@ +;/*++ +; +;Copyright (c) 1990-2000 Microsoft Corporation +; +;Module Name: +; EchoUm.INF +; +;Abstract: +; INF file for installing the Usermode Driver Frameworks Echo Driver +; +;Installation Notes: +; Using Devcon: Type "devcon install EchoUm.inf root\ECHO" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=wudf.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +Echo.dll = 1,, + +;***************************************** +; ECHO Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +[Standard.NT$ARCH$] +%ECHO.DeviceDesc%=ECHO_Device, root\ECHO + +;---------------- copy files + +[ECHO_Device.NT] +CopyFiles=UMDriverCopy + +[UMDriverCopy] +ECHO.dll + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to driversMdf + +;-------------- Service installation +[ECHO_Device.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +;-------------- WDF specific section ------------- +[ECHO_Device.NT.Wdf] +UmdfService=Echo, Echo_Install +UmdfServiceOrder=Echo + +[Echo_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\echo.dll + +[Strings] +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample ECHO Installation Disk #1" +ECHO.DeviceDesc = "Sample UMDF v2 ECHO Driver" +ClassName = "Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector"
\ No newline at end of file diff --git a/general/echo/umdf2/driver/AutoSync/queue.c b/general/echo/umdf2/driver/AutoSync/queue.c new file mode 100644 index 00000000..3162a683 --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/queue.c @@ -0,0 +1,541 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.c + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +#include "driver.h" + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE Device + ) +/*++ + +Routine Description: + + + The I/O dispatch callbacks for the frameworks device object + are configured in this function. + + A single default I/O Queue is configured for serial request + processing, and a driver context memory allocation is created + to hold our structure QUEUE_CONTEXT. + + This memory may be used by the driver automatically synchronized + by the Queue's presentation lock. + + The lifetime of this memory is tied to the lifetime of the I/O + Queue object, and we register an optional destructor callback + to release any private allocations, and/or resources. + + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS + +--*/ +{ + WDFQUEUE queue; + NTSTATUS status; + PQUEUE_CONTEXT queueContext; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES queueAttributes; + + // + // Configure a default queue so that requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching to goto + // other queues get dispatched here. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( + &queueConfig, + WdfIoQueueDispatchSequential + ); + + queueConfig.EvtIoRead = EchoEvtIoRead; + queueConfig.EvtIoWrite = EchoEvtIoWrite; + + // + // Fill in a callback for destroy, and our QUEUE_CONTEXT size + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_CONTEXT); + + // + // Set synchronization scope on queue and have the timer to use queue as + // the parent object so that queue and timer callbacks are synchronized + // with the same lock. + // + queueAttributes.SynchronizationScope = WdfSynchronizationScopeQueue; + + queueAttributes.EvtDestroyCallback = EchoEvtIoQueueContextDestroy; + + status = WdfIoQueueCreate( + Device, + &queueConfig, + &queueAttributes, + &queue + ); + + if( !NT_SUCCESS(status) ) { + KdPrint(("WdfIoQueueCreate failed 0x%x\n",status)); + return status; + } + + // Get our Driver Context memory from the returned Queue handle + queueContext = QueueGetContext(queue); + + queueContext->WriteMemory = NULL; + queueContext->Timer = NULL; + + queueContext->CurrentRequest = NULL; + queueContext->CurrentStatus = STATUS_INVALID_DEVICE_REQUEST; + + // + // Create the Queue timer + // + status = EchoTimerCreate(&queueContext->Timer, queue); + if (!NT_SUCCESS(status)) { + KdPrint(("Error creating timer 0x%x\n",status)); + return status; + } + + return status; +} + + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* Timer, + IN WDFQUEUE Queue + ) +/*++ + +Routine Description: + + Subroutine to create timer. By associating the timerobject with + the queue, we are basically telling the framework to serialize the queue + callbacks with the timer callback. By doing so, we don't have to worry + about protecting queue-context structure from multiple threads accessing + it simultaneously. + +Arguments: + + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status; + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + + // + // Create a WDFTIMER object + // + WDF_TIMER_CONFIG_INIT(&timerConfig, EchoEvtTimerFunc); + + // + // WDF_OBJECT_ATTRIBUTES_INIT sets AutomaticSerialization to TRUE by default + // + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + timerAttributes.ParentObject = Queue; // Synchronize with the I/O Queue + timerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + + // + // Create a non-periodic timer since WDF does not allow periodic timer + // with autosynchronization at passive level + // + Status = WdfTimerCreate(&timerConfig, + &timerAttributes, + Timer // Output handle + ); + + return Status; +} + + + +VOID +EchoEvtIoQueueContextDestroy( + WDFOBJECT Object +) +/*++ + +Routine Description: + + This is called when the Queue that our driver context memory + is associated with is destroyed. + +Arguments: + + Context - Context that's being freed. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(Object); + + // + // Release any resources pointed to in the queue context. + // + // The body of the queue context will be released after + // this callback handler returns + // + + // + // If Queue context has an I/O buffer, release it + // + if( queueContext->WriteMemory != NULL ) { + WdfObjectDelete(queueContext->WriteMemory); + queueContext->WriteMemory = NULL; + } + + return; +} + + +VOID +EchoEvtRequestCancel( + IN WDFREQUEST Request + ) +/*++ + +Routine Description: + + + Called when an I/O request is cancelled after the driver has marked + the request cancellable. This callback is automatically synchronized + with the I/O callbacks since we have chosen to use frameworks Device + level locking. + +Arguments: + + Request - Request being cancelled. + +Return Value: + + VOID + +--*/ +{ + PQUEUE_CONTEXT queueContext = QueueGetContext(WdfRequestGetIoQueue(Request)); + + KdPrint(("EchoEvtRequestCancel called on Request 0x%p\n", Request)); + + // + // The following is race free by the callside or DPC side + // synchronizing completion by calling + // WdfRequestMarkCancelable(Queue, Request, FALSE) before + // completion and not calling WdfRequestComplete if the + // return status == STATUS_CANCELLED. + // + WdfRequestCompleteWithInformation(Request, STATUS_CANCELLED, 0L); + + // + // This book keeping is synchronized by the common + // Queue presentation lock + // + ASSERT(queueContext->CurrentRequest == Request); + queueContext->CurrentRequest = NULL; + + return; +} + +VOID +EchoEvtIoRead( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_READ request. + It will copy the content from the queue-context buffer to the request buffer. + If the driver hasn't received any write request earlier, the read returns zero. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + WDFMEMORY memory; + size_t writeMemoryLength; + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoRead Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + // + // No data to read + // + if( (queueContext->WriteMemory == NULL) ) { + WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, (ULONG_PTR)0L); + return; + } + + // + // Read what we have + // + WdfMemoryGetBuffer(queueContext->WriteMemory, &writeMemoryLength); + _Analysis_assume_(writeMemoryLength > 0); + + if( writeMemoryLength < Length ) { + Length = writeMemoryLength; + } + + // + // Get the request memory + // + Status = WdfRequestRetrieveOutputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead Could not get request memory buffer 0x%x\n", Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestCompleteWithInformation(Request, Status, 0L); + return; + } + + // Copy the memory out + Status = WdfMemoryCopyFromBuffer( memory, // destination + 0, // offset into the destination memory + WdfMemoryGetBuffer(queueContext->WriteMemory, NULL), + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoRead: WdfMemoryCopyFromBuffer failed 0x%x\n", Status)); + WdfRequestComplete(Request, Status); + return; + } + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + // Mark the request is cancelable + WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); + + + // Defer the completion to another thread from the timer dpc + queueContext->CurrentRequest = Request; + queueContext->CurrentStatus = Status; + + return; +} + +VOID +EchoEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + This event is invoked when the framework receives IRP_MJ_WRITE request. + This routine allocates memory buffer, copies the data from the request to it, + and stores the buffer pointer in the queue-context with the length variable + representing the buffers length. The actual completion of the request + is defered to the periodic timer dpc. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + + Request - Handle to a framework request object. + + Length - number of bytes to be read. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + WDFMEMORY memory; + PQUEUE_CONTEXT queueContext = QueueGetContext(Queue); + PVOID writeBuffer = NULL; + + _Analysis_assume_(Length > 0); + + KdPrint(("EchoEvtIoWrite Called! Queue 0x%p, Request 0x%p Length %d\n", + Queue,Request,Length)); + + if( Length > MAX_WRITE_LENGTH ) { + KdPrint(("EchoEvtIoWrite Buffer Length to big %d, Max is %d\n", + Length,MAX_WRITE_LENGTH)); + WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_OVERFLOW, 0L); + return; + } + + // Get the memory buffer + Status = WdfRequestRetrieveInputMemory(Request, &memory); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite Could not get request memory buffer 0x%x\n", + Status)); + WdfVerifierDbgBreakPoint(); + WdfRequestComplete(Request, Status); + return; + } + + // Release previous buffer if set + if( queueContext->WriteMemory != NULL ) { + WdfObjectDelete(queueContext->WriteMemory); + queueContext->WriteMemory = NULL; + } + + Status = WdfMemoryCreate(WDF_NO_OBJECT_ATTRIBUTES, + NonPagedPoolNx, + 'sam1', + Length, + &queueContext->WriteMemory, + &writeBuffer + ); + + if(!NT_SUCCESS(Status)) { + KdPrint(("EchoEvtIoWrite: Could not allocate %d byte buffer\n", Length)); + WdfRequestComplete(Request, STATUS_INSUFFICIENT_RESOURCES); + return; + } + + + // Copy the memory in + Status = WdfMemoryCopyToBuffer( memory, + 0, // offset into the source memory + writeBuffer, + Length ); + if( !NT_SUCCESS(Status) ) { + KdPrint(("EchoEvtIoWrite WdfMemoryCopyToBuffer failed 0x%x\n", Status)); + WdfVerifierDbgBreakPoint(); + + WdfObjectDelete(queueContext->WriteMemory); + queueContext->WriteMemory = NULL; + + WdfRequestComplete(Request, Status); + return; + } + + // Set transfer information + WdfRequestSetInformation(Request, (ULONG_PTR)Length); + + // Specify the request is cancelable + WdfRequestMarkCancelable(Request, EchoEvtRequestCancel); + + // Defer the completion to another thread from the timer dpc + queueContext->CurrentRequest = Request; + queueContext->CurrentStatus = Status; + + return; +} + + +VOID +EchoEvtTimerFunc( + IN WDFTIMER Timer + ) +/*++ + +Routine Description: + + This is the TimerDPC the driver sets up to complete requests. + This function is registered when the WDFTIMER object is created, and + will automatically synchronize with the I/O Queue callbacks + and cancel routine. + +Arguments: + + Timer - Handle to a framework Timer object. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS Status; + WDFREQUEST Request; + WDFQUEUE queue; + PQUEUE_CONTEXT queueContext ; + + queue = WdfTimerGetParentObject(Timer); + queueContext = QueueGetContext(queue); + + // + // DPC is automatically synchronized to the Queue lock, + // so this is race free without explicit driver managed locking. + // + Request = queueContext->CurrentRequest; + if( Request != NULL ) { + + // + // Attempt to remove cancel status from the request. + // + // The request is not completed if it is already cancelled + // since the EchoEvtIoCancel function has run, or is about to run + // and we are racing with it. + // + Status = WdfRequestUnmarkCancelable(Request); + if( Status != STATUS_CANCELLED ) { + + queueContext->CurrentRequest = NULL; + Status = queueContext->CurrentStatus; + + KdPrint(("CustomTimerDPC Completing request 0x%p, Status 0x%x \n", Request,Status)); + + WdfRequestComplete(Request, Status); + } + else { + KdPrint(("CustomTimerDPC Request 0x%p is STATUS_CANCELLED, not completing\n", + Request)); + } + } + + // + // Restart the Timer since WDF does not allow periodic timer + // with autosynchronization at passive level + // + WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(TIMER_PERIOD)); + + return; +} + + diff --git a/general/echo/umdf2/driver/AutoSync/queue.h b/general/echo/umdf2/driver/AutoSync/queue.h new file mode 100644 index 00000000..580c5b41 --- /dev/null +++ b/general/echo/umdf2/driver/AutoSync/queue.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation + +Module Name: + + queue.h + +Abstract: + + This is a C version of a very simple sample driver that illustrates + how to use the driver framework and demonstrates best practices. + +--*/ + +// Set max write length for testing +#define MAX_WRITE_LENGTH 1024*40 + +// Set timer period in ms +#define TIMER_PERIOD 1000*2 + +// +// This is the context that can be placed per queue +// and would contain per queue information. +// +typedef struct _QUEUE_CONTEXT { + + // Here we allocate a buffer from a test write so it can be read back + WDFMEMORY WriteMemory; + + // Timer DPC for this queue + WDFTIMER Timer; + + // Virtual I/O + WDFREQUEST CurrentRequest; + NTSTATUS CurrentStatus; + +} QUEUE_CONTEXT, *PQUEUE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) + +NTSTATUS +EchoQueueInitialize( + WDFDEVICE hDevice + ); + +EVT_WDF_IO_QUEUE_CONTEXT_DESTROY_CALLBACK EchoEvtIoQueueContextDestroy; + +// +// Events from the IoQueue object +// +EVT_WDF_REQUEST_CANCEL EchoEvtRequestCancel; +EVT_WDF_IO_QUEUE_IO_READ EchoEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE EchoEvtIoWrite; + +NTSTATUS +EchoTimerCreate( + IN WDFTIMER* pTimer, + IN WDFQUEUE Queue + ); + +EVT_WDF_TIMER EchoEvtTimerFunc; diff --git a/general/echo/umdf2/exe/echoapp.cpp b/general/echo/umdf2/exe/echoapp.cpp new file mode 100644 index 00000000..9649a407 --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.cpp @@ -0,0 +1,700 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ioctl.cpp + +Abstract: + + A simple asynch test for usb driver. + + +Environment: + + user mode only + +--*/ + + +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#define INITGUID + +#include <windows.h> +#include <strsafe.h> +#include <setupapi.h> +#include <stdio.h> +#include <stdlib.h> +#include "public.h" + +#define NUM_ASYNCH_IO 100 +#define BUFFER_SIZE (40*1024) + +#define READER_TYPE 1 +#define WRITER_TYPE 2 + +#define MAX_DEVPATH_LENGTH 256 + +BOOLEAN G_PerformAsyncIo; +BOOLEAN G_LimitedLoops; +ULONG G_AsyncIoLoopsNum; +CHAR G_DevicePath[MAX_DEVPATH_LENGTH]; + + +ULONG +AsyncIo( + PVOID ThreadParameter + ); + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ); + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ); + + +int __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE th1 = NULL; + BOOLEAN result = TRUE; + + + if (argc > 1) { + if(!_strnicmp (argv[1], "-Async", 6) ) { + G_PerformAsyncIo = TRUE; + if (argc > 2) { + G_AsyncIoLoopsNum = atoi(argv[2]); + G_LimitedLoops = TRUE; + } + else { + G_LimitedLoops = FALSE; + } + + } else { + printf("Usage:\n"); + printf(" Echoapp.exe --- Send single write and read request synchronously\n"); + printf(" Echoapp.exe -Async --- Send reads and writes asynchronously without terminating\n"); + printf(" Echoapp.exe -Async <number> --- Send <number> reads and writes asynchronously\n"); + printf("Exit the app anytime by pressing Ctrl-C\n"); + result = FALSE; + goto exit; + } + } + + if ( !GetDevicePath( + (LPGUID) &GUID_DEVINTERFACE_ECHO, + G_DevicePath, + sizeof(G_DevicePath)/sizeof(G_DevicePath[0])) ) + { + result = FALSE; + goto exit; + } + + printf("DevicePath: %s\n", G_DevicePath); + + hDevice = CreateFile(G_DevicePath, + GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + 0, + NULL ); + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Failed to open device. Error %d\n",GetLastError()); + result = FALSE; + goto exit; + } + + printf("Opened device successfully\n"); + + if(G_PerformAsyncIo) { + + printf("Starting AsyncIo\n"); + + // + // Create a reader thread + // + th1 = CreateThread( NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) AsyncIo, // Thread Func + (LPVOID)READER_TYPE, + 0, // Creation Flags + NULL ); // Don't need the Thread Id. + + if (th1 == NULL) { + printf("Couldn't create reader thread - error %d\n", GetLastError()); + result = FALSE; + goto exit; + } + + // + // Use this thread for peforming write. + // + result = (BOOLEAN)AsyncIo((PVOID)WRITER_TYPE); + + }else { + // + // Write pattern buffers and read them back, then verify them + // + result = PerformWriteReadTest(hDevice, 512); + if(!result) { + goto exit; + } + + result = PerformWriteReadTest(hDevice, 30*1024); + if(!result) { + goto exit; + } + + } + +exit: + + if (th1 != NULL) { + WaitForSingleObject(th1, INFINITE); + CloseHandle(th1); + } + + if (hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + return ((result == TRUE) ? 0 : 1); + +} + +PUCHAR +CreatePatternBuffer( + IN ULONG Length + ) +{ + unsigned int i; + PUCHAR p, pBuf; + + pBuf = (PUCHAR)malloc(Length); + if( pBuf == NULL ) { + printf("Could not allocate %d byte buffer\n",Length); + return NULL; + } + + p = pBuf; + + for(i=0; i < Length; i++ ) { + *p = (UCHAR)i; + p++; + } + + return pBuf; +} + +BOOLEAN +VerifyPatternBuffer( + _In_reads_bytes_(Length) PUCHAR pBuffer, + _In_ ULONG Length + ) +{ + unsigned int i; + PUCHAR p = pBuffer; + + for( i=0; i < Length; i++ ) { + + if( *p != (UCHAR)(i & 0xFF) ) { + printf("Pattern changed. SB 0x%x, Is 0x%x\n", + (UCHAR)(i & 0xFF), *p); + return FALSE; + } + + p++; + } + + return TRUE; +} + +BOOLEAN +PerformWriteReadTest( + IN HANDLE hDevice, + IN ULONG TestLength + ) +/* +*/ +{ + ULONG bytesReturned =0; + PUCHAR WriteBuffer = NULL, + ReadBuffer = NULL; + BOOLEAN result = TRUE; + + WriteBuffer = CreatePatternBuffer(TestLength); + if( WriteBuffer == NULL ) { + + result = FALSE; + goto Cleanup; + } + + ReadBuffer = (PUCHAR)malloc(TestLength); + if( ReadBuffer == NULL ) { + + printf("PerformWriteReadTest: Could not allocate %d " + "bytes ReadBuffer\n",TestLength); + + result = FALSE; + goto Cleanup; + + } + + // + // Write the pattern to the device + // + bytesReturned = 0; + + if (!WriteFile ( hDevice, + WriteBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: WriteFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes written is not test length! Written %d, " + "SB %d\n",bytesReturned, TestLength); + + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Written successfully\n", + bytesReturned); + } + + bytesReturned = 0; + + if ( !ReadFile (hDevice, + ReadBuffer, + TestLength, + &bytesReturned, + NULL)) { + + printf ("PerformWriteReadTest: ReadFile failed: " + "Error %d\n", GetLastError()); + + result = FALSE; + goto Cleanup; + + } else { + + if( bytesReturned != TestLength ) { + + printf("bytes Read is not test length! Read %d, " + "SB %d\n",bytesReturned, TestLength); + + // + // Note: Is this a Failure Case?? + // + result = FALSE; + goto Cleanup; + } + + printf ("%d Pattern Bytes Read successfully\n",bytesReturned); + } + + // + // Now compare + // + if( !VerifyPatternBuffer(ReadBuffer, TestLength) ) { + + printf("Verify failed\n"); + + result = FALSE; + goto Cleanup; + } + + printf("Pattern Verified successfully\n"); + +Cleanup: + + // + // Free WriteBuffer if non NULL. + // + if (WriteBuffer) { + free (WriteBuffer); + } + + // + // Free ReadBuffer if non NULL + // + if (ReadBuffer) { + free (ReadBuffer); + } + + return result; +} + + + +ULONG +AsyncIo( + PVOID ThreadParameter + ) +{ + HANDLE hDevice = INVALID_HANDLE_VALUE; + HANDLE hCompletionPort = NULL; + OVERLAPPED *pOvList = NULL; + PUCHAR buf = NULL; + ULONG numberOfBytesTransferred; + OVERLAPPED *completedOv; + ULONG_PTR i; + ULONG ioType = (ULONG)(ULONG_PTR)ThreadParameter; + ULONG_PTR key; + ULONG error; + BOOLEAN result = TRUE; + ULONG maxPendingRequests = NUM_ASYNCH_IO; + ULONG remainingRequestsToSend = 0; + ULONG remainingRequestsToReceive = 0; + + hDevice = CreateFile(G_DevicePath, + GENERIC_WRITE|GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + NULL ); + + + if (hDevice == INVALID_HANDLE_VALUE) { + printf("Cannot open %s error %d\n", G_DevicePath, GetLastError()); + result = FALSE; + goto Error; + } + + hCompletionPort = CreateIoCompletionPort(hDevice, NULL, 1, 0); + if (hCompletionPort == NULL) { + printf("Cannot open completion port %d \n",GetLastError()); + result = FALSE; + goto Error; + } + + // + // We will only have NUM_ASYNCH_IO or G_AsyncIoLoopsNum pending at any + // time (whichever is less) + // + if (G_LimitedLoops == TRUE) { + remainingRequestsToReceive = G_AsyncIoLoopsNum; + if (G_AsyncIoLoopsNum > NUM_ASYNCH_IO) { + // + // After we send the initial NUM_ASYNCH_IO, we will have additional + // (G_AsyncIoLoopsNum - NUM_ASYNCH_IO) I/Os to send + // + maxPendingRequests = NUM_ASYNCH_IO; + remainingRequestsToSend = G_AsyncIoLoopsNum - NUM_ASYNCH_IO; + } + else { + maxPendingRequests = G_AsyncIoLoopsNum; + remainingRequestsToSend = 0; + + } + } + + pOvList = (OVERLAPPED *)malloc(maxPendingRequests * sizeof(OVERLAPPED)); + if (pOvList == NULL) { + printf("Cannot allocate overlapped array \n"); + result = FALSE; + goto Error; + } + + buf = (PUCHAR)malloc(maxPendingRequests * BUFFER_SIZE); + if (buf == NULL) { + printf("Cannot allocate buffer \n"); + result = FALSE; + goto Error; + } + + ZeroMemory(pOvList, maxPendingRequests * sizeof(OVERLAPPED)); + ZeroMemory(buf, maxPendingRequests * BUFFER_SIZE); + + // + // Issue asynch I/O + // + + for (i = 0; i < maxPendingRequests; i++) { + if (ioType == READER_TYPE) { + if ( ReadFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Read failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + + } else { + if ( WriteFile( hDevice, + buf + (i* BUFFER_SIZE), + BUFFER_SIZE, + NULL, + &pOvList[i]) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf(" %dth Write failed %d \n",i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + + // + // Wait for the I/Os to complete. If one completes then reissue the I/O + // + + WHILE (1) { + + if ( GetQueuedCompletionStatus(hCompletionPort, &numberOfBytesTransferred, &key, &completedOv, INFINITE) == 0) { + printf("GetQueuedCompletionStatus failed %d\n", GetLastError()); + result = FALSE; + goto Error; + } + + // + // Read successfully completed. If we're doing unlimited I/Os then Issue another one. + // + + if (ioType == READER_TYPE) { + + i = completedOv - pOvList; + printf("Number of bytes read by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( ReadFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + printf("%dth Read failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } else { + + i = completedOv - pOvList; + + printf("Number of bytes written by request number %d is %d\n", i, numberOfBytesTransferred); + + // + // If we're done with the I/Os, then exit + // + if (G_LimitedLoops == TRUE) { + if ((--remainingRequestsToReceive) == 0) { + break; + } + + if (remainingRequestsToSend == 0) { + continue; + } + else { + remainingRequestsToSend--; + } + } + + + if ( WriteFile( hDevice, + buf + (i * BUFFER_SIZE), + BUFFER_SIZE, + NULL, + completedOv) == 0) { + error = GetLastError(); + if (error != ERROR_IO_PENDING) { + + printf("%dth write failed %d \n", i, GetLastError()); + result = FALSE; + goto Error; + } + } + } + } + +Error: + if(hDevice != INVALID_HANDLE_VALUE) { + CloseHandle(hDevice); + } + + if(hCompletionPort) { + CloseHandle(hCompletionPort); + } + + if(buf) { + free(buf); + } + if(pOvList) { + free(pOvList); + } + + return (ULONG)result; + +} + + +BOOL +GetDevicePath( + IN LPGUID InterfaceGuid, + _Out_writes_(BufLen) PCHAR DevicePath, + _In_ size_t BufLen + ) +{ + HDEVINFO HardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData = NULL; + ULONG Length, RequiredLength = 0; + BOOL bResult; + HRESULT hr; + + HardwareDeviceInfo = SetupDiGetClassDevs( + InterfaceGuid, + NULL, + NULL, + (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)); + + if (HardwareDeviceInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed!\n"); + return FALSE; + } + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + bResult = SetupDiEnumDeviceInterfaces(HardwareDeviceInfo, + 0, + InterfaceGuid, + 0, + &DeviceInterfaceData); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + )) { + + printf("SetupDiEnumDeviceInterfaces failed: %s", (LPTSTR)lpMsgBuf); + LocalFree(lpMsgBuf); + } + + printf("SetupDiEnumDeviceInterfaces failed.\n"); + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + return FALSE; + } + + SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + NULL, + 0, + &RequiredLength, + NULL + ); + + DeviceInterfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, RequiredLength); + + if (DeviceInterfaceDetailData == NULL) { + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Failed to allocate memory.\n"); + return FALSE; + } + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Length = RequiredLength; + + bResult = SetupDiGetDeviceInterfaceDetail( + HardwareDeviceInfo, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + Length, + &RequiredLength, + NULL); + + if (bResult == FALSE) { + + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); + printf("Error in SetupDiGetDeviceInterfaceDetail: %s\n", (LPTSTR)lpMsgBuf); + LocalFree(DeviceInterfaceDetailData); + LocalFree(lpMsgBuf); + return FALSE; + } + + hr = StringCchCopy(DevicePath, + BufLen, + DeviceInterfaceDetailData->DevicePath) ; + + SetupDiDestroyDeviceInfoList(HardwareDeviceInfo); // It must be executed in both success and failure traces + LocalFree(DeviceInterfaceDetailData); + + return ( !FAILED(hr) ); // Result depends on StringCchCopy() +} + diff --git a/general/echo/umdf2/exe/echoapp.vcxproj b/general/echo/umdf2/exe/echoapp.vcxproj new file mode 100644 index 00000000..c8b2000b --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.vcxproj @@ -0,0 +1,171 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{2744B9D7-C918-4979-AF41-3DC6B305BA72}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{725C57DF-D40D-4503-ADBE-A694D0AC15A8}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>echoapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/umdf2/exe/echoapp.vcxproj.Filters b/general/echo/umdf2/exe/echoapp.vcxproj.Filters new file mode 100644 index 00000000..1b67a921 --- /dev/null +++ b/general/echo/umdf2/exe/echoapp.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{A27E5252-132E-4B45-BC34-E21958A5A7B8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{21C62558-1F78-4174-BB6A-42FE9F273912}</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>{D51D868F-D9FD-45A5-B7C1-50CBFF474959}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="echoapp.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdf2/exe/public.h b/general/echo/umdf2/exe/public.h new file mode 100644 index 00000000..d632951d --- /dev/null +++ b/general/echo/umdf2/exe/public.h @@ -0,0 +1,30 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + + +Environment: + + user and kernel + +--*/ + +#define WHILE(a) \ +__pragma(warning(suppress:4127)) while(a) + +// +// Define an Interface Guid so that app can find the device and talk to it. +// + +DEFINE_GUID (GUID_DEVINTERFACE_ECHO, + 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a); +// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A} + diff --git a/general/echo/umdf2/umdf2echo.sln b/general/echo/umdf2/umdf2echo.sln new file mode 100644 index 00000000..f7467745 --- /dev/null +++ b/general/echo/umdf2/umdf2echo.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{5B8D0286-7445-4569-84C3-D5616997F792}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AutoSync", "AutoSync", "{DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{0E50C291-4877-4FE5-A66C-EDEFF747DA75}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoapp", "exe\echoapp.vcxproj", "{2744B9D7-C918-4979-AF41-3DC6B305BA72}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echo", "driver\AutoSync\echo.vcxproj", "{95360722-8B66-4DD4-957A-DF8B7CA700FB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.ActiveCfg = Debug|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|Win32.Build.0 = Debug|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.ActiveCfg = Release|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|Win32.Build.0 = Release|Win32 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.ActiveCfg = Debug|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Debug|x64.Build.0 = Debug|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.ActiveCfg = Release|x64 + {2744B9D7-C918-4979-AF41-3DC6B305BA72}.Release|x64.Build.0 = Release|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.ActiveCfg = Debug|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|Win32.Build.0 = Debug|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.ActiveCfg = Release|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|Win32.Build.0 = Release|Win32 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.ActiveCfg = Debug|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Debug|x64.Build.0 = Debug|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.ActiveCfg = Release|x64 + {95360722-8B66-4DD4-957A-DF8B7CA700FB}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2744B9D7-C918-4979-AF41-3DC6B305BA72} = {5B8D0286-7445-4569-84C3-D5616997F792} + {95360722-8B66-4DD4-957A-DF8B7CA700FB} = {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} + {DAEA5A04-51AB-46D0-B95C-25DA1FEB0B70} = {0E50C291-4877-4FE5-A66C-EDEFF747DA75} + EndGlobalSection +EndGlobal diff --git a/general/echo/umdfSocketEcho/Driver/Connection.cpp b/general/echo/umdfSocketEcho/Driver/Connection.cpp new file mode 100644 index 00000000..e28d0c56 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Connection.cpp @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Connection.cpp + +Abstract: + + Module for the socket connection specfic routines in the driver. + Makes Connection to the server given server host and port address. + +Environment: + + User mode only + + +--*/ + +#include "internal.h" +#include "connection.tmh" + + +CConnection::CConnection() +/*++ + +Routine Description: + + Constructor for connection object + +Arguments: + + None + +Return Value: + + VOID + +--*/ +{ + + // Initialize the socket member as Invalid + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + m_socket = INVALID_SOCKET; +} + +HRESULT +CConnection::Connect( + IN IWDFDevice *pDevice + ) +/*++ + +Routine Description: + + This routine is for the initialization of the connection object associated with + the File Object . It is invoked from the dispatch OnCreateFile on the default + queue callback of the driver. It socket connection to the client. + +Arguments: + + pDevice = Wdf Device Object + +Return Value: + + S_OK if success , error HRESULT otherwise + +--*/ +{ + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + addrinfoW* info = NULL ; + + PWSTR hostStr = NULL; + + PWSTR portStr = NULL; + + // + // Reads the host and port strings stored in the device context. + // + + DeviceContext *pContext = NULL; + + hr = pDevice->RetrieveContext((void**)&pContext); + + if ( FAILED(hr) ) + { + + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: unable to retrieve context from wdf device object %!hresult!", + hr + ); + goto Clean0; + + } + + hostStr = pContext->hostStr; + + portStr = pContext->portStr; + + // + // lookup hostname with addrinfo hints; + // + + addrinfoW hints; + + ZeroMemory(&hints,sizeof(hints)); + + hints.ai_family = AF_INET; + + hints.ai_socktype = SOCK_STREAM; + + hints.ai_protocol = IPPROTO_TCP; + + int n = GetAddrInfoW(hostStr, portStr, &hints, &info); + + if (n != 0) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to find address/port of host %!winerr!", + err + ); + hr = HRESULT_FROM_WIN32(err); + goto Clean0; + } + + // + // Create a socket with this infomation recvd in getaddrinfo + // + m_socket = socket(info->ai_family,info->ai_socktype,info->ai_protocol); + + if (m_socket == INVALID_SOCKET) + { + DWORD err = WSAGetLastError(); + + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to create socket %!winerr!", + err + ); + + hr = HRESULT_FROM_WIN32(err); + + goto Clean0; + } + + // + // If that succeeds , proceed to connect to the socket + // + + + ATLASSERT(info->ai_addrlen <= 0x7fffffff); + + int nret = connect(m_socket,info->ai_addr,(int)info->ai_addrlen); + + if (nret == SOCKET_ERROR) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to connect to host %!winerr!", + err + ); + hr = HRESULT_FROM_WIN32(err); + + goto Clean0; + } + + +Clean0: + + if (info != NULL) + { + FreeAddrInfoW(info); + + } + + if (FAILED(hr) && m_socket != INVALID_SOCKET) + { + closesocket(m_socket); + m_socket = INVALID_SOCKET; + } + + return hr; + +} + +HANDLE +CConnection::GetSocketHandle( + ) +/*++ + +Routine Description: + + Function returns the socket handle associated with this connection object + +Arguments: + + None + +Return Value: + + Socket handle if valid socket + INVALID_HANDLE_VALUE otherwise + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + if ( INVALID_SOCKET != m_socket ) + { + return (HANDLE)m_socket ; + } + else + { + return INVALID_HANDLE_VALUE; + } + +} + + +VOID +CConnection::Close() +/*++ + +Routine Description: + + Closes the socket connection to the server associated with this connection object + +Arguments: + + None + +Return Value: + + None +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + if (m_socket != INVALID_SOCKET) + { + closesocket(m_socket); + m_socket = INVALID_SOCKET; + } + +} diff --git a/general/echo/umdfSocketEcho/Driver/FileContext.h b/general/echo/umdfSocketEcho/Driver/FileContext.h new file mode 100644 index 00000000..dbdda2e4 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/FileContext.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + filecontext.h + +Abstract: + + This header file defines the structure type for file context associated with the file object + +Environment: + + user mode only + +Revision History: + +--*/ + + +#pragma once + +typedef struct _FileContext +{ + CConnection *pConnection ; + + CComPtr<IWDFIoTarget> pFileTarget; + +}FileContext; diff --git a/general/echo/umdfSocketEcho/Driver/Queue.cpp b/general/echo/umdfSocketEcho/Driver/Queue.cpp new file mode 100644 index 00000000..242925d4 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Queue.cpp @@ -0,0 +1,580 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.cpp + +Abstract: + + This file implements the I/O queue interface and performs + the read/write/ioctl operations. + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "internal.h" + +#include "queue.tmh" + +CMyQueue::CMyQueue( + ) : + m_FxQueue(NULL), + m_Device(NULL) +{ +} + +// +// Queue destructor. +// + +CMyQueue::~CMyQueue( + VOID + ) +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); +} + +// +// Initialize +// + +HRESULT +CMyQueue::Initialize( + _In_ CMyDevice * Device + ) +/*++ + +Routine Description: + + Queue Initialize helper routine. + This routine will Create a default parallel queue associated with the Fx device object + and pass the IUnknown for this queue + +Aruments: + Device - Device object pointer + +Return Value: + + S_OK if Initialize succeeds + +--*/ +{ + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + CComPtr<IWDFIoQueue> fxQueue; + + HRESULT hr; + + m_Device = Device; + + // + // Create the I/O Queue object. + // + + { + CComPtr<IUnknown> pUnk; + + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = m_Device->GetFxDevice()->CreateIoQueue( + pUnk, + TRUE, + WdfIoQueueDispatchParallel, + TRUE, + FALSE, + &fxQueue + ); + } + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + "Failed to initialize driver queue %!hresult!", + hr + ); + goto Exit; + } + + m_FxQueue = fxQueue; + + +Exit: + + return hr; +} + +HRESULT +CMyQueue::Configure( + VOID + ) +/*++ + +Routine Description: + + Queue configuration function . + It is called after queue object has been succesfully initialized. + +Aruments: + + NONE + + Return Value: + + S_OK if succeeds. + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + return hr; +} + + +STDMETHODIMP_(void) +CMyQueue::OnCreateFile( + _In_ IWDFIoQueue* pWdfQueue, + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFFile* pWdfFileObject + ) + +/*++ + +Routine Description: + + Create callback from the framework for this default parallel queue + + The create request will create a socket connection , create a file i/o target associated + with the socket handle for this connection and store in the file object context. + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + pWdfFileObject - WDF file object for this create + + Return Value: + + VOID + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr = S_OK; + + CComPtr<IWDFFileHandleTargetFactory> spFileHandleTargetFactory; + + CComPtr<IWDFIoTarget> pFileTarget; + + CComPtr<IWDFDevice> pDevice; + + HANDLE SocketHandle = NULL; + + pWdfQueue->GetDevice(&pDevice); + + FileContext *pContext = NULL; + + // + // Create new connection object + // + + CConnection *pConnection = new CConnection(); + + if (NULL == pConnection ) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not create connection object %!hresult!", + hr + ); + goto Exit; + } + + // + // Connect to the socket server + // + + hr = pConnection->Connect(pDevice); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not connect %!hresult!", + hr + ); + + goto Exit; + + } + + // + // If that succeeds, get socket handle for the connection + // + + if ( NULL == (SocketHandle = pConnection->GetSocketHandle()) ) + { + hr = E_FAIL; + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to obtain valid Socket Handle %!hresult!", + hr + ); + goto Exit; + } + + // + // Create file context for this file object + // + + pContext = new FileContext; + + if (NULL == pContext) + { + hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Could not create file context %!hresult!", + hr + ); + goto Exit; + + } + + // + // QI for IWDFFileHandleTargetFactory from the framework device object. + // Note UmdfDispatcher in Wdf Section in the Inf + // + + hr = pDevice->QueryInterface(IID_PPV_ARGS(&spFileHandleTargetFactory)); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to obtain target factory for creating FileHandle based I/O target %!hresult!", + hr + ); + goto Exit; + } + + // + // If that succeeds, Create a File Handle I/O Target and associate the socket handle with this target + // + + hr = spFileHandleTargetFactory->CreateFileHandleTarget(SocketHandle ,&pFileTarget); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to create framework I/O target %!hresult!", + hr + ); + goto Exit; + } + + + pContext->pFileTarget = pFileTarget; + + pContext->pConnection = pConnection; + + hr = pWdfFileObject->AssignContext(NULL,(void*)pContext); + + if (FAILED(hr)) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Unable to Assign Context to this File Object %!hresult!", + hr + ); + goto Exit; + } + + + +Exit: + + if (FAILED(hr)) + { + + if ( pFileTarget ) + { + pFileTarget->DeleteWdfObject(); + } + + if (pConnection != NULL) + { + delete pConnection; + pConnection = NULL; + } + + if (pContext != NULL) + { + delete pContext; + pContext = NULL; + } + + } + + pWdfRequest->Complete(hr); + +} + + +STDMETHODIMP_ (void) +CMyQueue::OnWrite( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToWrite + ) +/*++ + +Routine Description: + + Write callback from the framework for this default parallel queue + + The write request needs to be sent to the file handle i/o target associated with this fileobject + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToWrite - Lenth of bytes in the write buffer + + Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(BytesToWrite); + + // Call helper function to send request to i/o target + + SendRequestToFileTarget(pWdfRequest); + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + return; +} + +STDMETHODIMP_ (void) +CMyQueue::OnRead( + _In_ IWDFIoQueue *pWdfQueue, + _In_ IWDFIoRequest *pWdfRequest, + _In_ SIZE_T BytesToRead + ) +/*++ + +Routine Description: + + Read callback from the framework for this default parallel queue + + The read request needs to be sent to the file handle i/o target associated with this fileobject + +Aruments: + + pWdfQueue - Framework Queue instance + pWdfRequest - Framework Request instance + BytesToRead - Lenth of bytes in the read buffer + + +Return Value: + + VOID + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pWdfQueue); + UNREFERENCED_PARAMETER(BytesToRead); + + // + // Call helper function to send request to i/o target + // + + SendRequestToFileTarget(pWdfRequest); + + return; +} + +STDMETHODIMP_(void) +CMyQueue::OnCompletion( + _In_ IWDFIoRequest* pWdfRequest, + _In_ IWDFIoTarget* pTarget, + _In_ IWDFRequestCompletionParams* pCompletionParams, + _In_ void* pContext +) +/*++ + +Routine Description: + + This routine is invoked when the request is completed by the lower stack location, + in this case the win32 i/o target associated with the file object of this request + + + Arguments: + + pWdfRequest - wdf request + pTarget - wdf target to which request was earlier sent + pCompletionParams - wdf request completion parameters + pContext - Context information , if any + + +Return Value: + + None +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pTarget); + UNREFERENCED_PARAMETER(pContext); + + // Complete request from the driver + pWdfRequest->CompleteWithInformation( + pCompletionParams->GetCompletionStatus(), + pCompletionParams->GetInformation()); +} + +VOID +CMyQueue::SendRequestToFileTarget( + _In_ IWDFIoRequest* pWdfRequest +) +/*++ + +Routine Description: + + This is a helper functiom to send R/W requests to the win32 file i/o target + associated with the socket connection for this request. + First, filecontext is retrieved which has the file i/o target where this request needs to be sent. + + +Arguments: + + pWdfRequest - wdf request + +Return Value: + + None + +--*/ +{ + + HRESULT hr; + + FileContext *pContext = NULL; + CComPtr<IWDFFile> pWdfFile = NULL; + + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + // + // Get the file object for this request + // + + pWdfRequest->GetFileObject(&pWdfFile); + + // + // Retrieve Context from file object + // + + hr = pWdfFile->RetrieveContext((void**)&pContext); + + if (pContext == NULL) + { + if ( SUCCEEDED(hr) ) + { + hr = E_FAIL; + Trace(TRACE_LEVEL_ERROR, + " No Context associated with this file object %!hresult!", + hr); + } + goto Exit; + } + + // + // If that succeeds, set completion callback for the request + // + pWdfRequest->SetCompletionCallback(CComQIPtr<IRequestCallbackRequestCompletion>(this), + NULL); + + // + // Do not modify the request, format using current type + // + + pWdfRequest->FormatUsingCurrentType(); + + // + // Send the request to the win32 i/o target . This was created in OnCreateFile + // + + hr = pWdfRequest->Send(pContext->pFileTarget, + 0, + 0); +Exit: + + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Could not send request to i/o target %!hresult!", + hr); + pWdfRequest->Complete(hr); + } + + return ; +} + +STDMETHODIMP_(void) +CMyQueue::OnCleanup( + _In_ IWDFObject* /*pWdfObject*/ + ) +{ + // + // CMyQueue has a reference to framework device object via m_FxQueue. + // Framework queue object has a reference to CMyQueue object via the callbacks. + // This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. + // To break the circular reference we release the reference to the framework queue object here in OnCleanup. + // + m_FxQueue = NULL; +} diff --git a/general/echo/umdfSocketEcho/Driver/Queue.h b/general/echo/umdfSocketEcho/Driver/Queue.h new file mode 100644 index 00000000..952e1e0d --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/Queue.h @@ -0,0 +1,83 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + queue.h + +Abstract: + + This file defines the queue callback interface. + +Environment: + + user mode only + +Revision History: + +--*/ + +#pragma once + +// +// Queue Callback Object. +// + +class ATL_NO_VTABLE CMyQueue : + public CComObjectRootEx<CComMultiThreadModel>, + public IQueueCallbackCreate, + public IQueueCallbackRead, + public IQueueCallbackWrite, + public IRequestCallbackRequestCompletion, + public IObjectCleanup +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyQueue) + +BEGIN_COM_MAP(CMyQueue) + COM_INTERFACE_ENTRY(IQueueCallbackCreate) + COM_INTERFACE_ENTRY(IQueueCallbackRead) + COM_INTERFACE_ENTRY(IQueueCallbackWrite) + COM_INTERFACE_ENTRY(IRequestCallbackRequestCompletion) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + //IQueueCallbackRead + STDMETHOD_(void,OnRead)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWdfRequest,_In_ SIZE_T NumOfBytesToRead); + + //IQueueCallbackWrite + STDMETHOD_(void,OnWrite)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWdfRequest,_In_ SIZE_T NumOfBytesToWrite); + + //IQueueCallbackCreate + STDMETHOD_(void,OnCreateFile)(_In_ IWDFIoQueue* pWdfQueue,_In_ IWDFIoRequest* pWDFRequest,_In_ IWDFFile* pWdfFileObject); + + // IRequestCallbackRequestCompletion + STDMETHOD_(void,OnCompletion)(_In_ IWDFIoRequest* pWdfRequest,_In_ IWDFIoTarget* pTarget,_In_ IWDFRequestCompletionParams* pCompletionParams,_In_ void* pContext); + + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + +public: + CMyQueue(); + ~CMyQueue(); + + STDMETHOD(Initialize)(_In_ CMyDevice * Device); + + HRESULT + Configure( + ); + +private: + CComPtr<IWDFIoQueue> m_FxQueue; + + // + // Unreferenced pointer to the parent device. + // + + CMyDevice * m_Device; + + VOID SendRequestToFileTarget( _In_ IWDFIoRequest* pWdfRequest); +}; diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.inx b/general/echo/umdfSocketEcho/Driver/SocketEcho.inx new file mode 100644 index 00000000..d9ed27ea --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.inx @@ -0,0 +1,89 @@ +; +; SocketEcho.inf +; + +[Version] +Signature="$WINDOWS NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFT% +CatalogFile=wudf.cat +DriverVer=03/20/2003,5.00.3788 + +[Manufacturer] +%MSFTWUDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%SocketEchoName%=SocketEcho_Install,WUDF\SocketEcho + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll=1 +SocketEcho.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== WUDF SocketEcho Test Driver ================================== + +[SocketEcho_Install] +CopyFiles=UMDFDriverCopy + +[SocketEcho_Install.hw] +AddReg=SocketEcho_AddReg + +[SocketEcho_Install.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[SocketEcho_Install.CoInstallers] +AddReg = SocketEcho_Install.CoInstallers_AddReg +CopyFiles = CoInstallers_CopyFiles + +[SocketEcho_Install.CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WudfUpdate_$UMDFCOINSTALLERVERSION$.dll" + + + +[CoInstallers_CopyFiles] +WudfUpdate_$UMDFCOINSTALLERVERSION$.dll + +[SocketEcho_Install.Wdf] +UmdfService=SocketEcho, SocketEcho_Driver_Install +UmdfServiceOrder=SocketEcho +UmdfDispatcher=FileHandle + +[SocketEcho_AddReg] +HKR,"SocketEcho","Host",0x00000000,"localhost" +HKR,"SocketEcho","Port",0x00000000,"6000" + +[WUDFRD_ServiceInstall] +ServiceType=1 +StartType=3 +ErrorControl=1 +ServiceBinary=%12%\WUDFRd.sys + +[SocketEcho_Driver_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID="{83B87D35-76B8-4920-B43C-3BDE6B0EC5B8}" +ServiceBinary="%12%\UMDF\SocketEcho.dll" + +[DestinationDirs] +UMDFDriverCopy=12,UMDF + +[UMDFDriverCopy] +SocketEcho.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +; =================== Generic ================================== + +[Strings] +MSFT="Microsoft" +MSFTWUDF="Microsoft Internal (WUDF)" +MediaDescription="Microsoft WUDF Sample Driver Installation Media" +ClassName="Sample Device" +SocketEchoName="Sample WUDF SocketEcho Driver" diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.rc b/general/echo/umdfSocketEcho/Driver/SocketEcho.rc new file mode 100644 index 00000000..cc27b15f --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// Skeleton.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Sample WUDF SocketEcho Driver" +#define VER_INTERNALNAME_STR "SocketEcho" +#define VER_ORIGINALFILENAME_STR "SocketEcho.dll" + +#include "common.ver" diff --git a/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj new file mode 100644 index 00000000..d9930170 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj @@ -0,0 +1,245 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{DA04694B-6179-416F-83FF-53A671E51B26}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; driver.cpp; device.cpp; queue.cpp; connection.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="SocketEcho.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\SocketEcho.inf</CopyOutput> + </Inf> + <OtherWpp Include="SocketEcho.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SocketEcho</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\user32.lib;$(SDK_LIB_PATH)\ole32.lib;$(SDK_LIB_PATH)\oleaut32.lib;$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\shlwapi.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib;$(SDK_LIB_PATH)\Ws2_32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="SocketEcho.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters new file mode 100644 index 00000000..539cbe3b --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/SocketEcho.vcxproj.Filters @@ -0,0 +1,54 @@ +<?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>{BEDB1CCE-4E58-4AE0-B5B6-C54C6159232D}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{07B8152F-B3FA-4EA1-BBCD-EABDD1B7FCAB}</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>{61C11142-602D-496E-B9EB-516ED5D7685B}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{2BB65E51-CB92-4484-AD29-5ED2A6007684}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="connection.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="queue.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\SocketEcho.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="SocketEcho.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="SocketEcho.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdfSocketEcho/Driver/connection.h b/general/echo/umdfSocketEcho/Driver/connection.h new file mode 100644 index 00000000..2b7e23c6 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/connection.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Connection.h + +Abstract: + + Header file for the socketecho connection class + +Environment: + + User mode only + + +--*/ +#pragma once + +class CConnection +{ +public: + CConnection(); + HRESULT Connect(IN IWDFDevice *pDevice); + VOID Close(); + HANDLE GetSocketHandle( ); + +private: + SOCKET m_socket; +}; + diff --git a/general/echo/umdfSocketEcho/Driver/device.cpp b/general/echo/umdfSocketEcho/Driver/device.cpp new file mode 100644 index 00000000..9c3e4db1 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/device.cpp @@ -0,0 +1,469 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF socketecho sample + driver's device callback object. + + It does not implement either of the PNP interfaces so once the device + is setup, it won't ever get any callbacks until the device is removed. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "device.tmh" + +const GUID GUID_DEVINTERFACE_SOCKETECHO = + {0xcdc35b6e, 0xbe4, 0x4936, { 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a }}; + + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver* FxDriver, + _In_ IWDFDeviceInitialize* FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + FxDriver - IWDF Driver for this device. + + Return Value: + + status. + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + CComPtr<IWDFDevice> fxDevice; + HRESULT hr; + BOOL bFilter = FALSE; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set the locking model + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // Mark filter if we are a filter + // + + if (bFilter) + { + FxDeviceInit->SetFilter(); + } + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + CComPtr<IUnknown> pUnk; + HRESULT hrQI = this->QueryInterface(__uuidof(IUnknown),(void**)&pUnk); + WUDF_SAMPLE_DRIVER_ASSERT(SUCCEEDED(hrQI)); + + hr = FxDriver->CreateDevice(FxDeviceInit, pUnk, &fxDevice); + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + None + + Return Value: + + status + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr; + CComObject<CMyQueue> * defaultQueue = NULL; + + // + // Create a new instance of our queue callback object + // + hr = CComObject<CMyQueue>::CreateInstance(&defaultQueue); + + if (SUCCEEDED(hr)) + { + defaultQueue->AddRef(); + hr = defaultQueue->Initialize(this); + } + + if (SUCCEEDED(hr)) + { + hr = defaultQueue->Configure(); + } + + // + // Create and Enable Device Interface for this device. + // + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_SOCKETECHO, + NULL); + } + if (SUCCEEDED(hr)) + { + hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_SOCKETECHO, + NULL, + TRUE); + } + + if (SUCCEEDED(hr)) + { + hr = ReadAndAssignPropertyStoreValue(); + } + + // + // Release the reference we took on the queue callback object. + // The framework took its own references on the object's callback interfaces + // when we called m_FxDevice->CreateIoQueue, and will manage the object's lifetime. + // + SAFE_RELEASE(defaultQueue); + + return hr; +} + +STDMETHODIMP_(void) +CMyDevice::OnCloseFile( + _In_ IWDFFile* pWdfFileObject + ) +/*++ + + Routine Description: + + This method is called when an app closes the file handle to this device. + This will free the context memory associated with this file object, close + the connection object associated with this file object and delete the file + handle i/o target object associated with this file object. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr = S_OK ; + FileContext *pContext = NULL; + + hr = pWdfFileObject->RetrieveContext((void**)&pContext); + + if (SUCCEEDED(hr) && (pContext != NULL ) ) + { + pContext->pConnection->Close(); + pContext->pFileTarget->DeleteWdfObject(); + + delete pContext->pConnection; + delete pContext; + } + + return ; +} + + +STDMETHODIMP_(void) +CMyDevice::OnCleanupFile( + _In_ IWDFFile* pWdfFileObject + ) +/*++ + + Routine Description: + + This method is when app with open handle device terminates. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(pWdfFileObject); +} + +STDMETHODIMP_(void) +CMyDevice::OnCleanup( + _In_ IWDFObject* pWdfObject + ) +/*++ + + Routine Description: + + This device callback method is invoked by the framework when the WdfObject + is about to be released by the framework. This will free the context memory + associated with the device object. + + Arguments: + + pWdfObject - the framework device object for which OnCleanup. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + HRESULT hr ; + DeviceContext *pContext = NULL; + + WUDF_SAMPLE_DRIVER_ASSERT(pWdfObject == m_FxDevice); + + hr = pWdfObject->RetrieveContext((void**)&pContext); + + if (SUCCEEDED(hr) && (pContext != NULL)) + { + // hostStr is allocated through StrDup, and thus need be freed through LocalFree + // + if (pContext->hostStr != NULL) + { + LocalFree( pContext->hostStr ); + } + + if (pContext->portStr != NULL) + { + LocalFree( pContext->portStr ); + } + + delete pContext; + } +// +//CMyDevice has a reference to framework device object via m_Device. +//Framework device object has a reference to CMyDevice object via the callbacks. +//This leads to circular reference and both the objects can't be destroyed until this circular reference is broken. +//To break the circular reference we release the reference to the framework device object here in OnCleanup. + + m_FxDevice = NULL; +} + +HRESULT +CMyDevice::ReadAndAssignPropertyStoreValue( + VOID + ) +/*++ + + Routine Description: + Helper function for reading property store values and storing them in the + device level context. + + Arguments: + + pWdfFileObject - the framework file object for which close is handled. + + Return Value: + + None + +--*/ +{ + Trace(TRACE_LEVEL_INFORMATION, "%!FUNC!"); + + CComPtr<IWDFNamedPropertyStore> pPropStore; + WDF_PROPERTY_STORE_DISPOSITION disposition; + PROPVARIANT val; + HRESULT hr ; + + PropVariantInit(&val); + + DeviceContext *pContext = new DeviceContext; + if (pContext == NULL) + { + hr = E_OUTOFMEMORY; + Trace(TRACE_LEVEL_ERROR, + L"ERROR: Could not create device context object %!hresult!", + hr); + + goto CleanUp; + } + + pContext->hostStr = NULL; + pContext->portStr = NULL; + + // + // Retreive property store for reading drivers custom settings as specified + // in the INF + // + hr = m_FxDevice->RetrieveDevicePropertyStore(L"SocketEcho", + WdfPropertyStoreNormal, + &pPropStore, + &disposition); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to retrieve device property store for reading custom " + "settings as specified in the INF %!hresult!", + hr); + + goto CleanUp; + } + + // + // Get the key for this device with Named value "host" + // + hr = pPropStore->GetNamedValue(L"Host", &val); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to get \"Host\" key value %!hresult!", + hr); + + goto CleanUp; + } + + if (val.vt != VT_LPWSTR) + { + hr = HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION); + Trace(TRACE_LEVEL_ERROR, + "Unexpected string format for value in \"Host\" key %!hresult!", + hr); + + goto CleanUp; + } + + pContext->hostStr = StrDup(val.pwszVal); + + // + // Clear property variant for reading next key + // + PropVariantClear(&val); + + // + // Get the key for this device with Named value "Port" + // + hr = pPropStore->GetNamedValue(L"Port", &val); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to get \"Port\" key value %!hresult!", + hr); + + goto CleanUp; + } + + if (val.vt != VT_LPWSTR) + { + hr = HRESULT_FROM_WIN32(ERROR_BAD_CONFIGURATION); + Trace(TRACE_LEVEL_ERROR, + "Unexpected string format for value in \"Port\" key %!hresult!", + hr); + + goto CleanUp; + } + + pContext->portStr = StrDup(val.pwszVal); + + hr = m_FxDevice->AssignContext(NULL, (void*)pContext); + if (FAILED(hr)) + { + Trace(TRACE_LEVEL_ERROR, + "Failed to assign property store value to device %!hresult!", + hr); + + // + // Fall through to clean up and exit ... + // + } + +CleanUp: + + PropVariantClear(&val); + + if (FAILED(hr)) + { + if (pContext != NULL) + { + // hostStr is allocated through StrDup, and thus need be freed through LocalFree + // + if (pContext->hostStr != NULL) + { + LocalFree( pContext->hostStr ); + } + + if (pContext->portStr != NULL) + { + LocalFree( pContext->portStr ); + } + + delete pContext; + } + } + + return hr; +} + diff --git a/general/echo/umdfSocketEcho/Driver/device.h b/general/echo/umdfSocketEcho/Driver/device.h new file mode 100644 index 00000000..176f10e6 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/device.h @@ -0,0 +1,70 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF Skeleton sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Class for the iotrace driver. +// + +class ATL_NO_VTABLE CMyDevice : + public CComObjectRootEx<CComMultiThreadModel>, + public IFileCallbackCleanup, + public IFileCallbackClose, + public IObjectCleanup +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDevice) + +BEGIN_COM_MAP(CMyDevice) + COM_INTERFACE_ENTRY(IFileCallbackCleanup) + COM_INTERFACE_ENTRY(IFileCallbackClose) + COM_INTERFACE_ENTRY(IObjectCleanup) +END_COM_MAP() + +public: + + //IFileCallbackCleanup + STDMETHOD_(void,OnCleanupFile)(_In_ IWDFFile* pWdfFileObject); + //IFileCallbackClose + STDMETHOD_(void,OnCloseFile)(_In_ IWDFFile* pWdfFileObject); + //IObjectCleanup + STDMETHOD_(void,OnCleanup)(_In_ IWDFObject* pWdfObject); + +public: + + STDMETHOD(Initialize)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + + HRESULT + Configure( + ); + + IWDFDevice * + GetFxDevice( + ) + { + return m_FxDevice; + } + +private: + CComPtr<IWDFDevice> m_FxDevice; + HRESULT ReadAndAssignPropertyStoreValue(); + +}; diff --git a/general/echo/umdfSocketEcho/Driver/devicecontext.h b/general/echo/umdfSocketEcho/Driver/devicecontext.h new file mode 100644 index 00000000..2bf10d2e --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/devicecontext.h @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + devicecontext.h + +Abstract: + + This header file defines the structure type for device context associated with the device object + +Environment: + + user mode only + +Revision History: + +--*/ + + +#pragma once + + +typedef struct _DeviceContext +{ + PWSTR hostStr; + + PWSTR portStr; + +}DeviceContext; + diff --git a/general/echo/umdfSocketEcho/Driver/dllsup.cpp b/general/echo/umdfSocketEcho/Driver/dllsup.cpp new file mode 100644 index 00000000..5ec3eb33 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/dllsup.cpp @@ -0,0 +1,111 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Socktecho Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the socktecho uses + L"Microsoft\\UMDF\\Socketecho" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +class CSocketEchoModule : public CAtlDllModuleT< CSocketEchoModule > +{ +}; + + +OBJECT_ENTRY_AUTO(CLSID_MyDriverCoClass, CMyDriver) + + +CSocketEchoModule _AtlModule; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID Reserved + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER( ModuleHandle ); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return _AtlModule.DllMain(Reason, Reserved); +; +} + +_Check_return_ +STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID* ppv) +{ + return _AtlModule.DllGetClassObject(rclsid, riid, ppv); +} diff --git a/general/echo/umdfSocketEcho/Driver/driver.cpp b/general/echo/umdfSocketEcho/Driver/driver.cpp new file mode 100644 index 00000000..4f93691c --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/driver.cpp @@ -0,0 +1,174 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Socketecho Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +STDMETHODIMP +CMyDriver::OnInitialize( + _In_ IWDFDriver* pWdfDriver + ) + + +/*++ + + Routine Description: + + This routine is invoked by the framework at driver load . + This method will invoke the Winsock Library for using + Winsock API in this driver. + + Arguments: + + pWdfDriver - Framework driver object + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ + +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + UNREFERENCED_PARAMETER(pWdfDriver); + + WORD sockVersion; + WSADATA wsaData; + + sockVersion = MAKEWORD(2, 0); + + int result = WSAStartup(sockVersion, &wsaData); + + if (result != 0) + { + DWORD err = WSAGetLastError(); + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Failed to initialize Winsock 2.0 %!winerr!", + err + ); + return HRESULT_FROM_WIN32(err); + } + + return S_OK; +} + +STDMETHODIMP_(void) +CMyDriver::OnDeinitialize( + _In_ IWDFDriver* pWdfDriver + ) + +/*++ + Routine Description: + + The FX invokes this method when it unloads the driver. + This routine will Cleanup Winsock library + + Arguments: + + pWdfDriver - the Fx driver object. + + Return Value: + + None + + + --*/ + +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + UNREFERENCED_PARAMETER(pWdfDriver); + + WSACleanup(); +} + +STDMETHODIMP +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + Trace( + TRACE_LEVEL_INFORMATION, + "%!FUNC!" + ); + + HRESULT hr; + + CComObject<CMyDevice> * device = NULL; + + // + // Create a new instance of our device callback object + // + + hr = CComObject<CMyDevice>::CreateInstance(&device); + + if (SUCCEEDED(hr)) + { + device->AddRef(); + hr = device->Initialize(FxWdfDriver, FxDeviceInit); + } + + // + // If that succeeded then call the device's configure method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference we took on the device callback object. + // The framework took its own references on the object's callback interfaces + // when we called FxWdfDriver->CreateDevice, and will manage the object's lifetime. + // + SAFE_RELEASE(device); + + return hr; +} diff --git a/general/echo/umdfSocketEcho/Driver/driver.h b/general/echo/umdfSocketEcho/Driver/driver.h new file mode 100644 index 00000000..6affa20f --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/driver.h @@ -0,0 +1,53 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF Socketecho sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the socktecho sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +extern const GUID CLSID_MyDriverCoClass; + +class ATL_NO_VTABLE CMyDriver : + public CComObjectRootEx<CComMultiThreadModel>, + public CComCoClass<CMyDriver, &CLSID_MyDriverCoClass>, + public IDriverEntry +{ +public: + +DECLARE_NOT_AGGREGATABLE(CMyDriver) + +DECLARE_CLASSFACTORY(); + +DECLARE_NO_REGISTRY(); + +BEGIN_COM_MAP(CMyDriver) + COM_INTERFACE_ENTRY(IDriverEntry) +END_COM_MAP() + +public: + // IDriverEntry + STDMETHOD(OnInitialize)(_In_ IWDFDriver* pWdfDriver); + STDMETHOD(OnDeviceAdd)(_In_ IWDFDriver* pWdfDriver, _In_ IWDFDeviceInitialize* pWdfDeviceInit); + STDMETHOD_(void,OnDeinitialize)(_In_ IWDFDriver* pWdfDriver); +}; + diff --git a/general/echo/umdfSocketEcho/Driver/exports.def b/general/echo/umdfSocketEcho/Driver/exports.def new file mode 100644 index 00000000..2c0b7d49 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/exports.def @@ -0,0 +1,6 @@ +; Socketecho.def : Declares the module parameters. + +LIBRARY "SocketEcho" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/general/echo/umdfSocketEcho/Driver/internal.h b/general/echo/umdfSocketEcho/Driver/internal.h new file mode 100644 index 00000000..a7875468 --- /dev/null +++ b/general/echo/umdfSocketEcho/Driver/internal.h @@ -0,0 +1,117 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Socketecho sample + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the winsock headers before any other windows headers. +// +#include <winsock2.h> +#include <ws2tcpip.h> + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Define the tracing flags. +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (64316518,DFE2,42B6,8786,4995E5EC435), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\SocketEcho" +#define MYDRIVER_CLASS_ID { 0x83B87D35, 0x76B8, 0x4920, {0xB4, 0x3C, 0x3B, 0xDE, 0x6B, 0x0E, 0xC5, 0xB8} } + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) {if ((p)) { (p)->Release(); (p) = NULL; }} +#endif + +__forceinline +#ifdef _PREFAST_ +__declspec(noreturn) +#endif +VOID +WdfTestNoReturn( + VOID + ) +{ + // do nothing. +} + +#define WUDF_SAMPLE_DRIVER_ASSERT(p) \ +{ \ + if ( !(p) ) \ + { \ + DebugBreak(); \ + WdfTestNoReturn(); \ + } \ +} + +// +// Include the type specific headers. +// +#include <atlbase.h> +#include <atlcom.h> + +#include "connection.h" +#include "filecontext.h" +#include "devicecontext.h" +#include "driver.h" +#include "device.h" +#include "queue.h" + +_Analysis_mode_(_Analysis_operator_new_null_) + diff --git a/general/echo/umdfSocketEcho/Exe/internal.h b/general/echo/umdfSocketEcho/Exe/internal.h new file mode 100644 index 00000000..ff1cd863 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/internal.h @@ -0,0 +1,18 @@ +// internal.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include <driverspecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_); +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <strsafe.h> +#include <setupapi.h> + +#include "socketechoserver.h" diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp new file mode 100644 index 00000000..bfe5f546 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.cpp @@ -0,0 +1,512 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + socketserver.cpp + +Abstract: + + A simple socket server application that listens on a specified port and echoes back data + received. + +Environment: + + User Mode + +--*/ + +#include "internal.h" + + +DWORD +Run( + LPVOID lpThreadParameter + ) + /*++ + +Routine Description: + + This routine is invoked for each thread created for a new connection accepted by the server. + The rcv and send to socket happen in this thread routine. + + +Arguments: + + lpThreadParameter , The Thread parameter which contains socket information + +Return Value: + + Thread Exit Code + + +--*/ +{ + #define DeleteBufferExitThread(dwExitCode) \ + delete[] buffer; \ + buffer = NULL; \ + ExitThread(dwExitCode); + + #define DeleteBufferReturn(dwExitCode) \ + delete[] buffer; \ + buffer = NULL; \ + return dwExitCode; + + int count =0; + + char *buffer = new char[DATA_LENGTH]; + if (NULL == buffer) + { + ExitThread(1); + } + + DWORD Event; + + // + // Look at socket information from thread arg. + // + + + CEchoServer *pThreadData = (CEchoServer*)lpThreadParameter; + if (pThreadData==NULL) + { + DeleteBufferExitThread(1); + } + + SOCKET sClient = pThreadData->m_socket; + HANDLE NetworkEvent = pThreadData->m_NetworkEvent; + WSANETWORKEVENTS NetworkEvents; + printf("Client Start: 0x%Ix\n", sClient); + int actual = 0; + for(;;) + { + if ((Event = WSAWaitForMultipleEvents( + 1, + &NetworkEvent, + FALSE, + WSA_INFINITE, + FALSE)) == WSA_WAIT_FAILED) + { + printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError()); + DeleteBufferReturn(0); + } + + if (WSAEnumNetworkEvents(sClient ,NetworkEvent, &NetworkEvents) == SOCKET_ERROR) + { + printf("WSAEnumNetworkEvents failed with error %d\n", WSAGetLastError()); + DeleteBufferReturn(0); + } + + if (NetworkEvents.lNetworkEvents & FD_READ) + { + if (NetworkEvents.lNetworkEvents & FD_READ && NetworkEvents.iErrorCode[FD_READ_BIT] != 0) + { + printf("FD_READ failed with error %d\n", NetworkEvents.iErrorCode[FD_READ_BIT]); + } + else + { + + actual = recv(sClient,buffer,DATA_LENGTH*sizeof(char),0); + // + // socket connection has been reset ,so bail out . + // + if (actual == 0 || actual == WSAECONNRESET ) + { + printf(" Could not get data , Error : 0x%lx \n",WSAGetLastError()); + break; // socket shut-down + + } + printf("FD_READ read buffer on client 0x%Ix with length %d \n",sClient,actual); + count = send(sClient, (const char*)buffer,actual,0); + if ( count == SOCKET_ERROR ) + { + if ( WSAGetLastError()== WSAEWOULDBLOCK ) + { + printf(" Could not send data as resource is unavaliable , do not retry until next Write event \n"); + } + else + { + printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError()); + break; + } + } + else + { + printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count); + } + } + } + // + // if there is a write network event and there is data to write , write that + // + if (NetworkEvents.lNetworkEvents & FD_WRITE) + { + if (NetworkEvents.lNetworkEvents & FD_WRITE && NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0) + { + printf("FD_WRITE failed with error %d\n", NetworkEvents.iErrorCode[FD_WRITE_BIT]); + } + else + { + count = send(sClient, (const char*)buffer,actual,0); + if ( count == SOCKET_ERROR ) + { + if ( WSAGetLastError()== WSAEWOULDBLOCK ) + { + printf(" Could not send data as resource is unavaliable , do not retry until next Write event "); + } + else + { + printf(" Could not send data , Error : 0x%lx \n",WSAGetLastError()); + break; + } + } + else + { + printf("FD_WRITE write buffer on client 0x%Ix with length %d \n",sClient,count); + } + actual = 0; + } + } + if (NetworkEvents.lNetworkEvents & FD_CLOSE) + { + shutdown(sClient,FD_READ|FD_WRITE); + printf(" recived a close from client : 0x%Ix \n",sClient); + closesocket(sClient); + DeleteBufferExitThread(0); + } + } + + DeleteBufferReturn(1); + +} + +CEchoServer::CEchoServer( + SOCKET socketclient + ) +/*++ + +Routine Description: + + This is the constructor routine for CEchoServer class. This is called for each instance of new + connection accepted by the server . + +Arguments: + + Socket received from the accept + +Return Value: + + None . + +--*/ +{ + m_socket = socketclient; + m_NetworkEvent = WSACreateEvent(); + printf("socket created : 0x%Ix \n", m_socket); + +} + +void +CEchoServer::Start() +/*++ + +Routine Description: + + This routine is to Start the thread which will rcv and send the data recieved on this instance of socket connection. + + +Arguments: + + None. + +Return Value: + + None. +--*/ +{ + + + if(WSAEventSelect( + m_socket, + m_NetworkEvent, + FD_READ|FD_WRITE|FD_CLOSE)== SOCKET_ERROR) + { + printf("Error in Event Select,Cannot start Server thread for this socket \n"); + closesocket(m_socket); + goto Exit; + } +// +// Create thread to read/write data to this socket +// + + HANDLE hRunThread = CreateThread( + NULL, // Default Security Attrib. + 0, // Initial Stack Size, + (LPTHREAD_START_ROUTINE) Run, // Thread Func + this, // Arg to Thread Func. + 0, // Creation Flags + NULL // Don't need the Thread Id. + ); + if (NULL == hRunThread) + { + printf(" Could not create socket server run thread : 0x%lx \n", GetLastError()); + closesocket(m_socket); + goto Exit; + } + +Exit: + + return ; + } + +void +SocketServerMain( + _In_ unsigned short uPort + ) +/*++ + +Routine Description: + + This routine is the main entry for the app when the app is configured to + be a socket server. + It creates a a listening socket for incoming conenctions. + + +Arguments: + + uPort - Port Number that the socket server binds to + +Return Value: + + None. +--*/ +{ + + + SOCKET ListenSocket; + int iResult; + #pragma warning( suppress: 24002 ) // suppress warning for IPv6 ,currently IPv4 specific + sockaddr_in service ; + + // Initialize Winsock 2.2 + WSADATA wsaData; + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if ( NO_ERROR != iResult ) + { + printf("Error at WSAStartup() \n"); + goto Exit; + } + // + // Create a SOCKET for listening for incoming connection requests. + // + ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if ( INVALID_SOCKET == ListenSocket) + { + printf("Error at socket(): %ld\n ", WSAGetLastError()); + goto Cleanup; + } + // The sockaddr_in structure specifies the address family, + // IP address, and port for the socket that is being bound. + service.sin_family = AF_INET; + // + // Suppress overflow warning. + // inet_pton is annotated to write sizeof(IN6_ADDR) bytes to pAddrBuf, + // but it only writes sizeof(IN_ADDR) bytes when Family is AF_INET (IPv4). + // https://msdn.microsoft.com/en-us/library/windows/desktop/cc805844(v=vs.85).aspx + // + #pragma warning( suppress: 26000 ) + iResult = inet_pton(AF_INET, "127.0.0.1", &service.sin_addr); + if (iResult != 1) + { + printf("Error at inet_pton(): %ld\n ", WSAGetLastError()); + closesocket(ListenSocket); + goto Cleanup; + } + service.sin_port = htons(uPort); + if (SOCKET_ERROR == bind( + ListenSocket, + (SOCKADDR*) &service, + sizeof(service) ) ) + { + printf("bind() failed. \n"); + closesocket(ListenSocket); + goto Cleanup; + } + + // + // Listen for incoming connection requests + // on the created socket upto MAX_CONNECTIONS + // + if ( SOCKET_ERROR == listen( + ListenSocket, + MAX_CONNECTIONS ) ) + { + printf("Error listening on socket.\n"); + } + printf("Listening on socket...\n"); + + // + // Set Socket RCVBUF and SNDBUF size to DATA_LENGTH , so large requests are not fragmented . + // + int iOptVal; + int iOptLen = sizeof(int); + + if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_RCVBUF value: %ld\n", iOptVal); + } + iOptVal = DATA_LENGTH; + iOptLen = sizeof(int); + if (setsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR) + { + printf("Set SO_RCVBUF: ON\n"); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_RCVBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_RCVBUF Value: %ld\n", iOptVal); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_SNDBUF value: %ld\n", iOptVal); + } + iOptVal = DATA_LENGTH; + iOptLen = sizeof(int); + if (setsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, iOptLen) != SOCKET_ERROR) + { + printf("Set SO_SNDBUF: ON\n"); + } + iOptLen = sizeof(int); + if (getsockopt(ListenSocket, SOL_SOCKET, SO_SNDBUF, (char*)&iOptVal, &iOptLen) != SOCKET_ERROR) + { + printf("SO_SNDBUF Value: %ld\n", iOptVal); + } + +// +// Loop the server to start accepting connections from clients on this socket +// + + for(;;) + { + CEchoServer *client = new CEchoServer(accept(ListenSocket,NULL,NULL)); + + if (client) + { + printf("Client connected.\n"); + client->Start(); // Start receiving/sending data on the socket + } + } + +Cleanup: + // + // Invoke Winsock Cleanup + // + + WSACleanup(); + + Exit: + return; + +} +void +Usage() + +/*++ + +Routine Description: + + This routine is invoked to display the usage of this application + +Arguments: + + None. + +Return Value: + + None . +--*/ + +{ + printf("\n\n Usage: \n"); + printf(" ------ \n\n"); + printf(" socketechoapp Display Usage \n"); + printf(" socketechoapp -h Display Usage\n"); + printf(" socketechoapp -p Start the app as server listening on default port\n"); + printf(" socketechoapp -p [port#] Start the app as server listening on this port \n"); + + + +} + + +/* */ +void __cdecl +main( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) + +/*++ + +Routine Description: + + + +Arguments: + + None. + +Return Value: + + None. +--*/ +{ + unsigned short argIndex = 1 ; + unsigned short uPort = DEFAULT_PORT_ADDRESS ; + + + if (argc < 2) + { + Usage(); + goto Exit; + } + +// +// look at second arg and check for either -h which indicates user asked for help in Usage +// of this commandline +// + + if (!strcmp(*(argv+argIndex),"-h")) + { + Usage(); + goto Exit; + } +// +// check if its -p and proceed with otherwise show usage +// + else if (!strcmp(*(argv+argIndex),"-p")) + { + // + // look at third arg, which should be the port# + // + if ( ++argIndex < argc ) + { + uPort = (unsigned short)atoi(*(argv+(argIndex))); + } + SocketServerMain(uPort); + + } + else + { + Usage(); + goto Exit; + } + +Exit: + return; + +} + + diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.h b/general/echo/umdfSocketEcho/Exe/socketechoserver.h new file mode 100644 index 00000000..f71bc48b --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + sockechoserver.h + +Abstract: + + Header file for the socket server module of the socketecho application + +Environment: + + User mode only + +--*/ + +#pragma once + + +#define MAX_CONNECTIONS 5 +#define DEFAULT_PORT_ADDRESS 6000 +#define DATA_LENGTH 1024*40 + +void +SocketServerMain( + _In_ unsigned short uPort + ); + + // + // Class definition for CEchoServer Class + // +class CEchoServer +{ + + public: + + SOCKET m_socket; + HANDLE m_NetworkEvent; + + + + CEchoServer(SOCKET socketclient); + void Start(); + +}; + diff --git a/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj new file mode 100644 index 00000000..ea299161 --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj @@ -0,0 +1,179 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4237BF5F-1426-45DD-96E0-74DEADFA24C6}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{13151EE8-4C58-4284-BA01-C4B9431C6B06}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>socketechoserver</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);user32.lib;Ws2_32.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="socketechoserver.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters new file mode 100644 index 00000000..035fba1a --- /dev/null +++ b/general/echo/umdfSocketEcho/Exe/socketechoserver.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{1BEC8228-FE60-4512-B036-885F56208A4B}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{E4060FEA-373E-4AE6-94B7-FF878D406EAE}</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>{181042B8-D282-46BA-B9D7-BDEE33402D00}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="socketechoserver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/echo/umdfSocketEcho/ReadMe.md b/general/echo/umdfSocketEcho/ReadMe.md new file mode 100644 index 00000000..12515365 --- /dev/null +++ b/general/echo/umdfSocketEcho/ReadMe.md @@ -0,0 +1,184 @@ +UMDF SocketEcho Sample (UMDF Version 1) +======================================= + +The UMDF SocketEcho sample demonstrates how to use the User-Mode Driver Framework (UMDF) to write a driver and demonstrates best practices. + +This sample also demonstrates how to use a default parallel dispatch I/O queue, use a Microsoft Win32 dispatcher, and handle a socket handle by using a Win32 file I/O target. + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + +Code Tour +--------- + +Parts of this code sample are generated from the ATL Project Wizard in Microsoft Visual Studio 2005. This sample driver is a minimal driver that is intended to demonstrate how to use UMDF. It is not intended for use in a production environment. + +CMyDriver::OnInitialize in driver.cpp is called by the framework when the driver loads. This method initiates use of the Winsock Library. CMyDriver::OnDeviceAdd in driver.cpp is called by the framework to install the driver on a device stack. OnDeviceAdd creates a device callback object, and then calls IWDFDriver::CreateDevice to create an framework device object and to associate the device callback object with the framework device object. + +CMyQueue::OnCreateFile in queue.cpp is called by the framework to create a socket connection, create a file i/o target that is associated with the socket handle for this connection, and store the socket handle in the file object context. + +Installation +------------ + +In Visual Studio, you can press F5 to build the sample and then deploy it to a target machine. For more information, see [Deploying a Driver to a Test Computer](http://msdn.microsoft.com/en-us/library/windows/hardware/hh454834). Alternatively, you can install the sample from the command line. + +To test this sample, you must have a test computer that is running Windows Vista or later. This test computer can be a second computer or, if necessary, your development computer. + +To install the UMDF Echo sample driver from the command line, do the following: + +1. Copy the driver binary and the socketecho.inf file to a directory on your test computer (for example, C:\\ socketechoSample.) + +2. Copy the UMDF coinstaller, WUDFUpdate\_*MMmmmm*.dll, from the \\redist\\wdf\\\<architecture\> directory to the same directory (for example, C:\\socketechoSample). + + **Note** + + You can obtain redistributable framework updates by downloading the *wdfcoinstaller.msi* package from [WDK 8 Redistributable Components](http://go.microsoft.com/fwlink/p/?LinkID=226396). This package performs a silent install into the directory of your Windows Driver Kit (WDK) installation. You will see no confirmation that the installation has completed. You can verify that the redistributables have been installed on top of the WDK by ensuring there is a redist\\wdf directory under the root directory of the WDK, %ProgramFiles(x86)%\\Windows Kits\\8.0. + +3. + + Navigate to the directory that contains the INF file and binaries (for example, cd /d c:\\socketechoSample), and run DevCon.exe as follows: + + **devcon.exe install socketecho.inf WUDF\\socketecho** + + You can find DevCon.exe in the \\tools directory of the WDK (for example, \\tools\\devcon\\i386\\devcon.exe). + +To update the socketecho driver after you make any changes, do the following: + +1. Increment the version number in the INF file. This change is not necessary, but it will help ensure that Plug and Play (PnP) selects your new driver as a better match for the device. + +2. Copy the updated driver binary and the socketecho.inf file to a directory on your test computer (for example, C:\\ socketechoSample.) + +3. Navigate to the directory that contains the INF file and binaries (for example, cd /d c:\\ socketechoSample), and run devcon.exe as follows: + + devcon.exe update socketecho.inf WUDF\\socketecho + +To test this sample drivers on a checked operating system that you have installed (in contrast to the standard retail installations), you must modify the INF file to use the checked version of the UMDF co-installer. That is, you must do the following: + +1. In the INX file, replace all occurrences of WudfUpdate\_*MMmmmm*.dll with WudfUpdate\_*MMmmmm*\_chk.dll. + +2. Copy the WudfUpdate\_*MMmmmm*\_chk.dll file from the \\redist\\wdf\\\<architecture\> directory to your driver package instead of WudfUpdate\_*MMmmmm*.dll. + +3. If WdfCoinstaller*MMmmmm*.dll or WinUsbCoinstaller.dll is included in your driver package, repeat step 1 and step 2 for them. + +Testing +------- + +To test the SocketEcho driver, you can run socketechoserver.exe, which is built from the src\\general\\echo\\umdfSocketEcho\\Exe directory, and echoapp.exe, which is built from the Kernel-Mode Driver Framework (KMDF) samples in the src\\general\\echo\\kmdf directory. + +First, you must install the device as described earlier. Then, run socketechoserver.exe from a Command Prompt window. + +D:\\\>socketechoserver -h + +Usage: + +------ + +socketechoserver Display Usage + +socketechoserver -h Display Usage + +socketechoserver -p Start the app as server listening on default port + +socketechoserver -p [port\#] Start the app as server listening on this port + +D:\\\>socketechoserver -p + +Listening on socket... + +In another Command Prompt window, run echoapp.exe. + +D:\\\>echoapp + +DevicePath: \\\\?\\root\#sample\#0000\#{ e5e65b0c-82c8-4689-96d4-f77837971990} + +Opened device successfully + +512 Pattern Bytes Written successfully + +512 Pattern Bytes Read successfully + +Pattern Verified successfully + +D:\\\>echoapp -Async + +DevicePath: \\\\?\\root\#sample\#0000\#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a} + +Opened device successfully + +Starting AsyncIo + +Number of bytes written by request number 0 is 1024 + +Number of bytes read by request number 0 is 1024 + +Number of bytes read by request number 1 is 1024 + +Number of bytes written by request number 2 is 1024 + +Number of bytes read by request number 2 is 1024 + +Number of bytes written by request number 3 is 1024 + +Number of bytes read by request number 3 is 1024 + +Number of bytes written by request number 4 is 1024 + +Number of bytes read by request number 4 is 1024 + +Number of bytes written by request number 5 is 1024 + +Number of bytes read by request number 5 is 1024 + +Number of bytes written by request number 6 is 1024 + +Number of bytes read by request number 6 is 1024 + +Number of bytes written by request number 7 is 1024 + +Number of bytes read by request number 7 is 1024 + +Number of bytes written by request number 8 is 1024 + +Number of bytes read by request number 8 is 1024 + +Number of bytes written by request number 9 is 1024 + +Number of bytes read by request number 9 is 1024 + +Number of bytes written by request number 10 is 1024 + +Number of bytes read by request number 10 is 1024 + +Number of bytes written by request number 11 is 1024 + +... + +Note that independent threads perform the reads and writes in the echo test application. As a result, the order of the output might not exactly match what you see in the preceding output. + +File Manifest +------------- + +<table> +<colgroup> +<col width="50%" /> +<col width="50%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">File +Description</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left"><p>Socketecho.htm</p> +<p>The documentation for this sample.</p></td> +<td align="left"><p>Dllsup.cpp</p> +<p>The DLL support code that provides the DLL's entry point and the single required export (DllGetClassObject).</p></td> +</tr> +</tbody> +</table> + + diff --git a/general/echo/umdfSocketEcho/umdfsocketecho.sln b/general/echo/umdfSocketEcho/umdfsocketecho.sln new file mode 100644 index 00000000..9cd8f76d --- /dev/null +++ b/general/echo/umdfSocketEcho/umdfsocketecho.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{C4B24CED-B58F-47D1-8FC0-778610EF84CF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{AFCDA28A-1D07-410D-BA77-47E637336CA6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SocketEcho", "Driver\SocketEcho.vcxproj", "{ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "socketechoserver", "Exe\socketechoserver.vcxproj", "{4237BF5F-1426-45DD-96E0-74DEADFA24C6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.ActiveCfg = Debug|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|Win32.Build.0 = Debug|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.ActiveCfg = Release|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|Win32.Build.0 = Release|Win32 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.ActiveCfg = Debug|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Debug|x64.Build.0 = Debug|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.ActiveCfg = Release|x64 + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3}.Release|x64.Build.0 = Release|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.ActiveCfg = Debug|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|Win32.Build.0 = Debug|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.ActiveCfg = Release|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|Win32.Build.0 = Release|Win32 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.ActiveCfg = Debug|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Debug|x64.Build.0 = Debug|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.ActiveCfg = Release|x64 + {4237BF5F-1426-45DD-96E0-74DEADFA24C6}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {ABEFFAA1-36CF-4F78-9A6B-10EAEC11B3E3} = {C4B24CED-B58F-47D1-8FC0-778610EF84CF} + {4237BF5F-1426-45DD-96E0-74DEADFA24C6} = {AFCDA28A-1D07-410D-BA77-47E637336CA6} + EndGlobalSection +EndGlobal diff --git a/general/event/ReadMe.md b/general/event/ReadMe.md new file mode 100644 index 00000000..8b8bebaa --- /dev/null +++ b/general/event/ReadMe.md @@ -0,0 +1,25 @@ +Hardware Event Sample +===================== + +This sample demonstrates two different ways a Windows kernel-mode driver can notify an application about a hardware event. One way uses an event-based method, and the other uses an IRP-based method. Because the sample driver is not talking to any real hardware, it uses a timer DPC to simulate hardware events. The test application informs the driver whether it wants to be notified by signaling an event or by completing the pending IRP. Additionally, the test application specifies a relative time at which the DPC timer must fire. + +*Event-based approach:* The application calls the [**CreateEvent**](http://msdn.microsoft.com/en-us/library/windows/hardware/ms682396) function to create an event. It then passes the event handle to the driver in an I/O control request that uses a private IOCTL code, IOCTL\_REGISTER\_EVENT. Because the driver is a monolithic, top-level driver, its IRP dispatch routines run in the application process context and, as a result, the event handle is still valid in the driver. The driver dereferences the user-mode handle into system space and saves the event object pointer for later use. Next, the driver queues a custom timer DPC. When the DPC fires, the driver signals the event by calling the [**KeSetEvent**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff553253) routine at DISPATCH\_LEVEL, and deletes the references to the event object. You can't use this approach if your driver is not a monolithic, top-level driver; that is because a driver can't guarantee the process context in a multi-level driver stack if the driver is not at the top of the stack. + +*Pending IRP-based approach:* The application makes a synchronous IOCTL\_REGISTER\_EVENT request. The driver sets the status of the device I/O control request to IRP pending, queues a timer DPC, and returns STATUS\_PENDING. When the timer fires to indicate a hardware event, the driver completes the pending IRP to notify the application about the hardware event. + +There are two advantages of IRP-based approach over the event-based approach. First, the driver can send a message to the application along with the event notification. Second, the driver routines don't have to run in the context of the process that made the request. Instead, the application can send a synchronous or asynchronous (overlapped) I/O control request to the driver. + +**Note** This sample driver is not a Plug and Play driver. This is a minimal driver meant to demonstrate a feature of the operating system. Neither this driver nor its sample programs are intended for use in a production environment. Rather, they are intended for educational purposes and as a skeleton driver. + + +Run the sample +-------------- + +To test this driver, copy the test application, event.exe, and the driver to the same directory, and run the application. The application will automatically load the driver, if it's not already loaded, and interact with the driver. When you exit the app, the driver will be stopped, unloaded, and removed. + +To run the test application, enter the following command in the command window: + +`C:\>event.exe <Delay> <0|1>` + +The first command-line parameter, `Delay`, equals the time, in seconds, to delay the event signal. For the second command-line parameter, specify 0 for IRP-based notification and 1 for event-based notification. + diff --git a/general/event/eventsample.sln b/general/event/eventsample.sln new file mode 100644 index 00000000..1b533282 --- /dev/null +++ b/general/event/eventsample.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{AD60DF57-AE60-4857-9CAE-41B96E1E0789}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wdm", "Wdm", "{1403EA42-4F69-4B63-B15F-3447F44A500A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "exe\event.vcxproj", "{19EFCD7C-6C7A-427A-84D2-A62D9073146A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "event", "wdm\event.vcxproj", "{99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|Win32.ActiveCfg = Debug|Win32 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|Win32.Build.0 = Debug|Win32 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|Win32.ActiveCfg = Release|Win32 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|Win32.Build.0 = Release|Win32 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|x64.ActiveCfg = Debug|x64 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Debug|x64.Build.0 = Debug|x64 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|x64.ActiveCfg = Release|x64 + {19EFCD7C-6C7A-427A-84D2-A62D9073146A}.Release|x64.Build.0 = Release|x64 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|Win32.ActiveCfg = Debug|Win32 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|Win32.Build.0 = Debug|Win32 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|Win32.ActiveCfg = Release|Win32 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|Win32.Build.0 = Release|Win32 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|x64.ActiveCfg = Debug|x64 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Debug|x64.Build.0 = Debug|x64 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|x64.ActiveCfg = Release|x64 + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {19EFCD7C-6C7A-427A-84D2-A62D9073146A} = {AD60DF57-AE60-4857-9CAE-41B96E1E0789} + {99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B} = {1403EA42-4F69-4B63-B15F-3447F44A500A} + EndGlobalSection +EndGlobal diff --git a/general/event/exe/event.vcxproj b/general/event/exe/event.vcxproj new file mode 100644 index 00000000..1ec7b921 --- /dev/null +++ b/general/event/exe/event.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{19EFCD7C-6C7A-427A-84D2-A62D9073146A}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{B020889A-CDA3-4F73-AA14-45C800A49925}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>event</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\wdm</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x400000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="eventtest.c" /> + <ClCompile Include="install.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/event/exe/event.vcxproj.Filters b/general/event/exe/event.vcxproj.Filters new file mode 100644 index 00000000..7cdaec8b --- /dev/null +++ b/general/event/exe/event.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{F62E2250-4375-47E7-8996-8B59DCFCFCF8}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{B34D45F9-19AD-4EA0-A3AA-ABDD239D4829}</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>{F9F32DF2-C4E0-45E6-9964-FE9DAA47CC64}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="eventtest.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/event/exe/eventtest.c b/general/event/exe/eventtest.c new file mode 100644 index 00000000..e1b03204 --- /dev/null +++ b/general/event/exe/eventtest.c @@ -0,0 +1,266 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + EventTest.c + +Abstract: + + Simple console test app for the event.sys driver. + +Enviroment: + + User Mode + +Revision History: + +--*/ + +// +// INCLUDES +// +#include <windows.h> +#include <winioctl.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <conio.h> +#include <strsafe.h> +#include "public.h" + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ); + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ); + +#define USAGE() {\ + printf("event <delay> <0/1>\n");\ + printf("\twhere <delay> = time to delay the event signal in seconds.\n");\ + printf("\t 0 for IRP based and 1 for event based notification.\n");\ +} + +// +// MAIN +// +VOID __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + BOOL bStatus; + HANDLE hDevice; + ULONG ulReturnedLength; + REGISTER_EVENT registerEvent; + FLOAT fDelay = 3; + UINT type = EVENT_BASED; + DWORD errNum = 0; + TCHAR driverLocation[MAX_PATH] = { 0 }; + + + if ( (argc < 3) || (argv[1] == NULL) || (argv[2] == NULL) ) { + USAGE(); + exit(1); + } + + if (sscanf_s( argv[1], "%f", &fDelay ) == 0) { + printf("sscanf_s failed\n"); + exit(1); + } + + if (sscanf_s( argv[2], "%d", &type ) == 0) { + printf("sscanf_s failed\n"); + exit(1); + } + + // + // open the device + // + if ((hDevice = CreateFile( + "\\\\.\\Event_Sample", // lpFileName + GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess + FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode + NULL, // lpSecurityAttributes + OPEN_EXISTING, // dwCreationDistribution + 0, // dwFlagsAndAttributes + NULL // hTemplateFile + )) == INVALID_HANDLE_VALUE) { + + errNum = GetLastError(); + + if (errNum != ERROR_FILE_NOT_FOUND) { + + printf("CreateFile failed! ERROR_FILE_NOT_FOUND = %d\n", errNum); + + return ; + } + + // + // The driver is not started yet so let us the install driver. + // First setup full path to driver name. + // + + if (!SetupDriverName(driverLocation, sizeof(driverLocation) )) { + + return ; + } + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + printf("Unable to install driver. \n"); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return; + } + + // + // Now open the device again. + // + hDevice = CreateFile( + "\\\\.\\Event_Sample", // lpFileName + GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess + FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode + NULL, // lpSecurityAttributes + OPEN_EXISTING, // dwCreationDistribution + 0, // dwFlagsAndAttributes + NULL // hTemplateFile + ); + + if ( hDevice == INVALID_HANDLE_VALUE ){ + printf ( "Error: CreatFile Failed : %d\n", GetLastError()); + return; + } + + } + + // + // set the event signal delay. Use relative time for this sample + // + registerEvent.DueTime.QuadPart = -((LONGLONG)(fDelay * 10.0E6)); + registerEvent.Type = type; + + if (type == EVENT_BASED) { + // + // + // + registerEvent.hEvent = CreateEvent( + NULL, // lpEventAttributes + TRUE, // bManualReset + FALSE, // bInitialState +#ifdef DBG + "TEST_EVENT" // use WinObj to view named events for DBG +#else + NULL // lpName +#endif + ); + + + if ( !registerEvent.hEvent ) { + printf("CreateEvent error = %d\n", GetLastError() ); + } else { + + printf("Event HANDLE = %p\n", registerEvent.hEvent ); + printf("Press any key to exit.\n"); + while( !_kbhit() ) { + bStatus = DeviceIoControl( + hDevice, // Handle to device + IOCTL_REGISTER_EVENT, // IO Control code + ®isterEvent, // Input Buffer to driver. + SIZEOF_REGISTER_EVENT, // Length of input buffer in bytes. + NULL, // Output Buffer from driver. + 0, // Length of output buffer in bytes. + &ulReturnedLength, // Bytes placed in buffer. + NULL // synchronous call + ); + + if ( !bStatus ) { + printf("Ioctl failed with code %d\n", GetLastError() ); + break; + } else { + printf("Waiting for Event...\n"); + + WaitForSingleObject(registerEvent.hEvent, + INFINITE ); + + printf("Event signalled.\n\n"); + + ResetEvent( registerEvent.hEvent); + //printf("Event reset.\n"); + } + } + } + + }else if (type == IRP_BASED) { + + printf("Press any key to exit.\n"); + registerEvent.hEvent = NULL; + registerEvent.Type = IRP_BASED; + + while( !_kbhit() ) { + bStatus = DeviceIoControl( + hDevice, // Handle to device + IOCTL_REGISTER_EVENT, // IO Control code + ®isterEvent, // Input Buffer to driver. + SIZEOF_REGISTER_EVENT, // Length of input buffer in bytes. + NULL, // Output Buffer from driver. + 0, // Length of output buffer in bytes. + &ulReturnedLength, // Bytes placed in buffer. + NULL // synchronous call + ); + + if ( !bStatus ) { + printf("Ioctl failed with code %d\n", GetLastError() ); + break; + } + printf("Event occurred.\n\n"); + printf("\nRegistering event again....\n\n"); + } + + }else { //unknown type + USAGE(); + } + + // + // close the handle to the device. + // + CloseHandle(hDevice); + + // + // Unload the driver if loaded. Ignore any errors. + // + if (driverLocation[0] != (TCHAR)0) { + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + } + + return; +} diff --git a/general/event/exe/install.c b/general/event/exe/install.c new file mode 100644 index 00000000..b52178e5 --- /dev/null +++ b/general/event/exe/install.c @@ -0,0 +1,558 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + +--*/ + + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strsafe.h> +#include "public.h" + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else if (err == ERROR_SERVICE_MARKED_FOR_DELETE) { + // + // Previous instance of the service is not fully deleted so sleep + // and try again. + // + printf("Previous instance of the service is not fully deleted. Try again...\n"); + return FALSE; + } + else { + + printf("CreateService failed! Error = %d \n", err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + printf("Invalid Driver or Service provided to ManageDriver() \n"); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + printf("Open SC Manager failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + printf("Unknown ManageDriver() function. \n"); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + if (schSCManager) { + + CloseServiceHandle(schSCManager); + } + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("DeleteService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("StartService failure! Error = %d \n", err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("ControlService failed! Error = %d \n", GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle (schService); + } + + return rCode; + +} // StopDriver + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ) +{ + HANDLE fileHandle; + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(BufferLength, + DriverLocation + ); + + if (driverLocLen == 0) { + + printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Setup path name to driver file. + // + if (FAILED( StringCbCat(DriverLocation, BufferLength, "\\"DRIVER_NAME".sys") )) { + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + printf("%s.sys is not loaded.\n", DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName + + + diff --git a/general/event/wdm/event.c b/general/event/wdm/event.c new file mode 100644 index 00000000..64bae443 --- /dev/null +++ b/general/event/wdm/event.c @@ -0,0 +1,1070 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Event.c + +Abstract: + + The purpose of this sample is to demonstrate how a kernel-mode driver can notify + an user-app about a device event. There are several different techniques. This sample + will demonstrate two very commonly used techniques. + + 1) Using an event: + The application creates an event object using CreateEvent(). + The app passes the event handle to the driver in a private IOCTL. + The driver is running in the app's thread context during the IOCTL so + there is a valid user-mode handle at that time. + The driver dereferences the user-mode handle into system space & saves + the event object pointer for later use. + The driver signals the event via KeSetEvent() at IRQL <= DISPATCH_LEVEL. + The driver deletes the references to the event object. + + 2) Pending Irp: This technique is useful if you want to send a message + to the app along with the notification. In this, an application sends + a synchronous or asynchronous (overlapped) ioctl to the driver. The driver + would then pend the IRP until the device event occurs. When the hardware + event occurs, the driver will complete the IRP. This will cause the thread that + sent the request to come out of DeviceIoControl call if it's synchronous or signal + the event that the thread is waiting on in the usermode it's has done a + OVERLAPPED call. Another advantage of this technique over the event model + is that the driver doesn't have to be in the context of the process that + sent the IOCTL request. You can't guarantee the process context in multi-level + drivers. + + 3) Using WMI to fire events. Check the wmifilter sample in the DDK. + + 4) Using PNP custom notification scheme. Walter Oney's book describes this. + Can be used only in PNP drivers. + + 4) Named events: In that an app creates a named event in the usermode + and driver opens that in kernel and signal it. This technique is deprecated + by the kb article (Q228785) + + This sample demonstrates the first two techniques. This sample is an + improvised version of the event sample available in the KB article + Q176415 + + +Enviroment: + + Kernel Mode Only + +Revision History: + +--*/ + +#include <ntddk.h> +#include "public.h" //common to app and driver +#include "event.h" // private to driver + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, EventCreateClose) +#pragma alloc_text (PAGE, EventUnload) +#endif + +_Use_decl_annotations_ +NTSTATUS +DriverEntry( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This routine gets called by the system to initialize the driver. + +Arguments: + + DriverObject - the system supplied driver object. + RegistryPath - the system supplied registry path for this driver. + +Return Value: + + NTSTATUS + +--*/ + +{ + + + + PDEVICE_OBJECT deviceObject; + PDEVICE_EXTENSION deviceExtension; + UNICODE_STRING ntDeviceName; + UNICODE_STRING symbolicLinkName; + NTSTATUS status; + + UNREFERENCED_PARAMETER(RegistryPath); + + DebugPrint(("==>DriverEntry\n")); + + // + // Create the device object + // + RtlInitUnicodeString(&ntDeviceName, NTDEVICE_NAME_STRING); + + status = IoCreateDevice(DriverObject, // DriverObject + sizeof(DEVICE_EXTENSION), // DeviceExtensionSize + &ntDeviceName, // DeviceName + FILE_DEVICE_UNKNOWN, // DeviceType + FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics + FALSE, // Not Exclusive + &deviceObject // DeviceObject + ); + + if (!NT_SUCCESS(status)) { + DebugPrint(("\tIoCreateDevice returned 0x%x\n", status)); + return(status); + } + + // + // Set up dispatch entry points for the driver. + // + DriverObject->MajorFunction[IRP_MJ_CREATE] = EventCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = EventCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = EventCleanup; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = EventDispatchIoControl; + DriverObject->DriverUnload = EventUnload; + + // + // Create a symbolic link for userapp to interact with the driver. + // + RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING); + status = IoCreateSymbolicLink(&symbolicLinkName, &ntDeviceName); + + if (!NT_SUCCESS(status)) { + IoDeleteDevice(deviceObject); + DebugPrint(("\tIoCreateSymbolicLink returned 0x%x\n", status)); + return(status); + } + + // + // Initialize the device extension. + // + deviceExtension = deviceObject->DeviceExtension; + + InitializeListHead(&deviceExtension->EventQueueHead); + + KeInitializeSpinLock(&deviceExtension->QueueLock); + + deviceExtension->Self = deviceObject; + + // + // Establish user-buffer access method. + // + deviceObject->Flags |= DO_BUFFERED_IO; + + DebugPrint(("<==DriverEntry\n")); + + ASSERT(NT_SUCCESS(status)); + + return status; +} + +_Use_decl_annotations_ +VOID +EventUnload( + PDRIVER_OBJECT DriverObject + ) + +/*++ + +Routine Description: + + This routine gets called to remove the driver from the system. + +Arguments: + + DriverObject - the system supplied driver object. + +Return Value: + + NTSTATUS + +--*/ + +{ + + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + PDEVICE_EXTENSION deviceExtension = deviceObject->DeviceExtension; + UNICODE_STRING symbolicLinkName; + + DebugPrint(("==>Unload\n")); + + PAGED_CODE(); + + if (!IsListEmpty(&deviceExtension->EventQueueHead)) { + ASSERTMSG("Event Queue is not empty\n", FALSE); + } + + // + // Delete the user-mode symbolic link and deviceobjct. + // + RtlInitUnicodeString(&symbolicLinkName, SYMBOLIC_NAME_STRING); + IoDeleteSymbolicLink(&symbolicLinkName); + IoDeleteDevice(deviceObject); + + return; +} + +_Use_decl_annotations_ +NTSTATUS +EventCreateClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This device control dispatcher handles create & close IRPs. + +Arguments: + + DeviceObject - Context for the activity. + Irp - The device control argument block. + +Return Value: + + NTSTATUS + +--*/ +{ + PIO_STACK_LOCATION irpStack; + NTSTATUS status; + PFILE_CONTEXT fileContext; + + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE(); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + switch (irpStack->MajorFunction) + { + case IRP_MJ_CREATE: + DebugPrint(("IRP_MJ_CREATE\n")); + + fileContext = ExAllocatePoolWithQuotaTag(NonPagedPool, + sizeof(FILE_CONTEXT), + TAG); + + if (NULL == fileContext) { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + IoInitializeRemoveLock(&fileContext->FileRundownLock, TAG, 0, 0); + + // + // Make sure nobody is using the FsContext scratch area. + // + ASSERT(irpStack->FileObject->FsContext == NULL); + + // + // Store the context in the FileObject's scratch area. + // + irpStack->FileObject->FsContext = (PVOID) fileContext; + + status = STATUS_SUCCESS; + break; + + case IRP_MJ_CLOSE: + DebugPrint(("IRP_MJ_CLOSE\n")); + + fileContext = irpStack->FileObject->FsContext; + + ExFreePoolWithTag(fileContext, TAG); + + status = STATUS_SUCCESS; + break; + + default: + ASSERT(FALSE); // should never hit this + status = STATUS_NOT_IMPLEMENTED; + break; + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + +} + +_Use_decl_annotations_ +NTSTATUS +EventCleanup( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This device control dispatcher handles Cleanup IRP. + +Arguments: + + DeviceObject - Context for the activity. + Irp - The device control argument block. + +Return Value: + + NTSTATUS + +--*/ +{ + PIO_STACK_LOCATION irpStack; + NTSTATUS status ; + KIRQL oldIrql; + PLIST_ENTRY thisEntry, nextEntry, listHead; + PNOTIFY_RECORD notifyRecord; + PDEVICE_EXTENSION deviceExtension; + LIST_ENTRY cleanupList; + PFILE_CONTEXT fileContext; + + DebugPrint(("==>EventCleanup\n")); + + deviceExtension = DeviceObject->DeviceExtension; + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + // + // This acquire cannot fail because you cannot get more than one + // cleanup for the same handle. + // + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + ASSERT(NT_SUCCESS(status)); + + // + // Wait for all the threads that are currently dispatching to exit and + // prevent any threads dispatching I/O on the same handle beyond this point. + // + IoReleaseRemoveLockAndWait(&fileContext->FileRundownLock, Irp); + + InitializeListHead(&cleanupList); + + // + // Walk the list and remove all the pending notification records + // that belong to this filehandle. + // + + KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql); + + listHead = &deviceExtension->EventQueueHead; + + for (thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = nextEntry) + { + nextEntry = thisEntry->Flink; + + notifyRecord = CONTAINING_RECORD(thisEntry, NOTIFY_RECORD, ListEntry); + + if (irpStack->FileObject == notifyRecord->FileObject) { + + // + // KeCancelTimer returns if the timer is successfully cancelled. + // If it returns FALSE, there are two possibilities. Either the + // TimerDpc has just run and waiting to acquire the lock or it + // has run to completion. We wouldn't be here if it had run to + // completion because we wouldn't found the record in the list. + // So the only possibility is that it's waiting to acquire the lock. + // In that case, we will just let the DPC to complete the request + // and free the record. + // + if (KeCancelTimer(¬ifyRecord->Timer)) { + + DebugPrint(("\tCanceled timer\n")); + RemoveEntryList(thisEntry); + + switch (notifyRecord->Type) { + case IRP_BASED: + // + // Clear the cancel-routine and check the return value to + // see whether it was cleared by us or by the I/O manager. + // + if (IoSetCancelRoutine (notifyRecord->Message.PendingIrp, NULL) != NULL) { + + // + // We cleared it and as a result we own the IRP and + // nobody can cancel it anymore. We will queue the IRP + // in the local cleanup list so that we can complete + // all the IRPs outside the lock to avoid deadlocks in + // the completion routine of the driver above us re-enters + // our driver. + // + InsertTailList(&cleanupList, + ¬ifyRecord->Message.PendingIrp->Tail.Overlay.ListEntry); + ExFreePoolWithTag(notifyRecord, TAG); + + } else { + // + // The I/O manager cleared it and called the cancel-routine. + // Cancel routine is probably waiting to acquire the lock. + // So reinitialze the ListEntry so that it doesn't crash + // when it tries to remove the entry from the list and + // set the CancelRoutineFreeMemory to indicate that it should + // free the notification record. + // + InitializeListHead(¬ifyRecord->ListEntry); + notifyRecord->CancelRoutineFreeMemory = TRUE; + } + break; + + case EVENT_BASED: + ObDereferenceObject(notifyRecord->Message.Event); + ExFreePoolWithTag(notifyRecord, TAG); + break; + default: break; + + } + } + } + } + + KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql); + + // + // Walk through the cleanup list and cancel all + // the IRPs. + // + while (!IsListEmpty(&cleanupList)) + { + PIRP pendingIrp; + // + // Complete the IRP + // + thisEntry = RemoveHeadList(&cleanupList); + pendingIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry); + + DebugPrint(("\t canceled IRP %p\n", pendingIrp)); + + pendingIrp->Tail.Overlay.DriverContext[3] = NULL; + pendingIrp->IoStatus.Information = 0; + pendingIrp->IoStatus.Status = STATUS_CANCELLED; + + IoCompleteRequest(pendingIrp, IO_NO_INCREMENT); + } + + // + // Finally complete the cleanup Irp + // + Irp->IoStatus.Status = status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + DebugPrint(("<== EventCleanup\n")); + return status; + +} + +_Use_decl_annotations_ +NTSTATUS +EventDispatchIoControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This device control dispatcher handles IOCTLs. + +Arguments: + + DeviceObject - Context for the activity. + Irp - The device control argument block. + +Return Value: + + NTSTATUS + +--*/ + +{ + + PIO_STACK_LOCATION irpStack; + PREGISTER_EVENT registerEvent; + NTSTATUS status; + PFILE_CONTEXT fileContext; + + DebugPrint(("==> EventDispatchIoControl\n")); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + + ASSERT(irpStack->FileObject != NULL); + + fileContext = irpStack->FileObject->FsContext; + + status = IoAcquireRemoveLock(&fileContext->FileRundownLock, Irp); + if (!NT_SUCCESS(status)) { + // + // Lock is in a removed state. That means we have already received + // cleaned up request for this handle. + // + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + return status; + } + + switch (irpStack->Parameters.DeviceIoControl.IoControlCode) + { + case IOCTL_REGISTER_EVENT: + + DebugPrint(("\tIOCTL_REGISTER_EVENT\n")); + + // + // First validate the parameters. + // + if (irpStack->Parameters.DeviceIoControl.InputBufferLength < + SIZEOF_REGISTER_EVENT) { + status = STATUS_INVALID_PARAMETER; + break; + } + + registerEvent = (PREGISTER_EVENT)Irp->AssociatedIrp.SystemBuffer; + + switch (registerEvent->Type) { + case IRP_BASED: + status = RegisterIrpBasedNotification(DeviceObject, Irp); + break; + case EVENT_BASED: + status = RegisterEventBasedNotification(DeviceObject, Irp); + break; + default: + ASSERTMSG("\tUnknow notification type from user-mode\n", FALSE); + status = STATUS_INVALID_PARAMETER; + break; + } + + break; + + default: + ASSERT(FALSE); // should never hit this + status = STATUS_NOT_IMPLEMENTED; + break; + + } // switch IoControlCode + + if (status != STATUS_PENDING) { + // + // complete the Irp + // + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + + // + // We don't hold the lock for IRP that's pending in the list because this + // lock is meant to rundown currently dispatching threads when the cleanup + // is handled. + // + IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); + + DebugPrint(("<== EventDispatchIoControl\n")); + return status; +} + +_Use_decl_annotations_ +VOID +EventCancelRoutine( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + The cancel routine. It will remove the IRP from the queue + and will complete it. The cancel spin lock is already acquired + when this routine is called. This routine is not required if + you are just using the event based notification. + +Arguments: + + DeviceObject - pointer to the device object. + + Irp - pointer to the IRP to be cancelled. + + +Return Value: + + VOID. + +--*/ +{ + PDEVICE_EXTENSION deviceExtension; + KIRQL oldIrql ; + PNOTIFY_RECORD notifyRecord; + + DebugPrint (("==>EventCancelRoutine irp %p\n", Irp)); + + deviceExtension = DeviceObject->DeviceExtension; + + // + // Release the cancel spinlock + // + IoReleaseCancelSpinLock(Irp->CancelIrql); + + // + // Acquire the queue spinlock + // + KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql); + + notifyRecord = Irp->Tail.Overlay.DriverContext[3]; + ASSERT(NULL != notifyRecord); + ASSERT(IRP_BASED == notifyRecord->Type); + + RemoveEntryList(¬ifyRecord->ListEntry); + + // + // Clear the pending Irp field because we complete the IRP no matter whether + // we succeed or fail to cancel the timer. TimerDpc will check this field + // before dereferencing the IRP. + // + notifyRecord->Message.PendingIrp = NULL; + + if (KeCancelTimer(¬ifyRecord->Timer)) { + DebugPrint(("\t canceled timer\n")); + ExFreePoolWithTag(notifyRecord, TAG); + notifyRecord = NULL; + } else { + // + // Here the possibilities are: + // 1) DPC is fired and waiting to acquire the lock. + // 2) DPC has run to completion. + // 3) DPC has been cancelled by the cleanup routine. + // By checking the CancelRoutineFreeMemory, we can figure out whether + // dpc is waiting to acquire the lock and access the notifyRecord memory. + // + if (notifyRecord->CancelRoutineFreeMemory == FALSE) { + // + // This is case 1 where the DPC is waiting to run. + // + InitializeListHead(¬ifyRecord->ListEntry); + } else { + // + // This is either 2 or 3. + // + ExFreePoolWithTag(notifyRecord, TAG); + notifyRecord = NULL; + } + + } + + KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql); + + DebugPrint (("\t canceled IRP %p\n", Irp)); + Irp->Tail.Overlay.DriverContext[3] = NULL; + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + DebugPrint (("<==EventCancelRoutine irp %p\n", Irp)); + return; + +} + +_Use_decl_annotations_ +VOID +CustomTimerDPC( + PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + This is the DPC associated with this drivers Timer object setup in ioctl routine. + +Arguments: + + Dpc - our DPC object associated with our Timer + DeferredContext - Context for the DPC that we setup in DriverEntry + SystemArgument1 - + SystemArgument2 - + +Return Value: + + Nothing. + +--*/ +{ + PNOTIFY_RECORD notifyRecord = DeferredContext; + PDEVICE_EXTENSION deviceExtension; + PIRP irp; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + DebugPrint(("==> CustomTimerDPC \n")); + + ASSERT(notifyRecord != NULL); // can't be NULL + _Analysis_assume_(notifyRecord != NULL); + + deviceExtension = notifyRecord->DeviceExtension; + + KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock); + + RemoveEntryList(¬ifyRecord->ListEntry); + + switch (notifyRecord->Type) { + case IRP_BASED: + irp = notifyRecord->Message.PendingIrp; + if (irp != NULL) { + if (IoSetCancelRoutine(irp, NULL) != NULL) { + + irp->Tail.Overlay.DriverContext[3] = NULL; + + // + // Drop the lock before completing the request. + // + KeReleaseSpinLockFromDpcLevel(&deviceExtension->QueueLock); + + irp->IoStatus.Status = STATUS_SUCCESS; + irp->IoStatus.Information = 0; + IoCompleteRequest(irp, IO_NO_INCREMENT); + + KeAcquireSpinLockAtDpcLevel(&deviceExtension->QueueLock); + + } else { + // + // Cancel routine will run as soon as we release the lock. + // So let it complete the request and free the record. + // + InitializeListHead(¬ifyRecord->ListEntry); + notifyRecord->CancelRoutineFreeMemory = TRUE; + notifyRecord = NULL; + } + } else { + // + // Cancel routine has run and completed the IRP. So just free + // the record. + // + ASSERT(notifyRecord->CancelRoutineFreeMemory == FALSE); + } + + break; + + case EVENT_BASED: + // + // Signal the Event created in user-mode. + // + KeSetEvent(notifyRecord->Message.Event, 0, FALSE); + + // + // Dereference the object as we are done with it. + // + ObDereferenceObject(notifyRecord->Message.Event); + + break; + + default: + ASSERT(FALSE); + break; + } + + KeReleaseSpinLockFromDpcLevel(&deviceExtension->QueueLock); + + // + // Free the memory outside the lock for better performance. + // + if (notifyRecord != NULL) { + ExFreePoolWithTag(notifyRecord, TAG); + notifyRecord = NULL; + } + + DebugPrint(("<== CustomTimerDPC\n")); + + return; +} + +_Use_decl_annotations_ +NTSTATUS +RegisterIrpBasedNotification( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine queues a IRP based notification record to be + handled by a DPC. + + +Arguments: + + DeviceObject - Context for the activity. + Irp - The device control argument block. + +Return Value: + + NTSTATUS - If the status is not STATUS_PENDING, the caller + will complete the request. + + +--*/ +{ + PDEVICE_EXTENSION deviceExtension; + PNOTIFY_RECORD notifyRecord; + PIO_STACK_LOCATION irpStack; + KIRQL oldIrql; + PREGISTER_EVENT registerEvent; + + DebugPrint(("\tRegisterIrpBasedNotification\n")); + + irpStack = IoGetCurrentIrpStackLocation(Irp); + deviceExtension = DeviceObject->DeviceExtension; + registerEvent = (PREGISTER_EVENT)Irp->AssociatedIrp.SystemBuffer; + + // + // Allocate a record and save all the event context. + // + + notifyRecord = ExAllocatePoolWithQuotaTag(NonPagedPool, + sizeof(NOTIFY_RECORD), + TAG); + + if (NULL == notifyRecord) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + InitializeListHead(¬ifyRecord->ListEntry); + + notifyRecord->FileObject = irpStack->FileObject; + notifyRecord->DeviceExtension = deviceExtension; + notifyRecord->Type = IRP_BASED; + notifyRecord->Message.PendingIrp = Irp; + + // + // Start the timer to run the CustomTimerDPC in DueTime seconds to + // simulate an interrupt (which would queue a DPC). + // The user's event object is signaled or the IRP is completed in the DPC to + // notify the hardware event. + // + + // ensure relative time for this sample + + if (registerEvent->DueTime.QuadPart > 0) { + registerEvent->DueTime.QuadPart = -(registerEvent->DueTime.QuadPart); + } + + KeInitializeDpc(¬ifyRecord->Dpc, // Dpc + CustomTimerDPC, // DeferredRoutine + notifyRecord // DeferredContext + ); + + KeInitializeTimer(¬ifyRecord->Timer); + + // + // We will set the cancel routine and TimerDpc within the + // lock so that they don't modify the list before we are + // completely done. + // + KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql); + + // + // Set the cancel routine. This is required if the app decides to + // exit or cancel the event prematurely. + // + IoSetCancelRoutine (Irp, EventCancelRoutine); + + // + // Before we queue the IRP, we must check to see if it's cancelled. + // + if (Irp->Cancel) { + + // + // Clear the cancel-routine automically and check the return value. + // We will complete the IRP here if we succeed in clearing it. If + // we fail then we will let the cancel-routine complete it. + // + if (IoSetCancelRoutine (Irp, NULL) != NULL) { + + // + // We are able to successfully clear the routine. Either the + // the IRP is cancelled before we set the cancel-routine or + // we won the race with I/O manager in clearing the routine. + // Return STATUS_CANCELLED so that the caller can complete + // the request. + + KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql); + + ExFreePoolWithTag(notifyRecord, TAG); + + return STATUS_CANCELLED; + } else { + // + // The IRP got cancelled after we set the cancel-routine and the + // I/O manager won the race in clearing it and called the cancel + // routine. So queue the request so that cancel-routine can dequeue + // and complete it. Note the cancel-routine cannot run until we + // drop the queue lock. + // + } + } + + IoMarkIrpPending(Irp); + + InsertTailList(&deviceExtension->EventQueueHead, + ¬ifyRecord->ListEntry); + + notifyRecord->CancelRoutineFreeMemory = FALSE; + + // + // We will save the record pointer in the IRP so that we can get to + // it directly in the CancelRoutine. + // + Irp->Tail.Overlay.DriverContext[3] = notifyRecord; + + KeSetTimer(¬ifyRecord->Timer, // Timer + registerEvent->DueTime, // DueTime + ¬ifyRecord->Dpc // Dpc + ); + + KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql); + + // + // We will return pending as we have marked the IRP pending. + // + return STATUS_PENDING;; + +} + +_Use_decl_annotations_ +NTSTATUS +RegisterEventBasedNotification( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine queues a event based notification record + to be handled by a DPC. + +Arguments: + + DeviceObject - Context for the activity. + Irp - The device control argument block. + +Return Value: + + NTSTATUS - If the status is not STATUS_PENDING, the caller + will complete the request. + +--*/ +{ + PDEVICE_EXTENSION deviceExtension; + PNOTIFY_RECORD notifyRecord; + NTSTATUS status; + PIO_STACK_LOCATION irpStack; + PREGISTER_EVENT registerEvent; + KIRQL oldIrql; + + DebugPrint(("\tRegisterEventBasedNotification\n")); + + deviceExtension = DeviceObject->DeviceExtension; + + irpStack = IoGetCurrentIrpStackLocation(Irp); + registerEvent = (PREGISTER_EVENT)Irp->AssociatedIrp.SystemBuffer; + + // + // Allocate a record and save all the event context. + // + notifyRecord = ExAllocatePoolWithQuotaTag(NonPagedPool, + sizeof(NOTIFY_RECORD), + TAG); + + if (NULL == notifyRecord) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + InitializeListHead(¬ifyRecord->ListEntry); + + notifyRecord->FileObject = irpStack->FileObject; + notifyRecord->DeviceExtension = deviceExtension; + notifyRecord->Type = EVENT_BASED; + + // + // Get the object pointer from the handle. Note we must be in the context + // of the process that created the handle. + // + status = ObReferenceObjectByHandle(registerEvent->hEvent, + SYNCHRONIZE | EVENT_MODIFY_STATE, + *ExEventObjectType, + Irp->RequestorMode, + ¬ifyRecord->Message.Event, + NULL + ); + + if (!NT_SUCCESS(status)) { + + DebugPrint(("\tUnable to reference User-Mode Event object, Error = 0x%x\n", status)); + ExFreePoolWithTag(notifyRecord, TAG); + return status; + } + + // + // Start the timer to run the CustomTimerDPC in DueTime seconds to + // simulate an interrupt (which would queue a DPC). + // The user's event object is signaled or the IRP is completed in the DPC to + // notify the hardware event. + // + if (registerEvent->DueTime.QuadPart > 0) { + registerEvent->DueTime.QuadPart = -(registerEvent->DueTime.QuadPart); + } + + KeInitializeDpc(¬ifyRecord->Dpc, // Dpc + CustomTimerDPC, // DeferredRoutine + notifyRecord // DeferredContext + ); + + KeInitializeTimer(¬ifyRecord->Timer); + + KeAcquireSpinLock(&deviceExtension->QueueLock, &oldIrql); + + InsertTailList(&deviceExtension->EventQueueHead, + ¬ifyRecord->ListEntry); + + KeReleaseSpinLock(&deviceExtension->QueueLock, oldIrql); + + KeSetTimer(¬ifyRecord->Timer, // Timer + registerEvent->DueTime, // DueTime + ¬ifyRecord->Dpc // Dpc + ); + return STATUS_SUCCESS; +} + + diff --git a/general/event/wdm/event.h b/general/event/wdm/event.h new file mode 100644 index 00000000..1de7db76 --- /dev/null +++ b/general/event/wdm/event.h @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + Event.h + +--*/ + +#ifndef __EVENT__ +#define __EVENT__ + +// +// DEFINES +// + +#define NTDEVICE_NAME_STRING L"\\Device\\Event_Sample" +#define SYMBOLIC_NAME_STRING L"\\DosDevices\\Event_Sample" +#define TAG (ULONG)'TEVE' + +#if DBG +#define DebugPrint(_x_) \ + DbgPrint("EVENT.SYS: ");\ + DbgPrint _x_; + +#else + +#define DebugPrint(_x_) + +#endif + +// +// DATA +// +typedef struct _DEVICE_EXTENSION { + PDEVICE_OBJECT Self; + LIST_ENTRY EventQueueHead; // where all the user notification requests are queued + KSPIN_LOCK QueueLock; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + + +typedef struct _NOTIFY_RECORD{ + NOTIFY_TYPE Type; + LIST_ENTRY ListEntry; + union { + PKEVENT Event; + PIRP PendingIrp; + } Message; + KDPC Dpc; + KTIMER Timer; + PFILE_OBJECT FileObject; + PDEVICE_EXTENSION DeviceExtension; + BOOLEAN CancelRoutineFreeMemory; +} NOTIFY_RECORD, *PNOTIFY_RECORD; + +typedef struct _FILE_CONTEXT{ + // + // Lock to rundown threads that are dispatching I/Os on a file handle + // while the cleanup for that handle is in progress. + // + IO_REMOVE_LOCK FileRundownLock; +} FILE_CONTEXT, *PFILE_CONTEXT; + +// +// Function prototypes +// + + +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH EventCreateClose; + +_Dispatch_type_(IRP_MJ_CLEANUP) +DRIVER_DISPATCH EventCleanup; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH EventDispatchIoControl; + +DRIVER_UNLOAD EventUnload; + +DRIVER_CANCEL EventCancelRoutine; + +KDEFERRED_ROUTINE CustomTimerDPC; + +DRIVER_DISPATCH RegisterEventBasedNotification; + +DRIVER_DISPATCH RegisterIrpBasedNotification; + + +#endif // __EVENT__ diff --git a/general/event/wdm/event.rc b/general/event/wdm/event.rc new file mode 100644 index 00000000..5ffe2ea7 --- /dev/null +++ b/general/event/wdm/event.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Sample Event Driver" +#define VER_INTERNALNAME_STR "event.sys" + +#include "common.ver" + diff --git a/general/event/wdm/event.vcxproj b/general/event/wdm/event.vcxproj new file mode 100644 index 00000000..3dd391d5 --- /dev/null +++ b/general/event/wdm/event.vcxproj @@ -0,0 +1,156 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{99CD8B5D-2961-44A5-ACB4-CC1CCCEE096B}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{463697D8-488D-488E-A7DF-ECB602F46DD2}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>event</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>event</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="event.c" /> + <ResourceCompile Include="event.rc" /> + </ItemGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/event/wdm/event.vcxproj.Filters b/general/event/wdm/event.vcxproj.Filters new file mode 100644 index 00000000..c876bb5b --- /dev/null +++ b/general/event/wdm/event.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{68A8B3BF-BA74-401E-A54C-A5D84A227969}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F899D68E-E4E7-4168-9636-254BF3CDC360}</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>{0DFB698C-60E9-4C46-A9DD-76D3E4A63C45}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{705F4A1B-5DF2-4182-BCEA-69C62EC7ED04}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="event.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="event.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/event/wdm/public.h b/general/event/wdm/public.h new file mode 100644 index 00000000..9e08960c --- /dev/null +++ b/general/event/wdm/public.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Event.h + +--*/ + +#ifndef __PUBLIC__ +#define __PUBLIC__ + + +#include "devioctl.h" +#include <dontuse.h> + +typedef enum { + IRP_BASED , + EVENT_BASED +} NOTIFY_TYPE; + +typedef struct _REGISTER_EVENT +{ + NOTIFY_TYPE Type; + HANDLE hEvent; + LARGE_INTEGER DueTime; // requested DueTime in 100-nanosecond units + +} REGISTER_EVENT , *PREGISTER_EVENT ; + +#define SIZEOF_REGISTER_EVENT sizeof(REGISTER_EVENT ) + + +#define IOCTL_REGISTER_EVENT \ + CTL_CODE( FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS ) + + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 + +#define DRIVER_NAME "event" + +#endif // __PUBLIC__ diff --git a/general/filehistory/ReadMe.md b/general/filehistory/ReadMe.md new file mode 100644 index 00000000..58ebbb46 --- /dev/null +++ b/general/filehistory/ReadMe.md @@ -0,0 +1,23 @@ +File History Sample +================== + +The FileHistory sample is a console application that starts the file history service, if it is stopped, and schedules regular backups. The application requires, as a command-line parameter, the path name of a storage device to use as the default backup target. + +This sample application uses the [File History API](http://msdn.microsoft.com/en-us/library/windows/hardware/hh829789), which is available starting with Windows 8.1. The File History API enables third parties to automatically configure the File History feature on a Windows platform and customize it in accordance with their unique needs. + + +Run the sample +-------------- + +The name of the built sample application is Fhsetup.exe. To run this application, open a command window and enter a command that has the following format: + +`fhsetup <path>` + +The `path` command-line parameter is the path name of a storage device to use as the default backup target. The following are examples: + +`fhsetup D:\` + +`fhsetup \\server\share` + +If the specified target is inaccessible, read-only, an invalid drive type (such as a CD), already being used for file history, or part of the protected namespace, the application fails the request and does not enable file history on the target. + diff --git a/general/filehistory/exe/fhsetup.cpp b/general/filehistory/exe/fhsetup.cpp new file mode 100644 index 00000000..41edfd02 --- /dev/null +++ b/general/filehistory/exe/fhsetup.cpp @@ -0,0 +1,271 @@ +// +// File History Sample Setup Tool +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// + +#include <fhsetup.h> + +HRESULT ScheduleBackups() +/*++ + +Routine Description: + + This function starts the File History service if it is stopped + and schedules regular backups. + +Arguments: + + None + +Return Value: + + S_OK if successful + HRESULT from underlying functions + +--*/ +{ + HRESULT backupHr = S_OK; + HRESULT pipeHr = S_OK; + FH_SERVICE_PIPE_HANDLE pipe = NULL; + + pipeHr = FhServiceOpenPipe(TRUE, &pipe); + if (SUCCEEDED(pipeHr)) + { + backupHr = FhServiceReloadConfiguration(pipe); + pipeHr = FhServiceClosePipe(pipe); + } + + // The HRESULT from the backup operation is more important than + // the HRESULT from pipe operations + return FAILED(backupHr) ? backupHr : pipeHr; +} + +HRESULT ConfigureFileHistory( + _In_ PWSTR TargetPath + ) +/*++ + +Routine Description: + + This function configures a target for File History. + It will only succeed if the user has never configured File History + before and there is no File History data on the target. + +Arguments: + + TargetPath - + The path of the File History target + +Return Value: + + S_OK if successful + E_INVALIDARG if TargetPath is NULL + E_FAIL if configuration failed because File History is disabled by + group policy or the target is not valid + HRESULT from underlying functions + +--*/ +{ + HRESULT hr = S_OK; + FH_BACKUP_STATUS backupStatus; + FH_DEVICE_VALIDATION_RESULT validationResult; + CComPtr<IFhConfigMgr> configMgr; + CComBSTR targetPath; + CComBSTR targetName; + + // TargetPath must not be NULL + if (TargetPath == NULL) + { + hr = E_INVALIDARG; + goto Cleanup; + } + + // Copy the target path into a local variable and set the target name + // to an empty string to allow the config manager to set a name + _ATLTRY + { + targetPath = TargetPath; + targetName = L""; + } + _ATLCATCH(e) + { + hr = e; + goto Cleanup; + } + + // The configuration manager is used to create and load configuration + // files, get/set the backup status, validate a target, etc + hr = configMgr.CoCreateInstance(CLSID_FhConfigMgr); + if (FAILED(hr)) + { + wprintf(L"Error: CoCreateInstance failed (0x%X)\n", hr); + goto Cleanup; + } + + // Create a new default configuration file - do not overwrite if one + // already exists + wprintf(L"Creating default configuration\n"); + hr = configMgr->CreateDefaultConfiguration(FALSE); + if (FAILED(hr)) + { + if (hr == FHCFG_E_CONFIG_ALREADY_EXISTS) + { + wprintf(L"Error: File History has previously been configured\n"); + } + else + { + wprintf(L"Error: CreateDefaultConfiguration failed (0x%X)\n", hr); + } + goto Cleanup; + } + + // Check the backup status + // If File History is disabled by group policy, quit + wprintf(L"Getting backup status\n"); + hr = configMgr->GetBackupStatus(&backupStatus); + if (FAILED(hr)) + { + wprintf(L"Error: GetBackupStatus failed (0x%X)\n", hr); + goto Cleanup; + } + if (backupStatus == FH_STATUS_DISABLED_BY_GP) + { + wprintf(L"Error: File History is disabled by group policy\n"); + hr = E_FAIL; + goto Cleanup; + } + + // Make sure the target is valid to be used for File History + wprintf(L"Validating target\n"); + hr = configMgr->ValidateTarget(targetPath, &validationResult); + if (FAILED(hr)) + { + wprintf(L"Error: ValidateTarget failed (0x%X)\n", hr); + goto Cleanup; + } + if (validationResult != FH_VALID_TARGET) + { + // If the target is inaccessible, read-only, an invalid drive type + // (such as a CD), already being used for File History, or part of + // the protected namespace - don't enable File History + wprintf(L"Error: %ws is not a valid target\n", targetPath.m_str); + hr = E_FAIL; + goto Cleanup; + } + + // Provision the target to be used for File History and set + // it as the default target + wprintf(L"Provisioning and setting target\n"); + hr = configMgr->ProvisionAndSetNewTarget(targetPath, targetName); + if (FAILED(hr)) + { + wprintf(L"Error: ProvisionAndSetNewTarget failed (0x%X)\n", hr); + goto Cleanup; + } + + // Enable File History + wprintf(L"Enabling File History\n"); + hr = configMgr->SetBackupStatus(FH_STATUS_ENABLED); + if (FAILED(hr)) + { + wprintf(L"Error: SetBackupStatus failed (0x%X)\n", hr); + goto Cleanup; + } + + // Save the configuration to disk + wprintf(L"Saving configuration\n"); + hr = configMgr->SaveConfiguration(); + if (FAILED(hr)) + { + wprintf(L"Error: SaveConfiguration failed (0x%X)\n", hr); + goto Cleanup; + } + + // Tell the File History service to schedule backups + wprintf(L"Scheduling regular backups\n"); + hr = ScheduleBackups(); + if (FAILED(hr)) + { + wprintf(L"Error: ScheduleBackups failed (0x%X)\n", hr); + goto Cleanup; + } + + // Recommend the target to other Homegroup members + wprintf(L"Recommending target to Homegroup\n"); + HRESULT hrRecommend = configMgr->ChangeDefaultTargetRecommendation(TRUE); + if (FAILED(hrRecommend)) + { + wprintf(L"Warning: Failed to recommend target to Homegroup (0x%X)\n", hrRecommend); + } + + wprintf(L"Success! File History is now enabled\n"); + +Cleanup: + return hr; +} + +int __cdecl wmain( + _In_ int Argc, + _In_reads_(Argc) PWSTR Argv[] + ) +/*++ + +Routine Description: + + This is the main entry point of the console application. + +Arguments: + + Argc - the number of command line arguments + Argv - command line arguments + +Return Value: + + exit code + +--*/ +{ + HRESULT hr = S_OK; + BOOL comInitialized = FALSE; + + wprintf(L"\nFile History Sample Setup Tool\n"); + wprintf(L"Copyright (C) Microsoft Corporation. All rights reserved.\n\n"); + + // If there are fewer than 2 command-line arguments, print the correct + // usage and exit + if (Argc < 2) + { + wprintf(L"Usage: fhsetup <path>\n\n"); + wprintf(L"Examples:\n"); + wprintf(L" fhsetup D:\\\n"); + wprintf(L" fhsetup \\\\server\\share\\\n\n"); + goto Cleanup; + } + + // COM is needed to use the Config Manager + wprintf(L"Initializing COM...\n"); + hr = CoInitialize(NULL); + if (FAILED(hr)) + { + wprintf(L"Error: CoInitialize failed (0x%X)\n", hr); + goto Cleanup; + } + comInitialized = TRUE; + + hr = ConfigureFileHistory(Argv[1]); + if (FAILED(hr)) + { + wprintf(L"File History configuration failed (0x%X)\n", hr); + goto Cleanup; + } + +Cleanup: + // If COM was initialized, make sure it is uninitialized + if (comInitialized) + { + CoUninitialize(); + comInitialized = FALSE; + } + + return 0; +} diff --git a/general/filehistory/exe/fhsetup.h b/general/filehistory/exe/fhsetup.h new file mode 100644 index 00000000..eeb241c9 --- /dev/null +++ b/general/filehistory/exe/fhsetup.h @@ -0,0 +1,27 @@ +// +// File History Sample Setup Tool +// Copyright (c) Microsoft Corporation. All Rights Reserved. +// + +#include <windows.h> +#include <atlcore.h> +#include <atlbase.h> +#include <atlcom.h> +#include <atlstr.h> +#include <shlwapi.h> +#include <shellapi.h> +#include <strsafe.h> + +#include <fherrors.h> +#include <fhstatus.h> +#include <fhcfg.h> +#include <fhsvcctl.h> + +// +// Define CLSID_FhConfigMgr. +// We must include initguid.h before using DEFINE_GUID otherwise +// DEFINE_GUID will declare CLSID_FhConfigMgr as extern. +// + +#include <initguid.h> +DEFINE_GUID(CLSID_FhConfigMgr,0xED43BB3C,0x09E9,0x498a,0x9D,0xF6,0x21,0x77,0x24,0x4C,0x6D,0xB4);
\ No newline at end of file diff --git a/general/filehistory/exe/fhsetup.vcxproj b/general/filehistory/exe/fhsetup.vcxproj new file mode 100644 index 00000000..29151c50 --- /dev/null +++ b/general/filehistory/exe/fhsetup.vcxproj @@ -0,0 +1,191 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{19CB999A-197D-4EAB-85F1-C4230C32B26E}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>fhsetup</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>fhsetup</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>fhsetup</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>fhsetup</TargetName> + <UseOfAtl>Dynamic</UseOfAtl> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);shell32.lib;shlwapi.lib;Ole32.lib;Oleaut32.lib;User32.lib;fhsvcctl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);shell32.lib;shlwapi.lib;Ole32.lib;Oleaut32.lib;User32.lib;fhsvcctl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);shell32.lib;shlwapi.lib;Ole32.lib;Oleaut32.lib;User32.lib;fhsvcctl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling>Sync</ExceptionHandling> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_INC_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);shell32.lib;shlwapi.lib;Ole32.lib;Oleaut32.lib;User32.lib;fhsvcctl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="fhsetup.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/filehistory/exe/fhsetup.vcxproj.Filters b/general/filehistory/exe/fhsetup.vcxproj.Filters new file mode 100644 index 00000000..8b773bab --- /dev/null +++ b/general/filehistory/exe/fhsetup.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{86ABC263-8E1E-48CB-8D3E-368CE3C22885}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{E466B712-D4BD-4268-8FDB-FB7BDDAC7FB4}</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>{C3E2505A-EA9E-4B2A-B2B1-1AF968556961}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="fhsetup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/filehistory/filehistory.sln b/general/filehistory/filehistory.sln new file mode 100644 index 00000000..055780ce --- /dev/null +++ b/general/filehistory/filehistory.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fhsetup", "exe\fhsetup.vcxproj", "{5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|Win32.ActiveCfg = Debug|Win32 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|Win32.Build.0 = Debug|Win32 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|Win32.ActiveCfg = Release|Win32 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|Win32.Build.0 = Release|Win32 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|x64.ActiveCfg = Debug|x64 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Debug|x64.Build.0 = Debug|x64 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|x64.ActiveCfg = Release|x64 + {5ED52C3F-4CA6-4E04-82DD-404CA008EE8B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/installwdf/Install.cpp b/general/installwdf/Install.cpp new file mode 100644 index 00000000..cd89e284 --- /dev/null +++ b/general/installwdf/Install.cpp @@ -0,0 +1,509 @@ +#include <Windows.h> +#include <stdio.h> +#include <strsafe.h> +#include <wuerror.h> + +// +// These defines control which packages need to be updated. In order to +// to customize this for your drivers needs, edit needed packages to 1 and +// unneeded packages to 0. +// +// If your UMDF driver uses USB functionality, you also need KMDF and WinUSB +// +#define INSTALL_KMDF (TRUE) +#define INSTALL_WINUSB (TRUE) +#define INSTALL_UMDF (TRUE) + +// +// Reference strings that are used to build our MSU package name. These will +// change between releases of the framework and will need to be updated +// +#define WINUSB_UPDATE_NAME L"WinUSB_1.9.msu" + +// +// MSU names are of the format: +// <kmdf|umdf>-<wdf major version>.<wdf minor version>- +// Win-<windows major version>.<windows minor version>.msu +// +#define MSU_FORMAT_STRING L"%s-%d.%d-Win-%d.%d.msu" + +#define WUSA_EXE L"%windir%\\system32\\wusa.exe" + +#define WUSA_EXE_ARGUMENTS L"/quiet /norestart" + +#define WDF_MAJOR_VERSION 1 +#define WDF_MINOR_VERSION 11 + +DWORD +ApplyUpdate( + PCWSTR MSUName +) +{ + DWORD error = ERROR_SUCCESS; + size_t cmdLengthBytes; + size_t applicationLengthBytes; + BOOL ok; + PROCESS_INFORMATION pInfo; + STARTUPINFOW startInfo; + PWCHAR applicationName = NULL; + PWCHAR commandLine = NULL; + HRESULT hr; + + ZeroMemory(&startInfo,sizeof(startInfo)) ; + startInfo.cb = sizeof(STARTUPINFO) ; + + ZeroMemory(&pInfo,sizeof(pInfo)); + // + // Check that the update package exists + // + error = GetFileAttributes(MSUName); + + if (error == INVALID_FILE_ATTRIBUTES) { + error = GetLastError(); + wprintf(L"Error: Could not find update file %s; error %x\n", MSUName, error); + goto exit; + } + + // + // Invoke wusa + // + applicationName = (PWCHAR) LocalAlloc(LPTR, (MAX_PATH + 1)*sizeof(WCHAR)); + if (applicationName == NULL) { + error = ERROR_INSTALL_FAILURE; + wprintf(L"Failed to allocate applicationName buffer\n"); + goto exit; + } + + applicationName[0] = L'\0'; + + applicationLengthBytes = ExpandEnvironmentStrings(WUSA_EXE, + applicationName, + MAX_PATH+1); + + if ((applicationLengthBytes == 0) || + (applicationLengthBytes > MAX_PATH+1)) { + wprintf(L"Could not expland %s\n", WUSA_EXE); + error = ERROR_INSTALL_FAILURE; + goto exit; + } + + applicationLengthBytes = sizeof(WCHAR) * applicationLengthBytes; + + hr = StringCbLength(MSUName, + MAX_PATH * sizeof(WCHAR), + &cmdLengthBytes); + + if (hr != S_OK) { + + error = ERROR_INSTALL_FAILURE; + wprintf(L"StringCbLength failed MSUName, %x\n", + hr); + goto exit; + } + // + // Add enough padding for 2 \". The size returned by sizeof() includes + // the terminating L'\0' + // + cmdLengthBytes = applicationLengthBytes + cmdLengthBytes + sizeof(WUSA_EXE_ARGUMENTS) + 3*sizeof(WCHAR); + + commandLine = (PWCHAR) LocalAlloc(LPTR, cmdLengthBytes ); + + if (commandLine == NULL) { + wprintf(L"Failed to allocate applicationName buffer\n"); + error = ERROR_INSTALL_FAILURE; + goto exit; + } + + hr = StringCbPrintf(commandLine, + cmdLengthBytes, + L"%s \"%s\" %s", + applicationName, + MSUName, + WUSA_EXE_ARGUMENTS); + if (hr != S_OK) { + + error = ERROR_INSTALL_FAILURE; + wprintf(L"StringCbPrintf failed for applicationParameters, %x\n", + hr); + goto exit; + } + + wprintf(L"Invoking: %s\n", commandLine); + + ok = CreateProcess(applicationName, // name of executable module + commandLine, // command line string + NULL, // SD + NULL, // SD + TRUE, // handle inheritance option + 0, // creation flags CREATE_NO_WINDOW + NULL, // new environment block + NULL, // current directory name + &startInfo, // startup information + &pInfo // process information + ); + + if (ok == FALSE) { + + error = GetLastError(); + wprintf(L"Create process failed : %x\n", + error); + goto exit; + + } else { + + // + // Wait until child process exits. + // + + error = WaitForSingleObject( pInfo.hProcess, INFINITE ); + + if ( error != WAIT_OBJECT_0 ) { + // + // It can't hurt to add this + // + TerminateProcess(pInfo.hProcess, (UINT)-1); + } + + GetExitCodeProcess(pInfo.hProcess, &error); + + // + // The possible return values for wusa.exe are: + // 1)ERROR_SUCCESS (0) : installation was successfull + // 2)ERROR_SUCCESS_REBOOT_REQUIRED (3010) : installation was successful, + // however a reboot is required, so that the binaries will be + // loaded to memory + // 3)S_FALSE (1) (Vista) OR WU_S_ALREADY_INSTALLED (240006) (Win7): + // No action was taken (i.e. files were already installed) + // 4)Everything else (e.g. ERROR_INSTALL_FAILURE) is an error + // + + switch (error) { + case S_FALSE: + case WU_S_ALREADY_INSTALLED: + wprintf(L"The package was already installed in the system\n"); + error = ERROR_SUCCESS; + break; + case ERROR_SUCCESS: + wprintf(L"The package was installed successfully\n"); + break; + case ERROR_SUCCESS_REBOOT_REQUIRED: + wprintf(L"The package was installed successfully but requires a reboot\n"); + break; + case ERROR_SERVICE_DISABLED: + case WU_E_WU_DISABLED: + + // + // If the "Windows Update" service is disabled, then wusa + // returns ERROR_SERVICE_DISABLED + // + + wprintf(L"The \"Windows Update\" service is disabled. It " + L"has to be enabled for the installation to succeed." + L"\n"); + break; + default: + wprintf(L"The update process returned error code :%x. ", + error); + wprintf(L"For additional information please look at the log " + L"files %%windir%%\\windowsupdate.log and " + L"%%windir%%\\Logs\\CBS\\CBS.log\n"); + break; + } + + CloseHandle(pInfo.hProcess); + CloseHandle(pInfo.hThread); + } + +exit: + if (commandLine != NULL) { + LocalFree(commandLine); + commandLine = NULL; + } + + if (applicationName != NULL) { + LocalFree(applicationName); + applicationName = NULL; + } + + return error; +} + +BOOL +PromptRestart() +{ + HANDLE hToken; // handle to process token + TOKEN_PRIVILEGES tkp; // pointer to token structure + BOOL fResult; // system shutdown flag + + // Get the current process token handle so we can get shutdown + // privilege. + + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) + return FALSE; + + // Get the LUID for shutdown privilege. + + LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, + &tkp.Privileges[0].Luid); + + tkp.PrivilegeCount = 1; // one privilege to set + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // Get shutdown privilege for this process. + + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, + (PTOKEN_PRIVILEGES) NULL, 0); + + // Cannot test the return value of AdjustTokenPrivileges. + + if (GetLastError() != ERROR_SUCCESS) { + return FALSE; + } + + // Display the shutdown dialog box and start the countdown. + + #pragma prefast(suppress:28159, "Ignore the suggestion against system shutdown.") + fResult = InitiateSystemShutdownEx( + NULL, // shut down local computer + NULL, // message for user + 0, // time-out period, in seconds + FALSE, // ask user to close apps + TRUE, // reboot after shutdown + SHTDN_REASON_FLAG_PLANNED // shutdown reason + | SHTDN_REASON_MAJOR_SOFTWARE + | SHTDN_REASON_MINOR_UPGRADE); + + // Disable shutdown privilege. + + tkp.Privileges[0].Attributes = 0; + AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, + (PTOKEN_PRIVILEGES) NULL, 0); + + return fResult; + +} + +DWORD +UpdateWdf( + VOID + ) +{ + BOOL ok; + OSVERSIONINFO curOsvi; + OSVERSIONINFOEX targetOsvi; + DWORDLONG dwlConditionMask = 0; + WCHAR MSUName[MAX_PATH]; + BOOL rebootNeeded = FALSE; + DWORD error = ERROR_SUCCESS; + HRESULT hr; + + // + // Make sure updates are valid for this operating system. + // Vista SP1/SP2; Win7 RTM + // TODO: what happens on Vista RTM/SP3+/Win7 SP1+ + // + + ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX)); + dwlConditionMask = 0; + + targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + targetOsvi.dwMajorVersion = 6; + targetOsvi.dwMinorVersion = 0; + targetOsvi.wServicePackMajor = 0; + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_LESS_EQUAL ); + VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_LESS_EQUAL ); + VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR, VER_LESS_EQUAL ); + + ok = VerifyVersionInfo( &targetOsvi, + VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, + dwlConditionMask); + + if (ok) { + wprintf(L"Error: Updates are not supported on OS before Vista or Vista RTM\n"); + error = ERROR_OLD_WIN_VERSION; + goto exit; + } + + // + // No need to update on Win8+ + // + ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX)); + dwlConditionMask = 0; + + targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + targetOsvi.dwMajorVersion = 6; + targetOsvi.dwMinorVersion = 2; + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL ); + VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL ); + + ok = VerifyVersionInfo( &targetOsvi, + VER_MAJORVERSION | VER_MINORVERSION, + dwlConditionMask); + + if (ok) { + wprintf(L"Updates are not needed to Windows 8, they are already inbox\n"); + error = ERROR_SUCCESS; + goto exit; + } + + // + // Create MSU name + // + + ZeroMemory(&curOsvi, sizeof(OSVERSIONINFO)); + curOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + +#pragma warning( push ) +#pragma warning( disable : 4996 ) // 'GetVersionEx': was declared deprecated + ok = GetVersionEx(&curOsvi); + + if (ok == FALSE) { + + error = GetLastError(); + wprintf(L"GetVersionEx failed: %x\n", error); + goto exit; + } + + // + // We want to apply the updates in a specific order. This is because UMDF + // is potentially dependent on WinUSB. WinUSB is dependent on KMDF. If we + // fail to apply an update, we want to make sure the machine is in a good + // state. This we apply required framework updates first. + // KMDF > WinUSB > UMDF + // + +#if INSTALL_KMDF + hr = StringCchPrintf(MSUName, + MAX_PATH, + MSU_FORMAT_STRING, + L"kmdf", + WDF_MAJOR_VERSION, + WDF_MINOR_VERSION, + curOsvi.dwMajorVersion, + curOsvi.dwMinorVersion); + + if (hr != S_OK) { + wprintf(L"StringCchPrintf for KMDF MSU failed: %x\n", hr); + error = ERROR_INSTALL_FAILURE; + goto exit; + } + + error = ApplyUpdate(MSUName); + + if (error == ERROR_SUCCESS_REBOOT_REQUIRED) { + rebootNeeded = TRUE; + } else if (error != ERROR_SUCCESS) { + goto exit; + } +#endif // INSTALL_KMDF +#pragma warning( pop ) // 'GetVersionEx': was declared deprecated + +#if (INSTALL_WINUSB) + // + // WinUSB update only applies to Vista + // + + ZeroMemory(&targetOsvi, sizeof(OSVERSIONINFOEX)); + dwlConditionMask = 0; + + targetOsvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + targetOsvi.dwMajorVersion = 6; + targetOsvi.dwMinorVersion = 0; + + VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION, VER_EQUAL ); + VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION, VER_EQUAL ); + + ok = VerifyVersionInfo( &targetOsvi, + VER_MAJORVERSION | VER_MINORVERSION, + dwlConditionMask); + + if (ok) { + error = ApplyUpdate(WINUSB_UPDATE_NAME); + + if (error == ERROR_SUCCESS_REBOOT_REQUIRED) { + rebootNeeded = TRUE; + } else if (error != ERROR_SUCCESS) { + goto exit; + } + } +#endif // INSTALL_WINUSB + +#if INSTALL_UMDF + hr = StringCchPrintf(MSUName, + MAX_PATH, + MSU_FORMAT_STRING, + L"umdf", + WDF_MAJOR_VERSION, + WDF_MINOR_VERSION, + curOsvi.dwMajorVersion, + curOsvi.dwMinorVersion); + + if (hr != S_OK) { + wprintf(L"StringCchPrintf for UMDF MSU failed: %x\n", hr); + error = ERROR_INSTALL_FAILURE; + goto exit; + } + + error = ApplyUpdate(MSUName); + + if (error == ERROR_SUCCESS_REBOOT_REQUIRED) { + rebootNeeded = TRUE; + } else if (error != ERROR_SUCCESS) { + goto exit; + } +#endif // INSTALL_UMDF + + // + // If we have made it to this point there have been no fatal errors. If + // there were fatal errors, these should be caught and we would've jumped + // to exit. + // + // We must account for the fact the latest update applied did not require + // a reboot but earlier updates did. + // + if (rebootNeeded == TRUE) { + + error = ERROR_SUCCESS_REBOOT_REQUIRED; + goto exit; + } + + error = ERROR_SUCCESS; + +exit: + + return error; +} + +int __cdecl +wmain( + _In_ int argc, + _In_reads_(argc) char* argv[] + ) +{ + DWORD updateStatus; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + updateStatus = UpdateWdf(); + + if (updateStatus == ERROR_SUCCESS_REBOOT_REQUIRED) { + + int msgboxID = MessageBox( + NULL, + L"A restart is needed for these changes to take effect\nRestart now?", + L"Restart Required", + MB_ICONEXCLAMATION | MB_YESNO + ); + + if (msgboxID == IDYES) + { + PromptRestart(); + } + } + + return updateStatus; +} diff --git a/general/installwdf/InstallWdf.vcxproj b/general/installwdf/InstallWdf.vcxproj new file mode 100644 index 00000000..566e44b1 --- /dev/null +++ b/general/installwdf/InstallWdf.vcxproj @@ -0,0 +1,187 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{242C8F74-1471-4876-ABE9-F9B3798F7537}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{EC6592EB-25EF-40EB-8E93-87FABB3C6085}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>InstallWdf</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>InstallWdf</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>InstallWdf</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>InstallWdf</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/installwdf/InstallWdf.vcxproj.Filters b/general/installwdf/InstallWdf.vcxproj.Filters new file mode 100644 index 00000000..aded6d8a --- /dev/null +++ b/general/installwdf/InstallWdf.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{5F54DABF-B262-4C6D-922E-4458AB12ED8C}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{7D22CB0D-9813-4E12-B539-5F8A9BCC71F1}</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>{13558A71-E018-47D4-B9A5-45A8C27B32B1}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/installwdf/ReadMe.md b/general/installwdf/ReadMe.md new file mode 100644 index 00000000..429957d5 --- /dev/null +++ b/general/installwdf/ReadMe.md @@ -0,0 +1,9 @@ +WDF Installation Package +======================== + +This sample contains example code that demonstrates how to install WDF packages on a system. This code can be used as-is to install the needed WDF components onto a user system. This code can also be reworked into an existing setup application to provide a better experience. + + +Related technologies +-------------------- +[Installation Components for Framework-based Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544208) diff --git a/general/installwdf/installwdf.sln b/general/installwdf/installwdf.sln new file mode 100644 index 00000000..e520c1dc --- /dev/null +++ b/general/installwdf/installwdf.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InstallWdf", "InstallWdf.vcxproj", "{242C8F74-1471-4876-ABE9-F9B3798F7537}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|Win32.ActiveCfg = Debug|Win32 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|Win32.Build.0 = Debug|Win32 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|Win32.ActiveCfg = Release|Win32 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|Win32.Build.0 = Release|Win32 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|x64.ActiveCfg = Debug|x64 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Debug|x64.Build.0 = Debug|x64 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|x64.ActiveCfg = Release|x64 + {242C8F74-1471-4876-ABE9-F9B3798F7537}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/ioctl/wdm/ReadMe.md b/general/ioctl/wdm/ReadMe.md new file mode 100644 index 00000000..94191a33 --- /dev/null +++ b/general/ioctl/wdm/ReadMe.md @@ -0,0 +1,17 @@ +IOCTL +===== + +This sample demonstrates the usage of four different types of IOCTLs (METHOD\_IN\_DIRECT, METHOD\_OUT\_DIRECT, METHOD\_NEITHER, and METHOD\_BUFFERED). + +The sample shows how the user input and output buffers specified in the **DeviceIoControl** function call are handled, in each case, by the I/O subsystem and the driver. + +The sample consists of a legacy device driver and a Win32 console test application. The test application opens a handle to the device exposed by the driver and makes all four different **DeviceIoControl** calls, one after another. To understand how the IRP fields are set the I/O manager, you should run the checked build version of the driver and look at the debug output. + +**Note** This sample driver is not a Plug and Play driver. This is a minimal driver meant to demonstrate a feature of the operating system. Neither this driver nor its sample programs are intended for use in a production environment. Instead, they are intended for educational purposes and as a skeleton driver. + + +Run the sample +-------------- + +To test this driver, copy the test app, Ioctlapp.exe, and the driver to the same directory, and run the application. The application will automatically load the driver, if it's not already loaded, and interact with the driver. When you exit the application, the driver will be stopped, unloaded and removed. + diff --git a/general/ioctl/wdm/exe/install.c b/general/ioctl/wdm/exe/install.c new file mode 100644 index 00000000..4b77f0aa --- /dev/null +++ b/general/ioctl/wdm/exe/install.c @@ -0,0 +1,550 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + +--*/ + + +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strsafe.h> +#include "sioctl.h" + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("CreateService failed! Error = %d \n", err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + printf("Invalid Driver or Service provided to ManageDriver() \n"); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + printf("Open SC Manager failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + printf("Unknown ManageDriver() function. \n"); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + if (schSCManager) { + + CloseServiceHandle(schSCManager); + } + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("DeleteService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + printf("StartService failure! Error = %d \n", err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + _In_ SC_HANDLE SchSCManager, + _In_ LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + printf("OpenService failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + printf("ControlService failed! Error = %d \n", GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle (schService); + } + + return rCode; + +} // StopDriver + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ) +{ + HANDLE fileHandle; + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(BufferLength, + DriverLocation + ); + + if (driverLocLen == 0) { + + printf("GetCurrentDirectory failed! Error = %d \n", GetLastError()); + + return FALSE; + } + + // + // Setup path name to driver file. + // + if (FAILED( StringCbCat(DriverLocation, BufferLength, "\\"DRIVER_NAME".sys") )) { + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + printf("%s.sys is not loaded.\n", DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName + + + diff --git a/general/ioctl/wdm/exe/ioctlapp.vcxproj b/general/ioctl/wdm/exe/ioctlapp.vcxproj new file mode 100644 index 00000000..976df289 --- /dev/null +++ b/general/ioctl/wdm/exe/ioctlapp.vcxproj @@ -0,0 +1,196 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{76D71F31-1E96-453B-B624-603110936517}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{F11B90FF-7C0F-4187-A69C-B3D2C6FA36BD}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ioctlapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ioctlapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ioctlapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ioctlapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\sys</AdditionalIncludeDirectories> + </Midl> + <Link> + <BaseAddress>0x04000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.c" /> + <ClCompile Include="testapp.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/ioctl/wdm/exe/ioctlapp.vcxproj.Filters b/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters new file mode 100644 index 00000000..6698bc65 --- /dev/null +++ b/general/ioctl/wdm/exe/ioctlapp.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{A6129EF0-0D42-48B8-B0C4-C484D8CB1BEC}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{7C1B93C7-3641-4D37-AF76-8B4E72FB0E36}</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>{4E2B024A-1EF5-41B1-A019-C74272815D2A}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="testapp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/ioctl/wdm/exe/testapp.c b/general/ioctl/wdm/exe/testapp.c new file mode 100644 index 00000000..5a62faa0 --- /dev/null +++ b/general/ioctl/wdm/exe/testapp.c @@ -0,0 +1,261 @@ +/*++ + +Copyright (c) 1990-98 Microsoft Corporation All Rights Reserved + +Module Name: + + testapp.c + +Abstract: + +Environment: + + Win32 console multi-threaded application + +--*/ +#include <windows.h> +#include <winioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strsafe.h> +#include "..\sys\sioctl.h" + + +BOOLEAN +ManageDriver( + _In_ LPCTSTR DriverName, + _In_ LPCTSTR ServiceName, + _In_ USHORT Function + ); + +BOOLEAN +SetupDriverName( + _Inout_updates_bytes_all_(BufferLength) PCHAR DriverLocation, + _In_ ULONG BufferLength + ); + +char OutputBuffer[100]; +char InputBuffer[100]; + +VOID __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + HANDLE hDevice; + BOOL bRc; + ULONG bytesReturned; + DWORD errNum = 0; + TCHAR driverLocation[MAX_PATH]; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + // + // open the device + // + + if ((hDevice = CreateFile( "\\\\.\\IoctlTest", + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL)) == INVALID_HANDLE_VALUE) { + + errNum = GetLastError(); + + if (errNum != ERROR_FILE_NOT_FOUND) { + + printf("CreateFile failed! ERROR_FILE_NOT_FOUND = %d\n", errNum); + + return ; + } + + // + // The driver is not started yet so let us the install the driver. + // First setup full path to driver name. + // + + if (!SetupDriverName(driverLocation, sizeof(driverLocation))) { + + return ; + } + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + printf("Unable to install driver. \n"); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return; + } + + hDevice = CreateFile( "\\\\.\\IoctlTest", + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if ( hDevice == INVALID_HANDLE_VALUE ){ + printf ( "Error: CreatFile Failed : %d\n", GetLastError()); + return; + } + + } + + // + // Printing Input & Output buffer pointers and size + // + + printf("InputBuffer Pointer = %p, BufLength = %d\n", InputBuffer, + sizeof(InputBuffer)); + printf("OutputBuffer Pointer = %p BufLength = %d\n", OutputBuffer, + sizeof(OutputBuffer)); + // + // Performing METHOD_BUFFERED + // + + StringCbCopy(InputBuffer, sizeof(InputBuffer), + "This String is from User Application; using METHOD_BUFFERED"); + + printf("\nCalling DeviceIoControl METHOD_BUFFERED:\n"); + + memset(OutputBuffer, 0, sizeof(OutputBuffer)); + + bRc = DeviceIoControl ( hDevice, + (DWORD) IOCTL_SIOCTL_METHOD_BUFFERED, + &InputBuffer, + (DWORD) strlen ( InputBuffer )+1, + &OutputBuffer, + sizeof( OutputBuffer), + &bytesReturned, + NULL + ); + + if ( !bRc ) + { + printf ( "Error in DeviceIoControl : %d", GetLastError()); + return; + + } + printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); + + // + // Performing METHOD_NIETHER + // + + printf("\nCalling DeviceIoControl METHOD_NEITHER\n"); + + StringCbCopy(InputBuffer, sizeof(InputBuffer), + "This String is from User Application; using METHOD_NEITHER"); + memset(OutputBuffer, 0, sizeof(OutputBuffer)); + + bRc = DeviceIoControl ( hDevice, + (DWORD) IOCTL_SIOCTL_METHOD_NEITHER, + &InputBuffer, + (DWORD) strlen ( InputBuffer )+1, + &OutputBuffer, + sizeof( OutputBuffer), + &bytesReturned, + NULL + ); + + if ( !bRc ) + { + printf ( "Error in DeviceIoControl : %d\n", GetLastError()); + return; + + } + + printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); + + // + // Performing METHOD_IN_DIRECT + // + + printf("\nCalling DeviceIoControl METHOD_IN_DIRECT\n"); + + StringCbCopy(InputBuffer, sizeof(InputBuffer), + "This String is from User Application; using METHOD_IN_DIRECT"); + StringCbCopy(OutputBuffer, sizeof(OutputBuffer), + "This String is from User Application in OutBuffer; using METHOD_IN_DIRECT"); + + bRc = DeviceIoControl ( hDevice, + (DWORD) IOCTL_SIOCTL_METHOD_IN_DIRECT, + &InputBuffer, + (DWORD) strlen ( InputBuffer )+1, + &OutputBuffer, + sizeof( OutputBuffer), + &bytesReturned, + NULL + ); + + if ( !bRc ) + { + printf ( "Error in DeviceIoControl : : %d", GetLastError()); + return; + } + + printf(" Number of bytes transfered from OutBuffer: %d\n", + bytesReturned); + + // + // Performing METHOD_OUT_DIRECT + // + + printf("\nCalling DeviceIoControl METHOD_OUT_DIRECT\n"); + StringCbCopy(InputBuffer, sizeof(InputBuffer), + "This String is from User Application; using METHOD_OUT_DIRECT"); + memset(OutputBuffer, 0, sizeof(OutputBuffer)); + bRc = DeviceIoControl ( hDevice, + (DWORD) IOCTL_SIOCTL_METHOD_OUT_DIRECT, + &InputBuffer, + (DWORD) strlen ( InputBuffer )+1, + &OutputBuffer, + sizeof( OutputBuffer), + &bytesReturned, + NULL + ); + + if ( !bRc ) + { + printf ( "Error in DeviceIoControl : : %d", GetLastError()); + return; + } + + printf(" OutBuffer (%d): %s\n", bytesReturned, OutputBuffer); + + CloseHandle ( hDevice ); + + // + // Unload the driver. Ignore any errors. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + + // + // close the handle to the device. + // + +} + + diff --git a/general/ioctl/wdm/ioctl.sln b/general/ioctl/wdm/ioctl.sln new file mode 100644 index 00000000..ba787f9d --- /dev/null +++ b/general/ioctl/wdm/ioctl.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{91C983A9-7E97-4964-A924-F019A135772F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{9D017694-F9BE-450B-BF96-67F46D45BE81}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ioctlapp", "exe\ioctlapp.vcxproj", "{76D71F31-1E96-453B-B624-603110936517}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sioctl", "sys\sioctl.vcxproj", "{EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {76D71F31-1E96-453B-B624-603110936517}.Debug|Win32.ActiveCfg = Debug|Win32 + {76D71F31-1E96-453B-B624-603110936517}.Debug|Win32.Build.0 = Debug|Win32 + {76D71F31-1E96-453B-B624-603110936517}.Release|Win32.ActiveCfg = Release|Win32 + {76D71F31-1E96-453B-B624-603110936517}.Release|Win32.Build.0 = Release|Win32 + {76D71F31-1E96-453B-B624-603110936517}.Debug|x64.ActiveCfg = Debug|x64 + {76D71F31-1E96-453B-B624-603110936517}.Debug|x64.Build.0 = Debug|x64 + {76D71F31-1E96-453B-B624-603110936517}.Release|x64.ActiveCfg = Release|x64 + {76D71F31-1E96-453B-B624-603110936517}.Release|x64.Build.0 = Release|x64 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|Win32.ActiveCfg = Debug|Win32 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|Win32.Build.0 = Debug|Win32 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|Win32.ActiveCfg = Release|Win32 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|Win32.Build.0 = Release|Win32 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|x64.ActiveCfg = Debug|x64 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Debug|x64.Build.0 = Debug|x64 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|x64.ActiveCfg = Release|x64 + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {76D71F31-1E96-453B-B624-603110936517} = {91C983A9-7E97-4964-A924-F019A135772F} + {EFC79CFC-9D17-4830-90C1-1825B6CFE1AD} = {9D017694-F9BE-450B-BF96-67F46D45BE81} + EndGlobalSection +EndGlobal diff --git a/general/ioctl/wdm/sys/sioctl.c b/general/ioctl/wdm/sys/sioctl.c new file mode 100644 index 00000000..7eae2971 --- /dev/null +++ b/general/ioctl/wdm/sys/sioctl.c @@ -0,0 +1,744 @@ +/*++ + +Copyright (c) 1990-98 Microsoft Corporation All Rights Reserved + +Module Name: + + sioctl.c + +Abstract: + + Purpose of this driver is to demonstrate how the four different types + of IOCTLs can be used, and how the I/O manager handles the user I/O + buffers in each case. This sample also helps to understand the usage of + some of the memory manager functions. + +Environment: + + Kernel mode only. + +--*/ + + +// +// Include files. +// + +#include <ntddk.h> // various NT definitions +#include <string.h> + +#include "sioctl.h" + +#define NT_DEVICE_NAME L"\\Device\\SIOCTL" +#define DOS_DEVICE_NAME L"\\DosDevices\\IoctlTest" + +#if DBG +#define SIOCTL_KDPRINT(_x_) \ + DbgPrint("SIOCTL.SYS: ");\ + DbgPrint _x_; + +#else +#define SIOCTL_KDPRINT(_x_) +#endif + +// +// Device driver routine declarations. +// + +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH SioctlCreateClose; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH SioctlDeviceControl; + +DRIVER_UNLOAD SioctlUnloadDriver; + +VOID +PrintIrpInfo( + PIRP Irp + ); +VOID +PrintChars( + _In_reads_(CountChars) PCHAR BufferAddress, + _In_ size_t CountChars + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, DriverEntry ) +#pragma alloc_text( PAGE, SioctlCreateClose) +#pragma alloc_text( PAGE, SioctlDeviceControl) +#pragma alloc_text( PAGE, SioctlUnloadDriver) +#pragma alloc_text( PAGE, PrintIrpInfo) +#pragma alloc_text( PAGE, PrintChars) +#endif // ALLOC_PRAGMA + + +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + This routine is called by the Operating System to initialize the driver. + + It creates the device object, fills in the dispatch entry points and + completes the initialization. + +Arguments: + DriverObject - a pointer to the object that represents this device + driver. + + RegistryPath - a pointer to our Services key in the registry. + +Return Value: + STATUS_SUCCESS if initialized; an error otherwise. + +--*/ + +{ + NTSTATUS ntStatus; + UNICODE_STRING ntUnicodeString; // NT Device Name "\Device\SIOCTL" + UNICODE_STRING ntWin32NameString; // Win32 Name "\DosDevices\IoctlTest" + PDEVICE_OBJECT deviceObject = NULL; // ptr to device object + + UNREFERENCED_PARAMETER(RegistryPath); + + RtlInitUnicodeString( &ntUnicodeString, NT_DEVICE_NAME ); + + ntStatus = IoCreateDevice( + DriverObject, // Our Driver Object + 0, // We don't use a device extension + &ntUnicodeString, // Device name "\Device\SIOCTL" + FILE_DEVICE_UNKNOWN, // Device type + FILE_DEVICE_SECURE_OPEN, // Device characteristics + FALSE, // Not an exclusive device + &deviceObject ); // Returned ptr to Device Object + + if ( !NT_SUCCESS( ntStatus ) ) + { + SIOCTL_KDPRINT(("Couldn't create the device object\n")); + return ntStatus; + } + + // + // Initialize the driver object with this driver's entry points. + // + + DriverObject->MajorFunction[IRP_MJ_CREATE] = SioctlCreateClose; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = SioctlCreateClose; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SioctlDeviceControl; + DriverObject->DriverUnload = SioctlUnloadDriver; + + // + // Initialize a Unicode String containing the Win32 name + // for our device. + // + + RtlInitUnicodeString( &ntWin32NameString, DOS_DEVICE_NAME ); + + // + // Create a symbolic link between our device name and the Win32 name + // + + ntStatus = IoCreateSymbolicLink( + &ntWin32NameString, &ntUnicodeString ); + + if ( !NT_SUCCESS( ntStatus ) ) + { + // + // Delete everything that this routine has allocated. + // + SIOCTL_KDPRINT(("Couldn't create symbolic link\n")); + IoDeleteDevice( deviceObject ); + } + + + return ntStatus; +} + + +NTSTATUS +SioctlCreateClose( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) +/*++ + +Routine Description: + + This routine is called by the I/O system when the SIOCTL is opened or + closed. + + No action is performed other than completing the request successfully. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE(); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return STATUS_SUCCESS; +} + +VOID +SioctlUnloadDriver( + _In_ PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + This routine is called by the I/O system to unload the driver. + + Any resources previously allocated must be freed. + +Arguments: + + DriverObject - a pointer to the object that represents our driver. + +Return Value: + + None +--*/ + +{ + PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; + UNICODE_STRING uniWin32NameString; + + PAGED_CODE(); + + // + // Create counted string version of our Win32 device name. + // + + RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); + + + // + // Delete the link from our device name to a name in the Win32 namespace. + // + + IoDeleteSymbolicLink( &uniWin32NameString ); + + if ( deviceObject != NULL ) + { + IoDeleteDevice( deviceObject ); + } + + + +} + +NTSTATUS +SioctlDeviceControl( + PDEVICE_OBJECT DeviceObject, + PIRP Irp + ) + +/*++ + +Routine Description: + + This routine is called by the I/O system to perform a device I/O + control function. + +Arguments: + + DeviceObject - a pointer to the object that represents the device + that I/O is to be done on. + + Irp - a pointer to the I/O Request Packet for this request. + +Return Value: + + NT status code + +--*/ + +{ + PIO_STACK_LOCATION irpSp;// Pointer to current stack location + NTSTATUS ntStatus = STATUS_SUCCESS;// Assume success + ULONG inBufLength; // Input buffer length + ULONG outBufLength; // Output buffer length + PCHAR inBuf, outBuf; // pointer to Input and output buffer + PCHAR data = "This String is from Device Driver !!!"; + size_t datalen = strlen(data)+1;//Length of data including null + PMDL mdl = NULL; + PCHAR buffer = NULL; + + UNREFERENCED_PARAMETER(DeviceObject); + + PAGED_CODE(); + + irpSp = IoGetCurrentIrpStackLocation( Irp ); + inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength; + outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength; + + if (!inBufLength || !outBufLength) + { + ntStatus = STATUS_INVALID_PARAMETER; + goto End; + } + + // + // Determine which I/O control code was specified. + // + + switch ( irpSp->Parameters.DeviceIoControl.IoControlCode ) + { + case IOCTL_SIOCTL_METHOD_BUFFERED: + + // + // In this method the I/O manager allocates a buffer large enough to + // to accommodate larger of the user input buffer and output buffer, + // assigns the address to Irp->AssociatedIrp.SystemBuffer, and + // copies the content of the user input buffer into this SystemBuffer + // + + SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_BUFFERED\n")); + PrintIrpInfo(Irp); + + // + // Input buffer and output buffer is same in this case, read the + // content of the buffer before writing to it + // + + inBuf = Irp->AssociatedIrp.SystemBuffer; + outBuf = Irp->AssociatedIrp.SystemBuffer; + + // + // Read the data from the buffer + // + + SIOCTL_KDPRINT(("\tData from User :")); + // + // We are using the following function to print characters instead + // DebugPrint with %s format because we string we get may or + // may not be null terminated. + // + PrintChars(inBuf, inBufLength); + + // + // Write to the buffer over-writes the input buffer content + // + + RtlCopyBytes(outBuf, data, outBufLength); + + SIOCTL_KDPRINT(("\tData to User : ")); + PrintChars(outBuf, datalen ); + + // + // Assign the length of the data copied to IoStatus.Information + // of the Irp and complete the Irp. + // + + Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); + + // + // When the Irp is completed the content of the SystemBuffer + // is copied to the User output buffer and the SystemBuffer is + // is freed. + // + + break; + + case IOCTL_SIOCTL_METHOD_NEITHER: + + // + // In this type of transfer the I/O manager assigns the user input + // to Type3InputBuffer and the output buffer to UserBuffer of the Irp. + // The I/O manager doesn't copy or map the buffers to the kernel + // buffers. Nor does it perform any validation of user buffer's address + // range. + // + + + SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_NEITHER\n")); + + PrintIrpInfo(Irp); + + // + // A driver may access these buffers directly if it is a highest level + // driver whose Dispatch routine runs in the context + // of the thread that made this request. The driver should always + // check the validity of the user buffer's address range and check whether + // the appropriate read or write access is permitted on the buffer. + // It must also wrap its accesses to the buffer's address range within + // an exception handler in case another user thread deallocates the buffer + // or attempts to change the access rights for the buffer while the driver + // is accessing memory. + // + + inBuf = irpSp->Parameters.DeviceIoControl.Type3InputBuffer; + outBuf = Irp->UserBuffer; + + // + // Access the buffers directly if only if you are running in the + // context of the calling process. Only top level drivers are + // guaranteed to have the context of process that made the request. + // + + try { + // + // Before accessing user buffer, you must probe for read/write + // to make sure the buffer is indeed an userbuffer with proper access + // rights and length. ProbeForRead/Write will raise an exception if it's otherwise. + // + ProbeForRead( inBuf, inBufLength, sizeof( UCHAR ) ); + + // + // Since the buffer access rights can be changed or buffer can be freed + // anytime by another thread of the same process, you must always access + // it within an exception handler. + // + + SIOCTL_KDPRINT(("\tData from User :")); + PrintChars(inBuf, inBufLength); + + } + except(EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + SIOCTL_KDPRINT(( + "Exception while accessing inBuf 0X%08X in METHOD_NEITHER\n", + ntStatus)); + break; + } + + + // + // If you are accessing these buffers in an arbitrary thread context, + // say in your DPC or ISR, if you are using it for DMA, or passing these buffers to the + // next level driver, you should map them in the system process address space. + // First allocate an MDL large enough to describe the buffer + // and initilize it. Please note that on a x86 system, the maximum size of a buffer + // that an MDL can describe is 65508 KB. + // + + mdl = IoAllocateMdl(inBuf, inBufLength, FALSE, TRUE, NULL); + if (!mdl) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + try + { + + // + // Probe and lock the pages of this buffer in physical memory. + // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess + // Always perform this operation in a try except block. + // MmProbeAndLockPages will raise an exception if it fails. + // + MmProbeAndLockPages(mdl, UserMode, IoReadAccess); + } + except(EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + SIOCTL_KDPRINT(( + "Exception while locking inBuf 0X%08X in METHOD_NEITHER\n", + ntStatus)); + IoFreeMdl(mdl); + break; + } + + // + // Map the physical pages described by the MDL into system space. + // Note: double mapping the buffer this way causes lot of + // system overhead for large size buffers. + // + + buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); + + if (!buffer) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + MmUnlockPages(mdl); + IoFreeMdl(mdl); + break; + } + + // + // Now you can safely read the data from the buffer. + // + SIOCTL_KDPRINT(("\tData from User (SystemAddress) : ")); + PrintChars(buffer, inBufLength); + + // + // Once the read is over unmap and unlock the pages. + // + + MmUnlockPages(mdl); + IoFreeMdl(mdl); + + // + // The same steps can be followed to access the output buffer. + // + + mdl = IoAllocateMdl(outBuf, outBufLength, FALSE, TRUE, NULL); + if (!mdl) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + + try { + // + // Probe and lock the pages of this buffer in physical memory. + // You can specify IoReadAccess, IoWriteAccess or IoModifyAccess. + // + + MmProbeAndLockPages(mdl, UserMode, IoWriteAccess); + } + except(EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + SIOCTL_KDPRINT(( + "Exception while locking outBuf 0X%08X in METHOD_NEITHER\n", + ntStatus)); + IoFreeMdl(mdl); + break; + } + + + buffer = MmGetSystemAddressForMdlSafe(mdl, NormalPagePriority ); + + if (!buffer) { + MmUnlockPages(mdl); + IoFreeMdl(mdl); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + break; + } + // + // Write to the buffer + // + + RtlCopyBytes(buffer, data, outBufLength); + + SIOCTL_KDPRINT(("\tData to User : %s\n", buffer)); + PrintChars(buffer, datalen); + + MmUnlockPages(mdl); + + // + // Free the allocated MDL + // + + IoFreeMdl(mdl); + + // + // Assign the length of the data copied to IoStatus.Information + // of the Irp and complete the Irp. + // + + Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); + + break; + + case IOCTL_SIOCTL_METHOD_IN_DIRECT: + + // + // In this type of transfer, the I/O manager allocates a system buffer + // large enough to accommodatethe User input buffer, sets the buffer address + // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer + // into the SystemBuffer. For the user output buffer, the I/O manager + // probes to see whether the virtual address is readable in the callers + // access mode, locks the pages in memory and passes the pointer to + // MDL describing the buffer in Irp->MdlAddress. + // + + SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_IN_DIRECT\n")); + + PrintIrpInfo(Irp); + + inBuf = Irp->AssociatedIrp.SystemBuffer; + + SIOCTL_KDPRINT(("\tData from User in InputBuffer: ")); + PrintChars(inBuf, inBufLength); + + // + // To access the output buffer, just get the system address + // for the buffer. For this method, this buffer is intended for transfering data + // from the application to the driver. + // + + buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + + if (!buffer) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + SIOCTL_KDPRINT(("\tData from User in OutputBuffer: ")); + PrintChars(buffer, outBufLength); + + // + // Return total bytes read from the output buffer. + // Note OutBufLength = MmGetMdlByteCount(Irp->MdlAddress) + // + + Irp->IoStatus.Information = MmGetMdlByteCount(Irp->MdlAddress); + + // + // NOTE: Changes made to the SystemBuffer are not copied + // to the user input buffer by the I/O manager + // + + break; + + case IOCTL_SIOCTL_METHOD_OUT_DIRECT: + + // + // In this type of transfer, the I/O manager allocates a system buffer + // large enough to accommodate the User input buffer, sets the buffer address + // in Irp->AssociatedIrp.SystemBuffer and copies the content of user input buffer + // into the SystemBuffer. For the output buffer, the I/O manager + // probes to see whether the virtual address is writable in the callers + // access mode, locks the pages in memory and passes the pointer to MDL + // describing the buffer in Irp->MdlAddress. + // + + + SIOCTL_KDPRINT(("Called IOCTL_SIOCTL_METHOD_OUT_DIRECT\n")); + + PrintIrpInfo(Irp); + + + inBuf = Irp->AssociatedIrp.SystemBuffer; + + SIOCTL_KDPRINT(("\tData from User : ")); + PrintChars(inBuf, inBufLength); + + // + // To access the output buffer, just get the system address + // for the buffer. For this method, this buffer is intended for transfering data + // from the driver to the application. + // + + buffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); + + if (!buffer) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + // + // Write data to be sent to the user in this buffer + // + + RtlCopyBytes(buffer, data, outBufLength); + + SIOCTL_KDPRINT(("\tData to User : ")); + PrintChars(buffer, datalen); + + Irp->IoStatus.Information = (outBufLength<datalen?outBufLength:datalen); + + // + // NOTE: Changes made to the SystemBuffer are not copied + // to the user input buffer by the I/O manager + // + + break; + + default: + + // + // The specified I/O control code is unrecognized by this driver. + // + + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + SIOCTL_KDPRINT(("ERROR: unrecognized IOCTL %x\n", + irpSp->Parameters.DeviceIoControl.IoControlCode)); + break; + } + +End: + // + // Finish the I/O operation by simply completing the packet and returning + // the same status as in the packet itself. + // + + Irp->IoStatus.Status = ntStatus; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return ntStatus; +} + +VOID +PrintIrpInfo( + PIRP Irp) +{ + PIO_STACK_LOCATION irpSp; + irpSp = IoGetCurrentIrpStackLocation( Irp ); + + PAGED_CODE(); + + SIOCTL_KDPRINT(("\tIrp->AssociatedIrp.SystemBuffer = 0x%p\n", + Irp->AssociatedIrp.SystemBuffer)); + SIOCTL_KDPRINT(("\tIrp->UserBuffer = 0x%p\n", Irp->UserBuffer)); + SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.Type3InputBuffer = 0x%p\n", + irpSp->Parameters.DeviceIoControl.Type3InputBuffer)); + SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.InputBufferLength = %d\n", + irpSp->Parameters.DeviceIoControl.InputBufferLength)); + SIOCTL_KDPRINT(("\tirpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n", + irpSp->Parameters.DeviceIoControl.OutputBufferLength )); + return; +} + +VOID +PrintChars( + _In_reads_(CountChars) PCHAR BufferAddress, + _In_ size_t CountChars + ) +{ + PAGED_CODE(); + + if (CountChars) { + + while (CountChars--) { + + if (*BufferAddress > 31 + && *BufferAddress != 127) { + + KdPrint (( "%c", *BufferAddress) ); + + } else { + + KdPrint(( ".") ); + + } + BufferAddress++; + } + KdPrint (("\n")); + } + return; +} + + diff --git a/general/ioctl/wdm/sys/sioctl.h b/general/ioctl/wdm/sys/sioctl.h new file mode 100644 index 00000000..33c0ff4b --- /dev/null +++ b/general/ioctl/wdm/sys/sioctl.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) 1997 Microsoft Corporation + +Module Name: + + SIOCTL.H + +Abstract: + + + Defines the IOCTL codes that will be used by this driver. The IOCTL code + contains a command identifier, plus other information about the device, + the type of access with which the file must have been opened, + and the type of buffering. + +Environment: + + Kernel mode only. + +--*/ + +// +// Device type -- in the "User Defined" range." +// +#define SIOCTL_TYPE 40000 +// +// The IOCTL function codes from 0x800 to 0xFFF are for customer use. +// +#define IOCTL_SIOCTL_METHOD_IN_DIRECT \ + CTL_CODE( SIOCTL_TYPE, 0x900, METHOD_IN_DIRECT, FILE_ANY_ACCESS ) + +#define IOCTL_SIOCTL_METHOD_OUT_DIRECT \ + CTL_CODE( SIOCTL_TYPE, 0x901, METHOD_OUT_DIRECT , FILE_ANY_ACCESS ) + +#define IOCTL_SIOCTL_METHOD_BUFFERED \ + CTL_CODE( SIOCTL_TYPE, 0x902, METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#define IOCTL_SIOCTL_METHOD_NEITHER \ + CTL_CODE( SIOCTL_TYPE, 0x903, METHOD_NEITHER , FILE_ANY_ACCESS ) + + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 + +#define DRIVER_NAME "SIoctl" + diff --git a/general/ioctl/wdm/sys/sioctl.rc b/general/ioctl/wdm/sys/sioctl.rc new file mode 100644 index 00000000..a93374ac --- /dev/null +++ b/general/ioctl/wdm/sys/sioctl.rc @@ -0,0 +1,10 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Sample IOCTL Driver" +#define VER_INTERNALNAME_STR "SIOCTL.sys" + +#include "common.ver" diff --git a/general/ioctl/wdm/sys/sioctl.vcxproj b/general/ioctl/wdm/sys/sioctl.vcxproj new file mode 100644 index 00000000..7340c780 --- /dev/null +++ b/general/ioctl/wdm/sys/sioctl.vcxproj @@ -0,0 +1,140 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{EFC79CFC-9D17-4830-90C1-1825B6CFE1AD}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{733A9BE6-EB74-47AD-9701-2DB93FD4B2AC}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>sioctl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>sioctl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>sioctl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>sioctl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="sioctl.c" /> + <ResourceCompile Include="sioctl.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/ioctl/wdm/sys/sioctl.vcxproj.Filters b/general/ioctl/wdm/sys/sioctl.vcxproj.Filters new file mode 100644 index 00000000..3b5a4633 --- /dev/null +++ b/general/ioctl/wdm/sys/sioctl.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{68FEC55D-22E4-4CC8-86A7-C923C2AB8F07}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{9D595192-13EA-4968-AFE4-63BECD7EDD64}</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>{644100AF-059B-48EE-B8B9-280BA8724FF6}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{41B8EECC-BA42-433E-9150-6D2D385CC021}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="sioctl.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="sioctl.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/obcallback/ReadMe.md b/general/obcallback/ReadMe.md new file mode 100644 index 00000000..def34eac --- /dev/null +++ b/general/obcallback/ReadMe.md @@ -0,0 +1,42 @@ +ObCallback Callback Registration Driver +======================================= + +The ObCallback sample driver demonstrates the use of registered callbacks for process protection. The driver registers control callbacks which are called at process creation. + + +Design and Operation +-------------------- + +The sample exercises both the [**PsSetCreateProcessNotifyRoutineEx**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff559951) and the [**ObRegisterCallbacks**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff558692) routines. The first example uses the **ObRegisterCallbacks** routine and a callback to restrict requested access rights during a open process action. The second example uses the **PsSetCreateProcessNotifyRoutineEx** routine to reject a process creation by examining the command line. + +The following is a command line usage scenario to exercise access restriction: + +``` {.syntax xml:space="preserve"} +C:\> obcallbacktestctrl.exe -? (for command line help) +C:\> obcallbacktestctrl.exe -install (installs the kernel driver) +C:\> obcallbacktestctrl.exe -name notepad (specifies that the string “notepad” will be watched as a protected executable) + (now you can start up “notepad.exe”) +C:\> notepad + +C:\> tlist (locate the process ID of notepad.exe) + +C:\> kill –f 2329 (attempt to kill off the notepad.exe with a PID of 2329) +process notepad.exe (2329) – ‘Untitled – Notepad’ could not be killed + +C:\> obcallbacktestctrl.exe -deprotect (remove the protections on the notepad process) + +C:\> kill –f 2329 (attempt to kill off the process – which will succeed) +C:\> obcallbacktestctrl.exe -uninstall (uninstall the kernel driver) + + +``` + +The following is another sample test you can run to prevent a process from being created: + +``` {.syntax xml:space="preserve"} +C:\> obcallbacktestctrl.exe -install (installs the kernel driver) +C:\> obcallbacktestctrl.exe -reject notepad (specifies that the string “notepad” will be watched and prevented from starting as a process) + +C:\> notepad (now you can start up “notepad.exe”) +Access is denied. +``` diff --git a/general/obcallback/control/ObCallbackTestCtrl.vcxproj b/general/obcallback/control/ObCallbackTestCtrl.vcxproj new file mode 100644 index 00000000..d9ea7f08 --- /dev/null +++ b/general/obcallback/control/ObCallbackTestCtrl.vcxproj @@ -0,0 +1,236 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{8B053BEE-EA21-4D12-984B-6C93FE6D4992}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{BED8786D-3B67-42D0-AC7B-D7D2F45E551E}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ObCallbackTestCtrl</TargetName> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ObCallbackTestCtrl</TargetName> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ObCallbackTestCtrl</TargetName> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ObCallbackTestCtrl</TargetName> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalOptions>%(AdditionalOptions) /LARGEADDRESSAWARE</AdditionalOptions> + <AdditionalDependencies>%(AdditionalDependencies);ntdll.lib;kernel32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalOptions>%(AdditionalOptions) /LARGEADDRESSAWARE</AdditionalOptions> + <AdditionalDependencies>%(AdditionalDependencies);ntdll.lib;kernel32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalOptions>%(AdditionalOptions) /LARGEADDRESSAWARE</AdditionalOptions> + <AdditionalDependencies>%(AdditionalDependencies);ntdll.lib;kernel32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalOptions>%(AdditionalOptions) /LARGEADDRESSAWARE</AdditionalOptions> + <AdditionalDependencies>%(AdditionalDependencies);ntdll.lib;kernel32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="pchsrc.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="utils.cpp"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters b/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters new file mode 100644 index 00000000..b9258c52 --- /dev/null +++ b/general/obcallback/control/ObCallbackTestCtrl.vcxproj.Filters @@ -0,0 +1,28 @@ +<?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>{5FCF0F0F-49FE-446D-9A27-490CBE156E8F}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F9488019-A49A-430B-818A-BB8ADC3106D1}</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>{DBBA22E4-2B2D-4D16-8C9A-26B358D8752E}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="main.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pchsrc.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="utils.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/obcallback/control/common.h b/general/obcallback/control/common.h new file mode 100644 index 00000000..1ba366a2 --- /dev/null +++ b/general/obcallback/control/common.h @@ -0,0 +1,86 @@ + +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) + +#pragma once + +#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union + +#include "..\driver\shared.h" + +// +// Logging support macros. +// +// LOG_INFO +// LOG_INFO_FAILURE +// LOG_PASSED +// LOG_ERROR +// + + +#ifdef DEBUG +#define LOG_INFO(fmt, ...) \ + _tprintf(_T("%hs: ") fmt, __FUNCTION__, __VA_ARGS__);_tprintf(_T("\n")); +#define LOG_INFO_FAILURE(fmt, ...) \ + _tprintf(_T("ReportFailure %hs: ") fmt, __FUNCTION__, __VA_ARGS__);_tprintf(_T("\n")); + +#define LOG_PASSED(fmt, ...) \ + _tprintf(_T("\n!!!PASSED: %hs (%hs:%u): ") fmt, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__);_tprintf(_T("\n")); +#define LOG_ERROR(fmt, ...) \ + _tprintf(_T("\n!!!FAILED: %hs (%hs:%u): ") fmt, __FUNCTION__, __FILE__, __LINE__, __VA_ARGS__); _tprintf(_T("\n")); + +#else + +#define LOG_INFO(FormatString, ...) +#define LOG_INFO_FAILURE(FormatString, ...) + +#define LOG_PASSED(FormatString, ...) +#define LOG_ERROR(FormatString, ...) + +#endif + + +extern HANDLE TcDeviceHandle; + +BOOL TcInitialize(); +BOOL TcUnInitialize(); +BOOL TcCleanupSCM(); + +BOOL TcInstallDriver(); + +BOOL TcUninstallDriver(); + +BOOL TcRemoveProtection (); + +BOOL TcProcessName ( + _In_ int argc, + _In_reads_(argc) LPCWSTR argv[], + _In_ ULONG ulOperation +); + +BOOL TcUnprotectCallback (); + +BOOL TcProcessNameCallback ( + _In_reads_(NAME_SIZE+1) PCWSTR pnametoprotect, + _In_ ULONG ulOperation +); + +// +// Utility functions +// + +BOOL TcInitializeGlobals(); +BOOL TcLoadDriver(); +BOOL TcUnloadDriver(); + +BOOL TcCreateService(); +BOOL TcDeleteService(); +BOOL TcStartService(); +BOOL TcStopService(); + +BOOL TcOpenDevice(); +BOOL TcCloseDevice(); + diff --git a/general/obcallback/control/main.cpp b/general/obcallback/control/main.cpp new file mode 100644 index 00000000..e5a36224 --- /dev/null +++ b/general/obcallback/control/main.cpp @@ -0,0 +1,320 @@ +/*++ + +Module Name: + + main.cpp + +Abstract: + + Main module for for ps/Ob sample + +Notice: + + Use this sample code at your own risk; there is no support from Microsoft for the sample code. + In addition, this sample code is licensed to you under the terms of the Microsoft Public License + (http://www.microsoft.com/opensource/licenses.mspx) + + +--*/ + +#include "pch.h" +#include "common.h" + +// +// PrintUsage +// + +void TcPrintUsage() +{ + puts ("Usage:"); + puts (""); + puts(" ObCallbackTestCtrl.exe -install -name NameofExe -reject NameofExe -uninstall -deprotect [-?]"); + puts(" -install install driver"); + puts(" -uninstall uninstall driver"); + puts(" -name NameofExe protect/filter access to NameofExe"); + puts(" -reject NameofExe prevents execution of NameofExe"); + puts(" -deprotect unprotect/unfilter"); +} + +// +// wmain() +// + +int _cdecl +wmain ( + _In_ int argc, + _In_reads_(argc) LPCWSTR argv[] +) +{ + int ExitCode = ERROR_SUCCESS; + + if (argc > 1) + { + const wchar_t * arg = argv[1]; + + // initialize globals and logging + if (!TcInitialize()) { + puts("Initialization failed - program exiting"); + ExitCode = ERROR_FUNCTION_FAILED; + goto Exit; + } + + if (0 == wcscmp (arg, L"-install")) { + TcInstallDriver(); + } else + if (0 == wcscmp (arg, L"-uninstall")) { + TcUninstallDriver(); + } else + if ((0 == wcscmp (arg, L"-?")) || (0 == wcscmp (arg, L"-h")) || (0 == wcscmp (arg, L"-help"))) { + TcPrintUsage(); + } else + if (0 == wcscmp (arg, L"-deprotect")) { + TcRemoveProtection(); + } else + if (0 == wcscmp (arg, L"-name")) { + TcProcessName (argc, argv, TDProtectName_Protect); + } else + if (0 == wcscmp (arg, L"-reject")) { + TcProcessName (argc, argv, TDProtectName_Reject); + } else { + puts ("Unknown command!"); + TcPrintUsage(); + } + + } + else + { + TcPrintUsage(); + } + +Exit: + + if (!TcUnInitialize()) { + puts("UnInitialization failed"); + ExitCode = ERROR_FUNCTION_FAILED; + } + + return ExitCode; +} + + + +// +// TcRemoveProtection +// + +BOOL TcRemoveProtection () +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(_T("TcRemoveProtection: Entering")); + + + // + // Open a handle to the device. + // + + ReturnValue = TcOpenDevice(); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (_T("TcOpenDevice failed")); + goto Exit; + } + + + // + // Send the command to the driver + // + ReturnValue = TcUnprotectCallback(); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (_T("TcUnprotectCallback failed")); + goto Exit; + } + +Exit: + + // + // Close our handle to the device. + // + + ReturnValue = TcCloseDevice(); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (_T("TcCloseDevice failed")); + } + + + LOG_INFO(_T("TcRemoveProtection: Exiting")); + + return ReturnValue; +} + + +// +// TcProcessName +// + +BOOL TcProcessName( + _In_ int argc, + _In_reads_(argc) LPCWSTR argv[], + _In_ ULONG ulOperation +) +{ + BOOL ReturnValue = FALSE; + + PCWSTR pwProcessName = NULL; + + LOG_INFO(L"TcProcessName: Entering"); + + + // + // Parse command line. + // + // argv[1] is "-name" so starting from arg #2 that should be the process name to protect + // + + if (argc < 3) { + LOG_INFO_FAILURE (L"TcProcessName: Too few parameters"); + LOG_INFO_FAILURE (L"TcProcessName: Usage -name nameofExe -reject nameofExe"); + ReturnValue = FALSE; + goto Exit; + } + + pwProcessName = argv[2]; + + if (!pwProcessName) { + LOG_INFO_FAILURE (L"TcProcessName: NULL process name to process"); + ReturnValue = FALSE; + goto Exit; + } + + + LOG_INFO(L"Ready to copy process name"); + LOG_INFO(L"Name to pass to driver %ls", pwProcessName); + + + // + // Open a handle to the device. + // + + ReturnValue = TcOpenDevice(); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (L"TcProcessName: TcOpenDevice failed"); + goto Exit; + } + + + // + // Send process name to protect and the command to the driver + // + ReturnValue = TcProcessNameCallback(pwProcessName, ulOperation); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (L"TcProcessName: TcProcessNameCallback failed"); + goto Exit; + } + +Exit: + + // + // Close our handle to the device. + // + + ReturnValue = TcCloseDevice(); + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (L"TcProtectProcess: TcCloseDevice failed"); + } + + + LOG_INFO(L"TcProtectProcess: Exiting"); + + return ReturnValue; +} + + + +// +// TcInstallDriver - installs the kernel driver +// + +BOOL TcInstallDriver () +{ + BOOL bRC = TRUE; + + LOG_INFO(L"TcInstallDriver: Entering"); + BOOL Result = TcLoadDriver(); + + if (Result != TRUE) + { + LOG_ERROR (L"TcLoadDriver failed, exiting"); + bRC = FALSE; + goto Exit; + } + +Exit: + + LOG_INFO(L"TcInstallDriver: Exiting"); + return bRC; +} + + +// +// TcUninstallDriver - uninstalls the kernel driver +// + +BOOL TcUninstallDriver () +{ + BOOL bRC = TRUE; + + LOG_INFO(L"TcUninstallDriver: Entering"); + BOOL Result = TcUnloadDriver(); + + if (Result != TRUE) + { + LOG_ERROR (L"TcUnloadDriver failed, exiting"); + bRC = FALSE; + goto Exit; + } + +Exit: + + LOG_INFO(L"TcUninstallDriver: Exiting"); + return bRC; +} + + +// +// TcInitialize +// + +BOOL bLoggingInitialized = FALSE; + +BOOL TcInitialize () +{ + + BOOL Result = TcInitializeGlobals(); + if (Result != TRUE) + { + LOG_ERROR (L"TcInitializeGlobals failed, exiting"); + return FALSE; + } + + LOG_INFO(L"TcInitialize: Entering"); + return TRUE; + +} + +// +// TcUnInitialize +// + +BOOL TcUnInitialize() +{ + if (TcCleanupSCM() == FALSE){ + LOG_ERROR (L"TcUnInitialize failed cleanup of SCM"); + } + return TRUE; +} diff --git a/general/obcallback/control/pch.h b/general/obcallback/control/pch.h new file mode 100644 index 00000000..d165c04f --- /dev/null +++ b/general/obcallback/control/pch.h @@ -0,0 +1,18 @@ + +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) + +#pragma once + +//#include <nt.h> +//#include <ntrtl.h> +//#include <nturtl.h> +#include <windows.h> +#include <stdlib.h> +#include <tchar.h> +#include <strsafe.h> +#include <winioctl.h> + diff --git a/general/obcallback/control/pchsrc.cpp b/general/obcallback/control/pchsrc.cpp new file mode 100644 index 00000000..17305716 --- /dev/null +++ b/general/obcallback/control/pchsrc.cpp @@ -0,0 +1 @@ +#include "pch.h"
\ No newline at end of file diff --git a/general/obcallback/control/readme.txt b/general/obcallback/control/readme.txt new file mode 100644 index 00000000..694696ad --- /dev/null +++ b/general/obcallback/control/readme.txt @@ -0,0 +1,57 @@ +The sample code exercises both PsSetCreateProcessNotifyRoutineEx() and ObRegisterCallbacks(). +These routines were introduced in Vista SP1 and are present in Windows7. They are available in both 32bit OS and 64bit OS. +The first example uses ObRegisterCallbacks() and a callback to restrict requested access rights during a open process action. +The second example uses PsSetCreateProcessNotifyRoutineEx() to reject a process creation by examining the command line. + +The code once compiled produces two files: ObCallbackTest.sys and ObCallbackTestCtrl.exe + +It is important to change the names of the binaries in the sample code to be unique for your own use. +#define TD_DRIVER_NAME L"ObCallbackTest" +#define TD_DRIVER_NAME_WITH_EXT L"ObCallbackTest.sys" + +#define TD_NT_DEVICE_NAME L"\\Device\\ObCallbackTest" +#define TD_DOS_DEVICES_LINK_NAME L"\\DosDevices\\ObCallbackTest" +#define TD_WIN32_DEVICE_NAME L"\\\\.\\ObCallbackTest" + + + + +For running the code you can use (run as administrator): + + C:\> obcallbacktest.exe -? (for command line help) + C:\> obcallbacktest.exe -install (installs the kernel driver) + C:\> obcallbacktest.exe -name notepad (specifies that the string �notepad� will be watched as a protected executable) + + (now you can start up �notepad.exe�) + C:\> notepad + + (locate the process ID of notepad.exe) + C:\> tlist + + (attempt to kill off the notepad.exe with a PID of 2329) + C:\> kill �f 2329 + process notepad.exe (2329) � �Untitled � Notepad� could not be killed + + (remove the protections on the notepad process) + C:\> obcallbacktest.exe -deprotect + + (attempt to kill off the process � which will succeed) + C:\> kill �f 2329 + + (uninstall the kernel driver) + C:\> obcallbacktest.exe -uninstall + +Another sample test you can run is to prevent a process from being created + + C:\> obcallbacktest.exe -install (installs the kernel driver) + C:\> obcallbacktest.exe -reject notepad (specifies that the string �notepad� will be watched and prevented from starting as a process) + + (now you can start up �notepad.exe�) + C:\> notepad + Access is denied. + + +Use this sample code at your own risk; there is no support from Microsoft for the sample code. In addition, this sample code is licensed to you under the terms of the Microsoft Public License (http://www.microsoft.com/opensource/licenses.mspx). + +May 2009 + diff --git a/general/obcallback/control/utils.cpp b/general/obcallback/control/utils.cpp new file mode 100644 index 00000000..3c1cb617 --- /dev/null +++ b/general/obcallback/control/utils.cpp @@ -0,0 +1,727 @@ +// +// Module: utils.cpp +// +// Helper functions for Ob sample code tests. +// +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) +// +// + +#include "pch.h" +#include "common.h" + +// +// Globals +// + +SC_HANDLE TcScmHandle = NULL; +HANDLE TcDeviceHandle = INVALID_HANDLE_VALUE; + +WCHAR TcDriverPath[MAX_PATH]; + + +// +// TcUnprotectCallback +// +// Sends unprotect callback ioctl to the driver. +// + +BOOL TcUnprotectCallback () +{ + TD_UNPROTECT_CALLBACK_INPUT UnprotectCallbackInput = {0}; + + DWORD BytesReturned = 0; + + LOG_INFO (L"TcUnprotectCallback: entering"); + + BOOL Result = DeviceIoControl ( + TcDeviceHandle, + TD_IOCTL_UNPROTECT_CALLBACK, + &UnprotectCallbackInput, + sizeof(UnprotectCallbackInput), + NULL, + 0, + &BytesReturned, + NULL + ); + + if (Result == TRUE) + { + LOG_INFO (L"TcUnprotectCallback: succeeded"); + } + else + { + LOG_INFO_FAILURE (L"TcUnprotectCallback: DeviceIoControl failed, last error 0x%x", GetLastError()); + } + + + LOG_INFO (L"TcUnprotectCallback: exiting"); + return Result; +} + + +// +// TcUnprotectCallback +// +// Sends unprotect callback ioctl to the driver. +// + +BOOL TcProcessNameCallback ( + _In_reads_(NAME_SIZE+1) PCWSTR pnametoprotect, + _In_ ULONG ulOperation +) +{ + TD_PROTECTNAME_INPUT ProtectNameCallbackInput = {0}; + BOOL Result = FALSE; + DWORD BytesReturned = 0; + + LOG_INFO (L"TcProtectNameCallback: entering - nametoprotect %ls", pnametoprotect); + + // Copy the name of the exececutible to protect into IOCTL structure + if (!pnametoprotect) { + LOG_INFO_FAILURE (L"TcProcessNameCallback: NULL Protect Name"); + Result = FALSE; + goto Exit; + } + wcsncpy_s(ProtectNameCallbackInput.Name, pnametoprotect, NAME_SIZE); + ProtectNameCallbackInput.Operation = ulOperation; + + + LOG_INFO (L"TcProtectNameCallback: IOCTL sending nametoprotect %ls", ProtectNameCallbackInput.Name); + + Result = DeviceIoControl ( + TcDeviceHandle, + TD_IOCTL_PROTECT_NAME_CALLBACK, + &ProtectNameCallbackInput, + sizeof(ProtectNameCallbackInput), + NULL, + 0, + &BytesReturned, + NULL + ); + + if (Result == TRUE) + { + LOG_INFO (L"TcProcessNameCallback: succeeded"); + } + else + { + LOG_INFO_FAILURE (L"TcProcessNameCallback: DeviceIoControl failed, last error 0x%x", GetLastError()); + } + +Exit: + + LOG_INFO (L"TcProcessNameCallback: exiting"); + return Result; +} + + + +// +// TcInitializeGlobals +// + +BOOL TcInitializeGlobals() +{ + WCHAR SysDir[MAX_PATH]; + BOOL ReturnValue = FALSE; + +#if !defined (_WIN64) + + BOOL Result = FALSE; + BOOL Wow64Process = FALSE; + PVOID OldWowRedirectionValue = NULL; + + Result = IsWow64Process ( + GetCurrentProcess(), + &Wow64Process + ); + + if (Result == FALSE) + { + LOG_INFO_FAILURE (L"IsWow64Process failed, last error 0x%x", GetLastError()); + goto Exit; + } + + if (Wow64Process == TRUE) + { + // + // Disable FS redirection to make sure a 32 bit test process will + // copy our (64 bit) driver to system32\drivers rather than syswow64\drivers. + // + + Result = Wow64DisableWow64FsRedirection (&OldWowRedirectionValue); + + if (Result == FALSE) + { + LOG_INFO_FAILURE (L"Wow64DisableWow64FsRedirection failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + +#endif + + // + // Open the service control manager if not already open + // + + if (TcScmHandle == NULL) { + TcScmHandle = OpenSCManager ( + NULL, + NULL, + SC_MANAGER_ALL_ACCESS + ); + + if (TcScmHandle == NULL) + { + LOG_INFO_FAILURE (L"OpenSCManager failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + // + // Construct driver path. + // + + UINT Size = GetSystemDirectory (SysDir, ARRAYSIZE(SysDir)); + + if (Size == 0) + { + LOG_INFO_FAILURE (L"GetSystemDirectory failed, last error 0x%x", GetLastError()); + goto Exit; + } + + HRESULT hr = StringCchPrintf ( + TcDriverPath, + ARRAYSIZE(TcDriverPath), + L"%ls\\drivers\\%ls.sys", + SysDir, + TD_DRIVER_NAME + ); + + if (FAILED (hr)) + { + LOG_INFO_FAILURE (L"StringCchPrintf failed, hr 0x%08x", hr); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + return ReturnValue; +} + + +// +// TcUnInitialize +// + +BOOL TcCleanupSCM() +{ + if (TcScmHandle != NULL) { + CloseServiceHandle(TcScmHandle); + TcScmHandle = NULL; + } + + return TRUE; +} + +// +// TcLoadDriver +// + +BOOL TcLoadDriver() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcLoadDriver: Entering"); + + // + // First, uninstall and unload the driver. + // + + ReturnValue = TcUnloadDriver(); + + if (ReturnValue != TRUE) + { + LOG_INFO_FAILURE (L"TcUnloadDriver failed"); + goto Exit; + } + + // + // Copy the driver to system32\drivers + // + + ReturnValue = CopyFile (TD_DRIVER_NAME_WITH_EXT, TcDriverPath, FALSE); + + if (ReturnValue == FALSE) + { + LOG_INFO_FAILURE ( + L"CopyFile(%ls, %ls) failed, last error 0x%x", + TD_DRIVER_NAME_WITH_EXT, TcDriverPath, GetLastError() + ); + + goto Exit; + } + + // + // Install the driver. + // + + ReturnValue = TcCreateService(); + + if (ReturnValue == FALSE) + { + LOG_INFO_FAILURE (L"TcCreateService failed"); + goto Exit; + } + + // + // Load the driver. + // + + ReturnValue = TcStartService(); + + if (ReturnValue == FALSE) + { + LOG_INFO_FAILURE (L"TcStartService failed"); + goto Exit; + } + + + ReturnValue = TRUE; + +Exit: + + LOG_INFO(L"TcLoadDriver: Exiting"); + return ReturnValue; +} + + + +// +// TcUnloadDriver +// + +BOOL TcUnloadDriver() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcUnloadDriver: Entering"); + + + // + // Unload the driver. + // + + ReturnValue = TcStopService(); + + if (ReturnValue == FALSE) + { + LOG_INFO_FAILURE (L"TcStopService failed"); + goto Exit; + } + + // + // Delete the service. + // + + ReturnValue = TcDeleteService(); + + if (ReturnValue == FALSE) + { + LOG_INFO_FAILURE (L"TcDeleteService failed"); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + LOG_INFO(L"TcUnloadDriver: Exiting"); + + return ReturnValue; +} + +// +// TcGetServiceState +// + +BOOL TcGetServiceState ( + _In_ SC_HANDLE ServiceHandle, + _Out_ DWORD* State +) +{ + SERVICE_STATUS_PROCESS ServiceStatus; + DWORD BytesNeeded; + + *State = 0; + + BOOL Result = QueryServiceStatusEx ( + ServiceHandle, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ServiceStatus, + sizeof(ServiceStatus), + &BytesNeeded + ); + + if (Result == FALSE) + { + LOG_INFO_FAILURE (L"TcGetServiceState: QueryServiceStatusEx failed, last error 0x%x", GetLastError()); + return FALSE; + } + + *State = ServiceStatus.dwCurrentState; + + return TRUE; +} + +// +// Wait for service to enter specified state. +// + +BOOL TcWaitForServiceState ( + _In_ SC_HANDLE ServiceHandle, + _In_ DWORD State +) +{ + for (;;) + { + LOG_INFO (L"TcWaitForServiceState: Waiting for service %p to enter state %u...", (DWORD_PTR)ServiceHandle, State); + + DWORD ServiceState; + BOOL Result = TcGetServiceState (ServiceHandle, &ServiceState); + + if (Result == FALSE) + { + return FALSE; + } + + if (ServiceState == State) + { + break; + } + + Sleep (1000); + } + + return TRUE; +} + +// +// TcCreateService +// + +BOOL TcCreateService() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcCreateService: Entering"); + + // + // Create the service + // + + SC_HANDLE ServiceHandle = CreateService ( + TcScmHandle, // handle to SC manager + TD_DRIVER_NAME, // name of service + TD_DRIVER_NAME, // display name + SERVICE_ALL_ACCESS, // access mask + SERVICE_KERNEL_DRIVER, // service type + SERVICE_DEMAND_START, // start type + SERVICE_ERROR_NORMAL, // error control + TcDriverPath, // full path to driver + NULL, // load ordering + NULL, // tag id + NULL, // dependency + NULL, // account name + NULL // password + ); + + DWORD LastError = GetLastError(); + + if (ServiceHandle == NULL && LastError != ERROR_SERVICE_EXISTS) + { + LOG_INFO_FAILURE (L"CreateService failed, last error 0x%x", LastError); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (ServiceHandle) + { + CloseServiceHandle (ServiceHandle); + } + + LOG_INFO(L"TcCreateService: Exiting"); + + return ReturnValue; +} + +// +// TcStartService +// + +BOOL TcStartService() +{ + BOOL ReturnValue = FALSE; + + // + // Open the service. The function assumes that + // TdCreateService has been called before this one + // and the service is already installed. + // + + SC_HANDLE ServiceHandle = OpenService ( + TcScmHandle, + TD_DRIVER_NAME, + SERVICE_ALL_ACCESS + ); + + if (ServiceHandle == NULL) + { + LOG_INFO_FAILURE (L"TcStartService: OpenService failed, last error 0x%x", GetLastError()); + goto Exit; + } + + // + // Start the service + // + + if (! StartService (ServiceHandle, 0, NULL)) + { + if (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) + { + LOG_INFO_FAILURE (L"TcStartService: StartService failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + + if (FALSE == TcWaitForServiceState (ServiceHandle, SERVICE_RUNNING)) + { + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (ServiceHandle) + { + CloseServiceHandle (ServiceHandle); + } + + return ReturnValue; +} + + +// +// TcStopService +// + +BOOL TcStopService() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcStopService: Entering"); + + // + // Open the service so we can stop it + // + + SC_HANDLE ServiceHandle = OpenService ( + TcScmHandle, + TD_DRIVER_NAME, + SERVICE_ALL_ACCESS + ); + + DWORD LastError = GetLastError(); + + if (ServiceHandle == NULL) + { + if (LastError == ERROR_SERVICE_DOES_NOT_EXIST) + { + ReturnValue = TRUE; + } + else + { + LOG_INFO_FAILURE (L"TcStopService: OpenService failed, last error 0x%x", LastError); + } + + goto Exit; + } + + // + // Stop the service + // + + SERVICE_STATUS ServiceStatus; + + if (FALSE == ControlService (ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus)) + { + LastError = GetLastError(); + + if (LastError != ERROR_SERVICE_NOT_ACTIVE) + { + LOG_INFO_FAILURE (L"TcStopService: ControlService failed, last error 0x%x", LastError); + goto Exit; + } + } + + if (FALSE == TcWaitForServiceState (ServiceHandle, SERVICE_STOPPED)) + { + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (ServiceHandle) + { + CloseServiceHandle (ServiceHandle); + } + + LOG_INFO(L"TcStopService: Exiting"); + + return ReturnValue; +} + +// +// TcDeleteService +// + +BOOL TcDeleteService() +{ + BOOL ReturnValue = FALSE; + + + LOG_INFO(L"TcDeleteService: Entering"); + + // + // Open the service so we can delete it + // + + SC_HANDLE ServiceHandle = OpenService ( + TcScmHandle, + TD_DRIVER_NAME, + SERVICE_ALL_ACCESS + ); + + DWORD LastError = GetLastError(); + + if (ServiceHandle == NULL) + { + if (LastError == ERROR_SERVICE_DOES_NOT_EXIST) + { + ReturnValue = TRUE; + } + else + { + LOG_INFO_FAILURE (L"TcDeleteService: OpenService failed, last error 0x%x", LastError); + } + + goto Exit; + } + + // + // Delete the service + // + + if (! DeleteService (ServiceHandle)) + { + LastError = GetLastError(); + + if (LastError != ERROR_SERVICE_MARKED_FOR_DELETE) + { + LOG_INFO_FAILURE (L"TcDeleteService: DeleteService failed, last error 0x%x", LastError); + goto Exit; + } + } + + ReturnValue = TRUE; + +Exit: + + if (ServiceHandle) + { + CloseServiceHandle (ServiceHandle); + } + + LOG_INFO(L"TcDeleteService: Exiting"); + + return ReturnValue; +} + +// +// TcOpenDevice +// + +BOOL TcOpenDevice() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcOpenDevice: Entering"); + + + // + // Open the device if not already opened + // + if (TcDeviceHandle == INVALID_HANDLE_VALUE) { + TcDeviceHandle = CreateFile ( + TD_WIN32_DEVICE_NAME, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (TcDeviceHandle == INVALID_HANDLE_VALUE) + { + LOG_INFO_FAILURE (L"TcOpenDevice: CreateFile(%ls) failed, last error 0x%x", TD_WIN32_DEVICE_NAME, GetLastError()); + goto Exit; + } + } + + + ReturnValue = TRUE; + +Exit: + + LOG_INFO(L"TcOpenDevice: Exiting"); + return ReturnValue; +} + +// +// TcOpenDevice +// + +BOOL TcCloseDevice() +{ + BOOL ReturnValue = FALSE; + + LOG_INFO(L"TcCloseDevice: Entering"); + + // + // Close our handle to the device. + // + + if (TcDeviceHandle != INVALID_HANDLE_VALUE) + { + CloseHandle (TcDeviceHandle); + TcDeviceHandle = INVALID_HANDLE_VALUE; + } + + ReturnValue = TRUE; + + LOG_INFO(L"TcCloseDevice: Exiting"); + return ReturnValue; +} + diff --git a/general/obcallback/driver/ObCallbackTest.vcxproj b/general/obcallback/driver/ObCallbackTest.vcxproj new file mode 100644 index 00000000..e781eb3a --- /dev/null +++ b/general/obcallback/driver/ObCallbackTest.vcxproj @@ -0,0 +1,210 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{C696D115-0970-4E9C-8FED-31A99E039ED5}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{F7152E7D-34B2-4B88-A5D9-17D68B786DFC}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>ObCallbackTest</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>ObCallbackTest</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>ObCallbackTest</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>ObCallbackTest</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /INTEGRITYCHECK</AdditionalOptions> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /INTEGRITYCHECK</AdditionalOptions> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /INTEGRITYCHECK</AdditionalOptions> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> + <AdditionalOptions>%(AdditionalOptions) /INTEGRITYCHECK</AdditionalOptions> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="callback.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="pchsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="tdriver.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="util.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>pch.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\pch.h.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/obcallback/driver/ObCallbackTest.vcxproj.Filters b/general/obcallback/driver/ObCallbackTest.vcxproj.Filters new file mode 100644 index 00000000..6fb49bed --- /dev/null +++ b/general/obcallback/driver/ObCallbackTest.vcxproj.Filters @@ -0,0 +1,35 @@ +<?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>{5962AF0C-70AA-4F9A-870A-9CA844475924}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{B9BBA35B-98FC-4830-9A01-41A3227755C9}</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>{75DE6DD6-44CF-4D1B-BC2C-1EF556200FC9}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{593EF94F-8BBC-4C56-999C-5D894DD5456F}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="callback.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pchsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="tdriver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/obcallback/driver/callback.c b/general/obcallback/driver/callback.c new file mode 100644 index 00000000..39ecd1b4 --- /dev/null +++ b/general/obcallback/driver/callback.c @@ -0,0 +1,479 @@ + +// Callback functions for Ob sample code tests. +// +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) +// +// + + +#include "pch.h" +#include "tdriver.h" + +// +// Globals +// + +KGUARDED_MUTEX TdCallbacksMutex; +BOOLEAN bCallbacksInstalled = FALSE; + + +#define CB_PROCESS_TERMINATE 0x0001 +#define CB_THREAD_TERMINATE 0x0001 + +// The following are for setting up callbacks for Process and Thread filtering +PVOID pCBRegistrationHandle = NULL; + +OB_CALLBACK_REGISTRATION CBObRegistration = { 0 }; +OB_OPERATION_REGISTRATION CBOperationRegistrations[2] = { { 0 }, { 0 } }; +UNICODE_STRING CBAltitude = {0}; +TD_CALLBACK_REGISTRATION CBCallbackRegistration = {0}; + +// Here is the protected process +WCHAR TdwProtectName[NAME_SIZE+1] = {0}; +PVOID TdProtectedTargetProcess = NULL; +HANDLE TdProtectedTargetProcessId = {0}; + + +// +// TdDeleteProtectNameCallback +// +NTSTATUS TdDeleteProtectNameCallback () +{ + NTSTATUS Status = STATUS_SUCCESS; + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdDeleteProtectNameCallback entering\n"); + + KeAcquireGuardedMutex (&TdCallbacksMutex); + + // if the callbacks are active - remove them + if (bCallbacksInstalled == TRUE) { + ObUnRegisterCallbacks(pCBRegistrationHandle); + pCBRegistrationHandle = NULL; + bCallbacksInstalled = FALSE; + } + + + KeReleaseGuardedMutex (&TdCallbacksMutex); + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdDeleteProtectNameCallback exiting - status 0x%x\n", Status + ); + + return Status; +} + + +// +// TdProtectNameCallback +// + +NTSTATUS TdProtectNameCallback ( + _In_ PTD_PROTECTNAME_INPUT pProtectName +) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (!pProtectName) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, + "ObCallbackTest: TdProtectNameCallback: name to protect/filter NULL pointer\n" + ); + } + else { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdProtectNameCallback: entering name to protect/filter %ls\n", pProtectName->Name + ); + } + KeAcquireGuardedMutex (&TdCallbacksMutex); + + // Need to copy out the name and then set the flag to filter + // This will allow process creation to watch for the process to be created and get the PID + // and then prevent any other process from opening up that PID to terminate + + memcpy(TdwProtectName, pProtectName->Name, sizeof(TdwProtectName)); + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: name copied %ls\n", TdwProtectName + ); + + // Need to enable the OB callbacks + // once the process is matched to a newly created process, the callbacks will protect the process + if (bCallbacksInstalled == FALSE) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdProtectNameCallback: installing callbacks\n" + ); + + // Setup the Ob Registration calls + + CBOperationRegistrations[0].ObjectType = PsProcessType; + CBOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_CREATE; + CBOperationRegistrations[0].Operations |= OB_OPERATION_HANDLE_DUPLICATE; + CBOperationRegistrations[0].PreOperation = CBTdPreOperationCallback; + CBOperationRegistrations[0].PostOperation = CBTdPostOperationCallback; + + CBOperationRegistrations[1].ObjectType = PsThreadType; + CBOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_CREATE; + CBOperationRegistrations[1].Operations |= OB_OPERATION_HANDLE_DUPLICATE; + CBOperationRegistrations[1].PreOperation = CBTdPreOperationCallback; + CBOperationRegistrations[1].PostOperation = CBTdPostOperationCallback; + + + RtlInitUnicodeString (&CBAltitude, L"1000"); + + CBObRegistration.Version = OB_FLT_REGISTRATION_VERSION; + CBObRegistration.OperationRegistrationCount = 2; + CBObRegistration.Altitude = CBAltitude; + CBObRegistration.RegistrationContext = &CBCallbackRegistration; + CBObRegistration.OperationRegistration = CBOperationRegistrations; + + + Status = ObRegisterCallbacks ( + &CBObRegistration, + &pCBRegistrationHandle // save the registration handle to remove callbacks later + ); + + if (!NT_SUCCESS (Status)) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, + "ObCallbackTest: installing OB callbacks failed status 0x%x\n", Status + ); + KeReleaseGuardedMutex (&TdCallbacksMutex); // Release the lock before exit + goto Exit; + } + bCallbacksInstalled = TRUE; + + } + + + KeReleaseGuardedMutex (&TdCallbacksMutex); + + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdProtectNameCallback: name to protect/filter %ls\n", TdwProtectName + ); + +Exit: + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdProtectNameCallback: exiting status 0x%x\n", Status + ); + return Status; +} + + +// +// TdCheckProcessMatch - function to test a command line to see if the process is to be protected +// +NTSTATUS TdCheckProcessMatch ( + _In_ PCUNICODE_STRING pustrCommand, + _In_ PEPROCESS Process, + _In_ HANDLE ProcessId +) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + WCHAR CommandLineBuffer[NAME_SIZE + 1] = {0}; // force a NULL termination + USHORT CommandLineBytes = 0; + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: entering\n"); + + if (!pustrCommand || !pustrCommand->Buffer) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: no Command line provided\n" + ); + Status = FALSE; + goto Exit; + } + else { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: checking for %ls\n", TdwProtectName + ); + } + + KeAcquireGuardedMutex (&TdCallbacksMutex); + + + // Make sure that the CommandLineBuffer is NULL terminated + if (pustrCommand->Length < (NAME_SIZE * sizeof(WCHAR))) + CommandLineBytes = pustrCommand->Length; + else + CommandLineBytes = NAME_SIZE * sizeof(WCHAR); + + if (CommandLineBytes) { + memcpy(CommandLineBuffer, pustrCommand->Buffer, CommandLineBytes); + + // now check if the process to protect is in the command line + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: command line %ls\n", CommandLineBuffer + ); + + if (NULL != wcsstr (CommandLineBuffer, TdwProtectName)) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: match FOUND\n" + ); + + // Set the process to watch + TdProtectedTargetProcess = Process; + TdProtectedTargetProcessId = ProcessId; + + Status = STATUS_SUCCESS; + } + } + else { + Status = FALSE; // no command line buffer provided + } + + KeReleaseGuardedMutex (&TdCallbacksMutex); + + +Exit: + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCheckProcessMatch: leaving status 0x%x\n", Status + ); + return Status; +} + + +// +// CBTdPreOperationCallback +// +OB_PREOP_CALLBACK_STATUS +CBTdPreOperationCallback ( + _In_ PVOID RegistrationContext, + _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo +) +{ + PTD_CALLBACK_REGISTRATION CallbackRegistration; + + ACCESS_MASK AccessBitsToClear = 0; + ACCESS_MASK AccessBitsToSet = 0; + ACCESS_MASK InitialDesiredAccess = 0; + ACCESS_MASK OriginalDesiredAccess = 0; + + + PACCESS_MASK DesiredAccess = NULL; + + LPCWSTR ObjectTypeName = NULL; + LPCWSTR OperationName = NULL; + + // Not using driver specific values at this time + CallbackRegistration = (PTD_CALLBACK_REGISTRATION)RegistrationContext; + + + TD_ASSERT (PreInfo->CallContext == NULL); + + // Only want to filter attempts to access protected process + // all other processes are left untouched + + if (PreInfo->ObjectType == *PsProcessType) { + // + // Ignore requests for processes other than our target process. + // + + // if (TdProtectedTargetProcess != NULL && + // TdProtectedTargetProcess != PreInfo->Object) + if (TdProtectedTargetProcess != PreInfo->Object) + { + goto Exit; + } + + // + // Also ignore requests that are trying to open/duplicate the current + // process. + // + + if (PreInfo->Object == PsGetCurrentProcess()) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: CBTdPreOperationCallback: ignore process open/duplicate from the protected process itself\n"); + goto Exit; + } + + ObjectTypeName = L"PsProcessType"; + AccessBitsToClear = CB_PROCESS_TERMINATE; + AccessBitsToSet = 0; + } + else if (PreInfo->ObjectType == *PsThreadType) { + HANDLE ProcessIdOfTargetThread = PsGetThreadProcessId ((PETHREAD)PreInfo->Object); + + // + // Ignore requests for threads belonging to processes other than our + // target process. + // + + // if (CallbackRegistration->TargetProcess != NULL && + // CallbackRegistration->TargetProcessId != ProcessIdOfTargetThread) + if (TdProtectedTargetProcessId != ProcessIdOfTargetThread) { + goto Exit; + } + + // + // Also ignore requests for threads belonging to the current processes. + // + + if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: CBTdPreOperationCallback: ignore thread open/duplicate from the protected process itself\n"); + goto Exit; + } + + ObjectTypeName = L"PsThreadType"; + AccessBitsToClear = CB_THREAD_TERMINATE; + AccessBitsToSet = 0; + } + else { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, + "ObCallbackTest: CBTdPreOperationCallback: unexpected object type\n"); + goto Exit; + } + + switch (PreInfo->Operation) { + case OB_OPERATION_HANDLE_CREATE: + DesiredAccess = &PreInfo->Parameters->CreateHandleInformation.DesiredAccess; + OriginalDesiredAccess = PreInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess; + + OperationName = L"OB_OPERATION_HANDLE_CREATE"; + break; + + case OB_OPERATION_HANDLE_DUPLICATE: + DesiredAccess = &PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess; + OriginalDesiredAccess = PreInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess; + + OperationName = L"OB_OPERATION_HANDLE_DUPLICATE"; + break; + + default: + TD_ASSERT (FALSE); + break; + } + + InitialDesiredAccess = *DesiredAccess; + + // Filter only if request made outside of the kernel + if (PreInfo->KernelHandle != 1) { + *DesiredAccess &= ~AccessBitsToClear; + *DesiredAccess |= AccessBitsToSet; + } + + // + // Set call context. + // + + TdSetCallContext (PreInfo, CallbackRegistration); + + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: CBTdPreOperationCallback: PROTECTED process %p (ID 0x%p)\n", + TdProtectedTargetProcess, + (PVOID)TdProtectedTargetProcessId + ); + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: CBTdPreOperationCallback\n" + " Client Id: %p:%p\n" + " Object: %p\n" + " Type: %ls\n" + " Operation: %ls (KernelHandle=%d)\n" + " OriginalDesiredAccess: 0x%x\n" + " DesiredAccess (in): 0x%x\n" + " DesiredAccess (out): 0x%x\n", + PsGetCurrentProcessId(), + PsGetCurrentThreadId(), + PreInfo->Object, + ObjectTypeName, + OperationName, + PreInfo->KernelHandle, + OriginalDesiredAccess, + InitialDesiredAccess, + *DesiredAccess + ); + +Exit: + + return OB_PREOP_SUCCESS; +} + +// +// TdPostOperationCallback +// + +VOID +CBTdPostOperationCallback ( + _In_ PVOID RegistrationContext, + _In_ POB_POST_OPERATION_INFORMATION PostInfo + ) +{ + PTD_CALLBACK_REGISTRATION CallbackRegistration = (PTD_CALLBACK_REGISTRATION)RegistrationContext; + + TdCheckAndFreeCallContext (PostInfo, CallbackRegistration); + + if (PostInfo->ObjectType == *PsProcessType) { + // + // Ignore requests for processes other than our target process. + // + + if (CallbackRegistration->TargetProcess != NULL && + CallbackRegistration->TargetProcess != PostInfo->Object + ) { + return; + } + + // + // Also ignore requests that are trying to open/duplicate the current + // process. + // + + if (PostInfo->Object == PsGetCurrentProcess()) { + return; + } + } + else if (PostInfo->ObjectType == *PsThreadType) { + HANDLE ProcessIdOfTargetThread = PsGetThreadProcessId ((PETHREAD)PostInfo->Object); + + // + // Ignore requests for threads belonging to processes other than our + // target process. + // + + if (CallbackRegistration->TargetProcess != NULL && + CallbackRegistration->TargetProcessId != ProcessIdOfTargetThread + ) { + return; + } + + // + // Also ignore requests for threads belonging to the current processes. + // + + if (ProcessIdOfTargetThread == PsGetCurrentProcessId()) { + return; + } + } + else { + TD_ASSERT (FALSE); + } + +} + diff --git a/general/obcallback/driver/pch.h b/general/obcallback/driver/pch.h new file mode 100644 index 00000000..9cab74cc --- /dev/null +++ b/general/obcallback/driver/pch.h @@ -0,0 +1,13 @@ + +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) + +#pragma once + +#include <ntddk.h> +#include <ntstrsafe.h> + + diff --git a/general/obcallback/driver/pchsrc.c b/general/obcallback/driver/pchsrc.c new file mode 100644 index 00000000..17305716 --- /dev/null +++ b/general/obcallback/driver/pchsrc.c @@ -0,0 +1 @@ +#include "pch.h"
\ No newline at end of file diff --git a/general/obcallback/driver/shared.h b/general/obcallback/driver/shared.h new file mode 100644 index 00000000..cea7f5f9 --- /dev/null +++ b/general/obcallback/driver/shared.h @@ -0,0 +1,95 @@ +/*++ + +Module Name: + + shared.h + +Abstract: + + This contains declarations shared by the Ob/Ps callback test driver and + the user mode test app. + + +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) + +--*/ + +#pragma once + +#pragma warning(disable:4214) // bit field types other than int +#pragma warning(disable:4201) // nameless struct/union + +// +// TD_ASSERT +// +// This macro is identical to NT_ASSERT but works in fre builds as well. +// +// It is used for error checking in the driver in cases where +// we can't easily report the error to the user mode app, or the +// error is so severe that we should break in immediately to +// investigate. +// +// It's better than DbgBreakPoint because it provides additional info +// that can be dumped with .exr -1, and individual asserts can be disabled +// from kd using 'ahi' command. +// + +#define TD_ASSERT(_exp) \ + ((!(_exp)) ? \ + (__annotation(L"Debug", L"AssertFail", L#_exp), \ + DbgRaiseAssertionFailure(), FALSE) : \ + TRUE) + +// +// Driver and device names +// It is important to change the names of the binaries +// in the sample code to be unique for your own use. +// + +#define TD_DRIVER_NAME L"ObCallbackTest" +#define TD_DRIVER_NAME_WITH_EXT L"ObCallbackTest.sys" + +#define TD_NT_DEVICE_NAME L"\\Device\\ObCallbackTest" +#define TD_DOS_DEVICES_LINK_NAME L"\\DosDevices\\ObCallbackTest" +#define TD_WIN32_DEVICE_NAME L"\\\\.\\ObCallbackTest" + + +#define NAME_SIZE 200 + +#define TD_INVALID_CALLBACK_ID ((ULONG)-1) + +// +// IOCTLs exposed by the driver. +// + +// #define TD_IOCTL_REGISTER_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 0), METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +// #define TD_IOCTL_UNREGISTER_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 1), METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +#define TD_IOCTL_PROTECT_NAME_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 2), METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +#define TD_IOCTL_UNPROTECT_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 3), METHOD_BUFFERED, FILE_SPECIAL_ACCESS) + + +#define TDProtectName_Protect 0 // name of programs to proect and filter out the desiredAccess on Process Open +#define TDProtectName_Reject 1 // name of programs to reject during ProcessCreate + +// +// Structures used by TD_IOCTL_PROTECTNAME +// + +typedef struct _TD_PROTECTNAME_INPUT { + ULONG Operation; + WCHAR Name[NAME_SIZE+1]; // what is the filename to protect - extra wchar for forced NULL +} +TD_PROTECTNAME_INPUT, *PTD_PROTECTNAME_INPUT; + +// +// Structures used by TD_IOCTL_UNPROTECT_CALLBACK +// + +typedef struct _TD_UNPROTECT_CALLBACK_INPUT { + ULONG UnusedParameter; +} +TD_UNPROTECT_CALLBACK_INPUT, *PTD_UNPROTECT_CALLBACK_INPUT; diff --git a/general/obcallback/driver/tdriver.c b/general/obcallback/driver/tdriver.c new file mode 100644 index 00000000..641635ee --- /dev/null +++ b/general/obcallback/driver/tdriver.c @@ -0,0 +1,532 @@ +/*++ + +Module Name: + + tdriver.c + +Abstract: + + Main module for the Ob and Ps sample code + +Notice: + Use this sample code at your own risk; there is no support from Microsoft for the sample code. + In addition, this sample code is licensed to you under the terms of the Microsoft Public License + (http://www.microsoft.com/opensource/licenses.mspx) + + +--*/ + +#include "pch.h" +#include "tdriver.h" + +// +// Process notify routines. +// + +BOOLEAN TdProcessNotifyRoutineSet2 = FALSE; + +// allow filter the requested access +BOOLEAN TdbProtectName = FALSE; +BOOLEAN TdbRejectName = FALSE; + +// +// Function declarations +// +DRIVER_INITIALIZE DriverEntry; + +_Dispatch_type_(IRP_MJ_CREATE) DRIVER_DISPATCH TdDeviceCreate; +_Dispatch_type_(IRP_MJ_CLOSE) DRIVER_DISPATCH TdDeviceClose; +_Dispatch_type_(IRP_MJ_CLEANUP) DRIVER_DISPATCH TdDeviceCleanup; +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH TdDeviceControl; + +DRIVER_UNLOAD TdDeviceUnload; + +VOID +TdCreateProcessNotifyRoutine2 ( + _Inout_ PEPROCESS Process, + _In_ HANDLE ProcessId, + _In_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + + if (CreateInfo != NULL) + { + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdCreateProcessNotifyRoutine2: process %p (ID 0x%p) created, creator %Ix:%Ix\n" + " command line %wZ\n" + " file name %wZ (FileOpenNameAvailable: %d)\n", + Process, + (PVOID)ProcessId, + (ULONG_PTR)CreateInfo->CreatingThreadId.UniqueProcess, + (ULONG_PTR)CreateInfo->CreatingThreadId.UniqueThread, + CreateInfo->CommandLine, + CreateInfo->ImageFileName, + CreateInfo->FileOpenNameAvailable + ); + + // Search for matching process to protect only if filtering + if (TdbProtectName) { + if (CreateInfo->CommandLine != NULL) + { + Status = TdCheckProcessMatch(CreateInfo->CommandLine, Process, ProcessId); + + if (Status == STATUS_SUCCESS) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: TdCreateProcessNotifyRoutine2: PROTECTING process %p (ID 0x%p)\n", + Process, + (PVOID)ProcessId + ); + } + } + + } + + // Search for matching process to reject process creation + if (TdbRejectName) { + if (CreateInfo->CommandLine != NULL) + { + Status = TdCheckProcessMatch(CreateInfo->CommandLine, Process, ProcessId); + + if (Status == STATUS_SUCCESS) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: TdCreateProcessNotifyRoutine2: REJECTING process %p (ID 0x%p)\n", + Process, + (PVOID)ProcessId + ); + + CreateInfo->CreationStatus = STATUS_ACCESS_DENIED; + } + } + + } + } + else + { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: TdCreateProcessNotifyRoutine2: process %p (ID 0x%p) destroyed\n", + Process, + (PVOID)ProcessId + ); + } +} + +// +// DriverEntry +// + +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath +) +{ + NTSTATUS Status; + UNICODE_STRING NtDeviceName = RTL_CONSTANT_STRING (TD_NT_DEVICE_NAME); + UNICODE_STRING DosDevicesLinkName = RTL_CONSTANT_STRING (TD_DOS_DEVICES_LINK_NAME); + PDEVICE_OBJECT Device = NULL; + BOOLEAN SymLinkCreated = FALSE; + USHORT CallbackVersion; + + UNREFERENCED_PARAMETER (RegistryPath); + + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "ObCallbackTest: DriverEntry: Driver loaded. Use ed nt!Kd_IHVDRIVER_Mask f (or 7) to enable more traces\n"); + + CallbackVersion = ObGetFilterVersion(); + + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "ObCallbackTest: DriverEntry: Callback version 0x%hx\n", CallbackVersion); + + // + // Initialize globals. + // + + KeInitializeGuardedMutex (&TdCallbacksMutex); + + // + // Create our device object. + // + + Status = IoCreateDevice ( + DriverObject, // pointer to driver object + 0, // device extension size + &NtDeviceName, // device name + FILE_DEVICE_UNKNOWN, // device type + 0, // device characteristics + FALSE, // not exclusive + &Device); // returned device object pointer + + if (! NT_SUCCESS(Status)) + { + goto Exit; + } + + TD_ASSERT (Device == DriverObject->DeviceObject); + + // + // Set dispatch routines. + // + + DriverObject->MajorFunction[IRP_MJ_CREATE] = TdDeviceCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = TdDeviceClose; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TdDeviceCleanup; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TdDeviceControl; + DriverObject->DriverUnload = TdDeviceUnload; + + // + // Create a link in the Win32 namespace. + // + + Status = IoCreateSymbolicLink (&DosDevicesLinkName, &NtDeviceName); + + if (! NT_SUCCESS(Status)) + { + goto Exit; + } + + SymLinkCreated = TRUE; + + // + // Set process create routines. + // + + Status = PsSetCreateProcessNotifyRoutineEx ( + TdCreateProcessNotifyRoutine2, + FALSE + ); + + if (! NT_SUCCESS(Status)) + { + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "ObCallbackTest: DriverEntry: PsSetCreateProcessNotifyRoutineEx(2) returned 0x%x\n", Status); + goto Exit; + } + + TdProcessNotifyRoutineSet2 = TRUE; + +Exit: + + if (!NT_SUCCESS (Status)) + { + if (TdProcessNotifyRoutineSet2 == TRUE) + { + Status = PsSetCreateProcessNotifyRoutineEx ( + TdCreateProcessNotifyRoutine2, + TRUE + ); + + TD_ASSERT (Status == STATUS_SUCCESS); + + TdProcessNotifyRoutineSet2 = FALSE; + } + + if (SymLinkCreated == TRUE) + { + IoDeleteSymbolicLink (&DosDevicesLinkName); + } + + if (Device != NULL) + { + IoDeleteDevice (Device); + } + } + + return Status; +} + +// +// Function: +// +// TdDeviceUnload +// +// Description: +// +// This function handles driver unloading. All this driver needs to do +// is to delete the device object and the symbolic link between our +// device name and the Win32 visible name. +// + +VOID +TdDeviceUnload ( + _In_ PDRIVER_OBJECT DriverObject +) +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING DosDevicesLinkName = RTL_CONSTANT_STRING (TD_DOS_DEVICES_LINK_NAME); + + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "ObCallbackTest: TdDeviceUnload\n"); + + // + // Unregister process notify routines. + // + + if (TdProcessNotifyRoutineSet2 == TRUE) + { + Status = PsSetCreateProcessNotifyRoutineEx ( + TdCreateProcessNotifyRoutine2, + TRUE + ); + + TD_ASSERT (Status == STATUS_SUCCESS); + + TdProcessNotifyRoutineSet2 = FALSE; + } + + // remove filtering and remove any OB callbacks + TdbProtectName = FALSE; + Status = TdDeleteProtectNameCallback(); + TD_ASSERT (Status == STATUS_SUCCESS); + + // + // Delete the link from our device name to a name in the Win32 namespace. + // + + Status = IoDeleteSymbolicLink (&DosDevicesLinkName); + if (Status != STATUS_INSUFFICIENT_RESOURCES) { + // + // IoDeleteSymbolicLink can fail with STATUS_INSUFFICIENT_RESOURCES. + // + + TD_ASSERT (NT_SUCCESS (Status)); + + } + + + // + // Delete our device object. + // + + IoDeleteDevice (DriverObject->DeviceObject); +} + +// +// Function: +// +// TdDeviceCreate +// +// Description: +// +// This function handles the 'create' irp. +// + + +NTSTATUS +TdDeviceCreate ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + UNREFERENCED_PARAMETER (DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + +// +// Function: +// +// TdDeviceClose +// +// Description: +// +// This function handles the 'close' irp. +// + +NTSTATUS +TdDeviceClose ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + UNREFERENCED_PARAMETER (DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + +// +// Function: +// +// TdDeviceCleanup +// +// Description: +// +// This function handles the 'cleanup' irp. +// + +NTSTATUS +TdDeviceCleanup ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + UNREFERENCED_PARAMETER (DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + +// +// TdControlProtectName +// + +NTSTATUS TdControlProtectName ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION IrpStack = NULL; + ULONG InputBufferLength = 0; + PTD_PROTECTNAME_INPUT pProtectNameInput = NULL; + + UNREFERENCED_PARAMETER (DeviceObject); + + + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdControlProtectName: Entering\n"); + + IrpStack = IoGetCurrentIrpStackLocation (Irp); + InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; + + if (InputBufferLength < sizeof (TD_PROTECTNAME_INPUT)) + { + Status = STATUS_BUFFER_OVERFLOW; + goto Exit; + } + + pProtectNameInput = (PTD_PROTECTNAME_INPUT)Irp->AssociatedIrp.SystemBuffer; + + Status = TdProtectNameCallback (pProtectNameInput); + + switch (pProtectNameInput->Operation) { + case TDProtectName_Protect: + // Begin filtering access rights + TdbProtectName = TRUE; + TdbRejectName = FALSE; + break; + + case TDProtectName_Reject: + // Begin reject process creation on match + TdbProtectName = FALSE; + TdbRejectName = TRUE; + break; + } + + +Exit: + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TD_IOCTL_PROTECTNAME: Status %x\n", Status); + + return Status; +} + +// +// TdControlUnprotect +// + +NTSTATUS TdControlUnprotect ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + NTSTATUS Status = STATUS_SUCCESS; + // PIO_STACK_LOCATION IrpStack = NULL; + // ULONG InputBufferLength = 0; + + UNREFERENCED_PARAMETER (DeviceObject); + UNREFERENCED_PARAMETER (Irp); + + // IrpStack = IoGetCurrentIrpStackLocation (Irp); + // InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; + + // No need to check length of passed in parameters as we do not need any information from that + + // do not filter requested access + Status = TdDeleteProtectNameCallback(); + if (Status != STATUS_SUCCESS) { + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TdDeleteProtectNameCallback: status 0x%x\n", Status); + } + TdbProtectName = FALSE; + TdbRejectName = FALSE; + +//Exit: + DbgPrintEx ( + DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, + "ObCallbackTest: TD_IOCTL_UNPROTECT: exiting - status 0x%x\n", Status); + + return Status; +} + + +// +// Function: +// +// TdDeviceControl +// +// Description: +// +// This function handles 'control' irp. +// + +NTSTATUS +TdDeviceControl ( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp +) +{ + PIO_STACK_LOCATION IrpStack; + ULONG Ioctl; + NTSTATUS Status; + + UNREFERENCED_PARAMETER (DeviceObject); + + + Status = STATUS_SUCCESS; + + IrpStack = IoGetCurrentIrpStackLocation (Irp); + Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode; + + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "TdDeviceControl: entering - ioctl code 0x%x\n", Ioctl); + + switch (Ioctl) + { + case TD_IOCTL_PROTECT_NAME_CALLBACK: + + Status = TdControlProtectName (DeviceObject, Irp); + break; + + case TD_IOCTL_UNPROTECT_CALLBACK: + + Status = TdControlUnprotect (DeviceObject, Irp); + break; + + + default: + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "TdDeviceControl: unrecognized ioctl code 0x%x\n", Ioctl); + break; + } + + // + // Complete the irp and return. + // + + Irp->IoStatus.Status = Status; + IoCompleteRequest (Irp, IO_NO_INCREMENT); + + DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_TRACE_LEVEL, "TdDeviceControl leaving - status 0x%x\n", Status); + return Status; +} diff --git a/general/obcallback/driver/tdriver.h b/general/obcallback/driver/tdriver.h new file mode 100644 index 00000000..b7dedd02 --- /dev/null +++ b/general/obcallback/driver/tdriver.h @@ -0,0 +1,125 @@ +/*++ + +Module Name: + + tdriver.h + +Abstract: + + This module declarations for the Ob/Ps callback test driver. + + +// Notice: +// +// Use this sample code at your own risk; there is no support from Microsoft for the sample code. +// In addition, this sample code is licensed to you under the terms of the Microsoft Public License +// (http://www.microsoft.com/opensource/licenses.mspx) + +--*/ + +#pragma once + +#include "shared.h" + +#define TD_CALLBACK_REGISTRATION_TAG '0bCO' // TD_CALLBACK_REGISTRATION structure. +#define TD_CALL_CONTEXT_TAG '1bCO' // TD_CALL_CONTEXT structure. + + +typedef struct _TD_CALLBACK_PARAMETERS { + ACCESS_MASK AccessBitsToClear; + ACCESS_MASK AccessBitsToSet; +} +TD_CALLBACK_PARAMETERS, *PTD_CALLBACK_PARAMETERS; + +// +// TD_CALLBACK_REGISTRATION +// + +typedef struct _TD_CALLBACK_REGISTRATION { + + // + // Handle returned by ObRegisterCallbacks. + // + + PVOID RegistrationHandle; + + // + // If not NULL, filter only requests to open/duplicate handles to this + // process (or one of its threads). + // + + PVOID TargetProcess; + HANDLE TargetProcessId; + + + // + // Currently each TD_CALLBACK_REGISTRATION has at most one process and one + // thread callback. That is, we can't register more than one callback for + // the same object type with a single ObRegisterCallbacks call. + // + + TD_CALLBACK_PARAMETERS ProcessParams; + TD_CALLBACK_PARAMETERS ThreadParams; + + ULONG RegistrationId; // Index in the global TdCallbacks array. + +} +TD_CALLBACK_REGISTRATION, *PTD_CALLBACK_REGISTRATION; + +// +// TD_CALL_CONTEXT +// + +typedef struct _TD_CALL_CONTEXT +{ + PTD_CALLBACK_REGISTRATION CallbackRegistration; + + OB_OPERATION Operation; + PVOID Object; + POBJECT_TYPE ObjectType; +} +TD_CALL_CONTEXT, *PTD_CALL_CONTEXT; + +extern KGUARDED_MUTEX TdCallbacksMutex; + +NTSTATUS TdDeleteCallback ( + _In_ ULONG RegistrationId +); + +// delete the process/thead OB callbacks +NTSTATUS TdDeleteProtectNameCallback (); + + + +NTSTATUS TdProtectNameCallback( + _In_ PTD_PROTECTNAME_INPUT pProtectName +); + +NTSTATUS TdCheckProcessMatch ( + _In_ PCUNICODE_STRING pustrCommand, + _In_ PEPROCESS Process, + _In_ HANDLE ProcessId +); + +OB_PREOP_CALLBACK_STATUS +CBTdPreOperationCallback ( + _In_ PVOID RegistrationContext, + _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo +); + +VOID +CBTdPostOperationCallback ( + _In_ PVOID RegistrationContext, + _In_ POB_POST_OPERATION_INFORMATION PostInfo +); + +VOID TdSetCallContext ( + _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo, + _In_ PTD_CALLBACK_REGISTRATION CallbackRegistration +); + +VOID TdCheckAndFreeCallContext ( + _Inout_ POB_POST_OPERATION_INFORMATION PostInfo, + _In_ PTD_CALLBACK_REGISTRATION CallbackRegistration +); + diff --git a/general/obcallback/driver/util.c b/general/obcallback/driver/util.c new file mode 100644 index 00000000..c00e96a3 --- /dev/null +++ b/general/obcallback/driver/util.c @@ -0,0 +1,73 @@ +/*++ + +Module Name: + + util.c + +Notice: + Use this sample code at your own risk; there is no support from Microsoft for the sample code. + In addition, this sample code is licensed to you under the terms of the Microsoft Public License + (http://www.microsoft.com/opensource/licenses.mspx) + + +--*/ + +#include "pch.h" +#include "tdriver.h" + +// +// TdSetCallContext +// +// Creates a call context object and stores a pointer to it +// in the supplied OB_PRE_OPERATION_INFORMATION structure. +// +// This function is called from a pre-notification. The created call context +// object then has to be freed in a corresponding post-notification using +// TdCheckAndFreeCallContext. +// + +void TdSetCallContext ( + _Inout_ POB_PRE_OPERATION_INFORMATION PreInfo, + _In_ PTD_CALLBACK_REGISTRATION CallbackRegistration +) +{ + PTD_CALL_CONTEXT CallContext; + + CallContext = (PTD_CALL_CONTEXT) ExAllocatePoolWithTag ( + PagedPool, sizeof(TD_CALL_CONTEXT), TD_CALL_CONTEXT_TAG + ); + + if (CallContext == NULL) + { + return; + } + + RtlZeroMemory (CallContext, sizeof(TD_CALL_CONTEXT)); + + CallContext->CallbackRegistration = CallbackRegistration; + CallContext->Operation = PreInfo->Operation; + CallContext->Object = PreInfo->Object; + CallContext->ObjectType = PreInfo->ObjectType; + + PreInfo->CallContext = CallContext; +} + +void TdCheckAndFreeCallContext ( + _Inout_ POB_POST_OPERATION_INFORMATION PostInfo, + _In_ PTD_CALLBACK_REGISTRATION CallbackRegistration +) +{ + PTD_CALL_CONTEXT CallContext = (PTD_CALL_CONTEXT)PostInfo->CallContext; + + if (CallContext != NULL) + { + TD_ASSERT (CallContext->CallbackRegistration == CallbackRegistration); + + TD_ASSERT (CallContext->Operation == PostInfo->Operation); + TD_ASSERT (CallContext->Object == PostInfo->Object); + TD_ASSERT (CallContext->ObjectType == PostInfo->ObjectType); + + ExFreePoolWithTag (CallContext, TD_CALL_CONTEXT_TAG); + } +} + diff --git a/general/obcallback/obcallback.sln b/general/obcallback/obcallback.sln new file mode 100644 index 00000000..ed5a27b9 --- /dev/null +++ b/general/obcallback/obcallback.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Control", "Control", "{D429EFC9-09E8-495C-81B0-32340C75C2BA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Driver", "Driver", "{5DA38202-119A-41F8-B5A6-CB8D38191147}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTestCtrl", "control\ObCallbackTestCtrl.vcxproj", "{8B053BEE-EA21-4D12-984B-6C93FE6D4992}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ObCallbackTest", "driver\ObCallbackTest.vcxproj", "{C696D115-0970-4E9C-8FED-31A99E039ED5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|Win32.ActiveCfg = Debug|Win32 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|Win32.Build.0 = Debug|Win32 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|Win32.ActiveCfg = Release|Win32 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|Win32.Build.0 = Release|Win32 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|x64.ActiveCfg = Debug|x64 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Debug|x64.Build.0 = Debug|x64 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|x64.ActiveCfg = Release|x64 + {8B053BEE-EA21-4D12-984B-6C93FE6D4992}.Release|x64.Build.0 = Release|x64 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|Win32.ActiveCfg = Debug|Win32 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|Win32.Build.0 = Debug|Win32 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|Win32.ActiveCfg = Release|Win32 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|Win32.Build.0 = Release|Win32 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|x64.ActiveCfg = Debug|x64 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Debug|x64.Build.0 = Debug|x64 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|x64.ActiveCfg = Release|x64 + {C696D115-0970-4E9C-8FED-31A99E039ED5}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {8B053BEE-EA21-4D12-984B-6C93FE6D4992} = {D429EFC9-09E8-495C-81B0-32340C75C2BA} + {C696D115-0970-4E9C-8FED-31A99E039ED5} = {5DA38202-119A-41F8-B5A6-CB8D38191147} + EndGlobalSection +EndGlobal diff --git a/general/pcidrv/ReadMe.md b/general/pcidrv/ReadMe.md new file mode 100644 index 00000000..72898b5b --- /dev/null +++ b/general/pcidrv/ReadMe.md @@ -0,0 +1,186 @@ +PCIDRV - WDF Driver for PCI Device +================================== + +This sample demonstrates how to write a KMDF driver for a PCI device. The sample works with the Intel 82557/82558 based PCI Ethernet Adapter (10/100) and Intel compatibles. + +This adapter supports scatter-gather DMA, wake on external event (Wait-Wake), and idle power down. The hardware specification is publicly available, and the source code to interface with the hardware is included in the WDK. + + +Overview +-------- + +The following is a list of key KMDF interfaces demonstrated in this sample: + +- Handling PnP & Power Events + +- Registering Device Interface + +- Hardware resource mapping: Port, Memory & Interrupt + +- DMA Interfaces + +- Parallel default queue for write requests. If the write cannot be satisfied immediately, the request is put into a manual parallel queue. + +- Parallel manual queue for Read requests + +- Parallelc default queue for IOCTL requests. If the ioctl cannot be satisfied immediately, the request is put into a manual parallel queue. + +- Request cancelation + +- Handling Interrupt & DPC + +- Watchdog Timer DPC to monitor the device state. + +- Event Tracing & HEXDUMP + +- Reading & Writing to the registry + +Note: This sample provides an example of a minimal driver intended for educational purposes. Neither the driver nor its sample test programs are intended for use in a production environment. + +As stated earlier, this sample is meant to demonstrate how to write a KMDF driver for a generic PCI device and not for PCI network controllers. For network controllers, you should write a monolithic NDIS miniport driver based on the samples given under the src\\network\\ndis directory. + +Note that it is still possible to use a subset of KMDF APIs when writing a NDIS miniport (see src\\network\\ndis\\usbnwifi directory for a sample on how to use KMDF interfaces to talk to USB device in an NDIS miniport). + +The sample driver has been tested on the following Intel Ethernet controllers: + +<table> +<colgroup> +<col width="50%" /> +<col width="50%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">Device Desc +Hardware ID</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left"><p>IBM Netfinity 10/100 Ethernet Adapter</p> +<p>PCI\VEN_8086&DEV_1229&SUBSYS_005C1014&REV_05</p></td> +<td align="left"><p>Intel(R) PRO/100+ Management Adapter with Alert On LAN</p> +<p>PCI\VEN_8086&DEV_1229&SUBSYS_000E8086&REV_08</p></td> +</tr> +</tbody> +</table> + +Using this sample as a standalone driver +---------------------------------------- + +``` {.syntax xml:space="preserve"} + --------------------- + | | + | MYPING | <-- Usermode test application + | | + --------------------- + ^ + | UserMode +------------------------------------------------------------------- + | KernelMode + V + --------------------- + | | + | PCIDRV | <-- Installed as a function driver + | | + --------------------- + ^ + | <-----Talk to the hardware using I/O resources + V + --------------- + | H/W NIC | + --------------- + ||||||| + ------- +``` + +You can install the driver as a standalone driver of a custom setup class, called Sample Class using GENPCI.INF. The PCI device is not seen as a network controller and as a result no protocol driver is bound to the device. In order to test the read & write path of the driver, you can use the specially developed ping application, called MYPING. This test application crafts the entire Ethernet frame in usermode and sends it to the driver to be transferred on the wire. In this configuration, you can only ping another machine on the same subnet. The application does all the ARP and AARP resolution in the usermode to get the MAC address of the target machine and sends ICMP ECHO requests. + +The PCIDRV sample acts as a power policy owner of the device and implements all the wait-wake and idle detection logic. + +INSTALLATION +------------ + +The driver can be installed as a Net class driver or as a standalone driver (user defined class). The KMDF versions of the INF files are dynamically generated from .INX file. In addition to the driver files, you have to include the WDF coinstaller DLL from the src\\redist\\wdf folder of the WDK. + +You can obtain redistributable framework updates by downloading the *wdfcoinstaller.msi* package from [WDK 8 Redistributable Components](http://go.microsoft.com/fwlink/p/?LinkID=226396). This package performs a silent install into the directory of your Windows Driver Kit (WDK) installation. You will see no confirmation that the installation has completed. You can verify that the redistributables have been installed on top of the WDK by ensuring there is a redist\\wdf directory under the root directory of the WDK, %ProgramFiles(x86)%\\Windows Kits\\8.0. + +### TESTING + +To test standalone driver configuration: You should use the specially developed ping application, called MYPING that comes with the sample. The Ping.exe provided in the system will not work because in this configuration, the test card is not bound to any network protocol - it's not seen as Net device by the system. Currently the test application doesn't have ability to get an IP address from a network DHCP server. As a result, it is better to connect the network device to a private hub and ping another machine connected to that hub. For example, let us say you have a test machine A and another machine B (development box). + +- Connect machine A and Machine B to a local hub. + +- Assign a static IP address, say 128.0.0.1 to the NIC on machine B. + +- Clear the ARP table on machine B by running **Arp -d** on the command line + +- Now run Myping.exe. This application enumerates GUID\_DEVINTERFACE\_PCIDRV and displays the name of the devices with an index number. This number will be used in identifying the interface when you invoke ping dialog. + +- In the ping dialog specify the following and click okay: + +- Device Index: 1 \<- number displayed in the list window + +- Source Ip Address: 128.0.0.4 \<- You can make up any valid IP address for test Machine A + +- Destination IP Address: 128.0.0.1 \<- IP address of machine B + +- Packet Size: 1428 \<- Default max size of ping payload. Minimum value is 32 bytes. + +If the machine B has more than one adapter and if the second adapter is connected to the internet (Corporate Network), instead of assigning static IP address to the adapter that's connected to the test machine, you can install Internet Connection Sharing (ICS) on it and get an IP address for ICS. This would let you use the test machine to browse the internet when the sample is installed in the miniport configuration and also in the standalone mode without making up or stealing somebody's IP address. For example, let us say the machine B has two adapters NIC1 and NIC2. NIC1 is connected to the CorpNet and NIC2 is connected to the private hub. Install ICS on NIC2 as described below: + +- Select the NIC2 in the Network Connections Applet. + +- Click the **Properties** button. + +- Go to the Advanced Tab and Check the box "Allow Other network users to connect through this computers internet connection" in the Internet Connection Sharing choice. + +- This will assign 192.168.0.1 IP address to NIC2. + +- Now on machine B, you can assume 192.168.0.2 as the local IP address and run Myping.exe . Or, you can install the sample in the miniport configuration and browse the internet. + +Other menu options of myping applications are: + +- Reenumerate All Device: This command lets you terminate active ping threads and close handle to all the device and reenumerate the devices again and display their names with index numbers. This might cause the devices to have new index numbers. + +- Cleanup: This command terminates ping threads and closes handles to all the devices. + +- Clear Display: Clears the window. + +- Verbose: Let you get more debug messages. + +- Exit: Terminate the application. + +**Note** You can use this application only on a device installed in the standalone configuration. If you run it on a device that's installed as a miniport, you will get an error message. For such devices, you can use the system provided ping.exe. + +RESOURCES +--------- + +For the latest release of the Windows Driver Kit, see http://www.microsoft.com/whdc/. + +If you have questions on using or adapting this sample for your project, you can either contact Microsoft Technical Support or post your questions in the Microsoft driver development newsgroup. + +FILE MANIFEST +------------- + +<table> +<colgroup> +<col width="50%" /> +<col width="50%" /> +</colgroup> +<thead> +<tr class="header"> +<th align="left">File +Description</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td align="left"><p>KMDF</p> +<p>Contains the driver.</p></td> +<td align="left"><p>KMDF\HW</p> +<p>Contains hardware specific code.</p></td> +</tr> +</tbody> +</table> + + diff --git a/general/pcidrv/kmdf/HW/PCIDRV.vcxproj b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj new file mode 100644 index 00000000..ca2cff13 --- /dev/null +++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj @@ -0,0 +1,360 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{2221261F-E1E2-4562-A15D-2EF8BF7D878E}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{EAA7F2DD-6EAB-48CE-80E1-46A17BF21F72}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>KMDF</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="..\pcidrv.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="..\wmi.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="nic_init.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="eeprom.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="nic_recv.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="nic_send.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="routines.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="physet.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="nic_req.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="nic_pm.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="isrdpc.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <Inf Include="..\genpci.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\genpci.inf</CopyOutput> + </Inf> + <MofComp Include="..\pcidrv.mof"> + <CreateBinaryMofFile>".\$(IntDir)\pcidrv.bmf"</CreateBinaryMofFile> + </MofComp> + <OtherWpp Include="..\pcidrv.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>TraceEvents(LEVEL,FLAGS,MSG,...);Hexdump((LEVEL,FLAGS,MSG,...))</WppTraceFunction> + <WppGenerateUsingTemplateFile>{km-WdfDefault.tpl}*.tmh</WppGenerateUsingTemplateFile> + </OtherWpp> + <Wmimofck Include=".\$(IntDir)\pcidrv.bmf" /> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>PCIDRV</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>PCIDRV</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>PCIDRV</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>PCIDRV</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntstrsafe.lib</AdditionalDependencies> + </Link> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_WIN2K_COMPAT_SLIST_USAGE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);EVENT_TRACING</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="..\pcidrv.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters new file mode 100644 index 00000000..a15b9d16 --- /dev/null +++ b/general/pcidrv/kmdf/HW/PCIDRV.vcxproj.Filters @@ -0,0 +1,75 @@ +<?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>{8FC125AF-15BD-4DCD-9D5E-C7FE9A6ACD75}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{938C7F7B-13A2-43D1-A1CF-4B02B581687C}</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>{75E794A5-28E0-464A-A171-8AD7F2A1DEAA}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{EDAC3101-0378-4793-BEA6-FC4E036C130B}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="..\pcidrv.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="..\wmi.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="eeprom.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="isrdpc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nic_init.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nic_pm.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nic_recv.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nic_req.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="nic_send.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="physet.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="precompsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="routines.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\genpci.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="..\genpci.inx"> + <Filter>Driver Files</Filter> + </Inf> + <MofComp Include="..\pcidrv.mof"> + <Filter>Driver Files</Filter> + </MofComp> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="..\pcidrv.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/pcidrv/kmdf/HW/e100_557.h b/general/pcidrv/kmdf/HW/e100_557.h new file mode 100644 index 00000000..fb4075df --- /dev/null +++ b/general/pcidrv/kmdf/HW/e100_557.h @@ -0,0 +1,789 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + e100_557.h (82557.h) + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +#ifndef _E100_557_H +#define _E100_557_H + +//------------------------------------------------------------------------- +// D100 Stepping Defines +//------------------------------------------------------------------------- +#define D100_A_STEP 0 // NEVER SHIPPED +#define D100_B_STEP 1 // d100 first shipped silicon +#define D100_C_STEP 2 // d100' (c-step) with vendor/id and hw fix +#define D101_A_STEP 4 // first silicon of d101 + +//------------------------------------------------------------------------- +// E100 Stepping Defines - used in PoMgmt Decisions +//------------------------------------------------------------------------- +#define E100_82557_A_STEP 1 +#define E100_82557_B_STEP 2 +#define E100_82557_C_STEP 3 +#define E100_82558_A_STEP 4 +#define E100_82558_B_STEP 5 +#define E100_82559_A_STEP 6 +#define E100_82559_B_STEP 7 +#define E100_82559_C_STEP 8 +#define E100_82559ER_A_STEP 9 + +//------------------------------------------------------------------------- +// D100 PORT functions -- lower 4 bits +//------------------------------------------------------------------------- +#define PORT_SOFTWARE_RESET 0 +#define PORT_SELFTEST 1 +#define PORT_SELECTIVE_RESET 2 +#define PORT_DUMP 3 + + +//------------------------------------------------------------------------- +// CSR field definitions -- Offsets from CSR base +//------------------------------------------------------------------------- +#define SCB_STATUS_LOW_BYTE 0x0 +#define SCB_STATUS_HIGH_BYTE 0x1 +#define SCB_COMMAND_LOW_BYTE 0x2 +#define SCB_COMMAND_HIGH_BYTE 0x3 +#define SCB_GENERAL_POINTER 0x4 +#define CSR_PORT_LOW_WORD 0x8 +#define CSR_PORT_HIGH_WORD 0x0a +#define CSR_FLASH_CONTROL_REG 0x0c +#define CSR_EEPROM_CONTROL_REG 0x0e +#define CSR_MDI_CONTROL_LOW_WORD 0x10 +#define CSR_MDI_CONTROL_HIGH_WORD 0x12 + + +//------------------------------------------------------------------------- +// SCB Status Word bit definitions +//------------------------------------------------------------------------- +//- Interrupt status fields +#define SCB_STATUS_MASK BIT_12_15 // ACK Mask +#define SCB_STATUS_CX BIT_15 // CU Completed Action Cmd +#define SCB_STATUS_FR BIT_14 // RU Received A Frame +#define SCB_STATUS_CNA BIT_13 // CU Became Inactive (IDLE) +#define SCB_STATUS_RNR BIT_12 // RU Became Not Ready +#define SCB_STATUS_MDI BIT_11 // MDI read or write done +#define SCB_STATUS_SWI BIT_10 // Software generated interrupt + +//- Interrupt ACK fields +#define SCB_ACK_MASK (BIT_9 | BIT_12_15 | BIT_8) // ACK Mask +#define SCB_ALL_INTERRUPT_BITS BIT_8_15 // if all the bits are set, no interrupt to be served +#define SCB_ACK_CX BIT_15 // CU Completed Action Cmd +#define SCB_ACK_FR BIT_14 // RU Received A Frame +#define SCB_ACK_CNA BIT_13 // CU Became Inactive (IDLE) +#define SCB_ACK_RNR BIT_12 // RU Became Not Ready +#define SCB_ACK_MDI BIT_11 // MDI read or write done +#define SCB_ACK_SWI BIT_10 // Software generated interrupt +#define SCB_ACK_ER BIT_9 // Early Receive interrupt +#define SCB_ACK_FCP BIT_8 // Flow Control Pause interrupt + +//- CUS Fields +#define SCB_CUS_MASK (BIT_6 | BIT_7) // CUS 2-bit Mask +#define SCB_CUS_IDLE 0 // CU Idle +#define SCB_CUS_SUSPEND BIT_6 // CU Suspended +#define SCB_CUS_ACTIVE BIT_7 // CU Active + +//- RUS Fields +#define SCB_RUS_IDLE 0 // RU Idle +#define SCB_RUS_MASK BIT_2_5 // RUS 3-bit Mask +#define SCB_RUS_SUSPEND BIT_2 // RU Suspended +#define SCB_RUS_NO_RESOURCES BIT_3 // RU Out Of Resources +#define SCB_RUS_READY BIT_4 // RU Ready +#define SCB_RUS_SUSP_NO_RBDS (BIT_2 | BIT_5) // RU No More RBDs +#define SCB_RUS_NO_RBDS (BIT_3 | BIT_5) // RU No More RBDs +#define SCB_RUS_READY_NO_RBDS (BIT_4 | BIT_5) // RU Ready, No RBDs + + +//------------------------------------------------------------------------- +// SCB Command Word bit definitions +//------------------------------------------------------------------------- +//- CUC fields +#define SCB_CUC_MASK BIT_4_6 // CUC 3-bit Mask +#define SCB_CUC_START BIT_4 // CU Start +#define SCB_CUC_RESUME BIT_5 // CU Resume +#define SCB_CUC_DUMP_ADDR BIT_6 // CU Dump Counters Address +#define SCB_CUC_DUMP_STAT (BIT_4 | BIT_6) // CU Dump statistics counters +#define SCB_CUC_LOAD_BASE (BIT_5 | BIT_6) // Load the CU base +#define SCB_CUC_DUMP_RST_STAT BIT_4_6 // CU Dump and reset statistics counters +#define SCB_CUC_STATIC_RESUME (BIT_5 | BIT_7) // CU Static Resume + +//- RUC fields +#define SCB_RUC_MASK BIT_0_2 // RUC 3-bit Mask +#define SCB_RUC_START BIT_0 // RU Start +#define SCB_RUC_RESUME BIT_1 // RU Resume +#define SCB_RUC_ABORT BIT_2 // RU Abort +#define SCB_RUC_LOAD_HDS (BIT_0 | BIT_2) // Load RFD Header Data Size +#define SCB_RUC_LOAD_BASE (BIT_1 | BIT_2) // Load the RU base +#define SCB_RUC_RBD_RESUME BIT_0_2 // RBD resume + +// Interrupt fields (assuming byte addressing) +#define SCB_INT_MASK BIT_0 // Mask interrupts +#define SCB_SOFT_INT BIT_1 // Generate a software interrupt + + +//------------------------------------------------------------------------- +// EEPROM bit definitions +//------------------------------------------------------------------------- +//- EEPROM control register bits +#define EN_TRNF 0x10 // Enable turnoff +#define EEDO 0x08 // EEPROM data out +#define EEDI 0x04 // EEPROM data in (set for writing data) +#define EECS 0x02 // EEPROM chip select (1=high, 0=low) +#define EESK 0x01 // EEPROM shift clock (1=high, 0=low) + +//- EEPROM opcodes +#define EEPROM_READ_OPCODE 06 +#define EEPROM_WRITE_OPCODE 05 +#define EEPROM_ERASE_OPCODE 07 +#define EEPROM_EWEN_OPCODE 19 // Erase/write enable +#define EEPROM_EWDS_OPCODE 16 // Erase/write disable + +//- EEPROM data locations +#define EEPROM_NODE_ADDRESS_BYTE_0 0 +#define EEPROM_FLAGS_WORD_3 3 +#define EEPROM_FLAG_10MC BIT_0 +#define EEPROM_FLAG_100MC BIT_1 + +//------------------------------------------------------------------------- +// MDI Control register bit definitions +//------------------------------------------------------------------------- +#define MDI_DATA_MASK BIT_0_15 // MDI Data port +#define MDI_REG_ADDR BIT_16_20 // which MDI register to read/write +#define MDI_PHY_ADDR BIT_21_25 // which PHY to read/write +#define MDI_PHY_OPCODE BIT_26_27 // which PHY to read/write +#define MDI_PHY_READY BIT_28 // PHY is ready for another MDI cycle +#define MDI_PHY_INT_ENABLE BIT_29 // Assert INT at MDI cycle completion + + +//------------------------------------------------------------------------- +// MDI Control register opcode definitions +//------------------------------------------------------------------------- +#define MDI_WRITE 1 // Phy Write +#define MDI_READ 2 // Phy read + + +//------------------------------------------------------------------------- +// D100 Action Commands +//------------------------------------------------------------------------- +#define CB_NOP 0 +#define CB_IA_ADDRESS 1 +#define CB_CONFIGURE 2 +#define CB_MULTICAST 3 +#define CB_TRANSMIT 4 +#define CB_LOAD_MICROCODE 5 +#define CB_DUMP 6 +#define CB_DIAGNOSE 7 + + +//------------------------------------------------------------------------- +// Command Block (CB) Field Definitions +//------------------------------------------------------------------------- +//- CB Command Word +#define CB_EL_BIT BIT_15 // CB EL Bit +#define CB_S_BIT BIT_14 // CB Suspend Bit +#define CB_I_BIT BIT_13 // CB Interrupt Bit +#define CB_TX_SF_BIT BIT_3 // TX CB Flexible Mode +#define CB_CMD_MASK BIT_0_2 // CB 3-bit CMD Mask + +//- CB Status Word +#define CB_STATUS_MASK BIT_12_15 // CB Status Mask (4-bits) +#define CB_STATUS_COMPLETE BIT_15 // CB Complete Bit +#define CB_STATUS_OK BIT_13 // CB OK Bit +#define CB_STATUS_UNDERRUN BIT_12 // CB A Bit +#define CB_STATUS_FAIL BIT_11 // CB Fail (F) Bit + +//misc command bits +#define CB_TX_EOF_BIT BIT_15 // TX CB/TBD EOF Bit + +//------------------------------------------------------------------------- +// Config CB Parameter Fields +//------------------------------------------------------------------------- +#define CB_CFIG_BYTE_COUNT 22 // 22 config bytes +#define CB_SHORT_CFIG_BYTE_COUNT 8 // 8 config bytes + +// byte 0 bit definitions +#define CB_CFIG_BYTE_COUNT_MASK BIT_0_5 // Byte count occupies bit 5-0 + +// byte 1 bit definitions +#define CB_CFIG_RXFIFO_LIMIT_MASK BIT_0_4 // RxFifo limit mask +#define CB_CFIG_TXFIFO_LIMIT_MASK BIT_4_7 // TxFifo limit mask + +// byte 3 bit definitions -- +#define CB_CFIG_B3_MWI_ENABLE BIT_0 // Memory Write Invalidate Enable Bit + +// byte 4 bit definitions +#define CB_CFIG_RX_MIN_DMA_MASK BIT_0_6 // Rx minimum DMA count mask + +// byte 5 bit definitions +#define CB_CFIG_TX_MIN_DMA_MASK BIT_0_6 // Tx minimum DMA count mask +#define CB_CFIG_DMBC_EN BIT_7 // Enable Tx/Rx minimum DMA counts + +// byte 6 bit definitions +#define CB_CFIG_LATE_SCB BIT_0 // Update SCB After New Tx Start +#define CB_CFIG_TNO_INT BIT_2 // Tx Not OK Interrupt +#define CB_CFIG_CI_INT BIT_3 // Command Complete Interrupt +#define CB_CFIG_SAVE_BAD_FRAMES BIT_7 // Save Bad Frames Enabled + +// byte 7 bit definitions +#define CB_CFIG_DISC_SHORT_FRAMES BIT_0 // Discard Short Frames +#define CB_CFIG_URUN_RETRY BIT_1_2 // Underrun Retry Count + +// byte 8 bit definitions +#define CB_CFIG_503_MII BIT_0 // 503 vs. MII mode + +// byte 9 bit definitions -- pre-defined all zeros + +// byte 10 bit definitions +#define CB_CFIG_NO_SRCADR BIT_3 // No Source Address Insertion +#define CB_CFIG_PREAMBLE_LEN BIT_4_5 // Preamble Length +#define CB_CFIG_LOOPBACK_MODE BIT_6_7 // Loopback Mode + +// byte 11 bit definitions +#define CB_CFIG_LINEAR_PRIORITY BIT_0_2 // Linear Priority + +// byte 12 bit definitions +#define CB_CFIG_LINEAR_PRI_MODE BIT_0 // Linear Priority mode +#define CB_CFIG_IFS_MASK BIT_4_7 // CSMA level Interframe Spacing mask + +// byte 13 bit definitions -- pre-defined all zeros + +// byte 14 bit definitions -- pre-defined 0xf2 + +// byte 15 bit definitions +#define CB_CFIG_PROMISCUOUS BIT_0 // Promiscuous Mode Enable +#define CB_CFIG_BROADCAST_DIS BIT_1 // Broadcast Mode Disable +#define CB_CFIG_CRS_OR_CDT BIT_7 // CRS Or CDT + +// byte 16 bit definitions -- pre-defined all zeros + +// byte 17 bit definitions -- pre-defined 0x40 + +// byte 18 bit definitions +#define CB_CFIG_STRIPPING BIT_0 // Stripping Disabled +#define CB_CFIG_PADDING BIT_1 // Padding Disabled +#define CB_CFIG_CRC_IN_MEM BIT_2 // Transfer CRC To Memory + +// byte 19 bit definitions +#define CB_CFIG_FORCE_FDX BIT_6 // Force Full Duplex +#define CB_CFIG_FDX_ENABLE BIT_7 // Full Duplex Enabled + +// byte 20 bit definitions +#define CB_CFIG_MULTI_IA BIT_6 // Multiple IA Addr + +// byte 21 bit definitions +#define CB_CFIG_MULTICAST_ALL BIT_3 // Multicast All + + +//------------------------------------------------------------------------- +// Receive Frame Descriptor Fields +//------------------------------------------------------------------------- + +//- RFD Status Bits +#define RFD_RECEIVE_COLLISION BIT_0 // Collision detected on Receive +#define RFD_IA_MATCH BIT_1 // Indv Address Match Bit +#define RFD_RX_ERR BIT_4 // RX_ERR pin on Phy was set +#define RFD_FRAME_TOO_SHORT BIT_7 // Receive Frame Short +#define RFD_DMA_OVERRUN BIT_8 // Receive DMA Overrun +#define RFD_NO_RESOURCES BIT_9 // No Buffer Space +#define RFD_ALIGNMENT_ERROR BIT_10 // Alignment Error +#define RFD_CRC_ERROR BIT_11 // CRC Error +#define RFD_STATUS_OK BIT_13 // RFD OK Bit +#define RFD_STATUS_COMPLETE BIT_15 // RFD Complete Bit + +//- RFD Command Bits +#define RFD_EL_BIT BIT_15 // RFD EL Bit +#define RFD_S_BIT BIT_14 // RFD Suspend Bit +#define RFD_H_BIT BIT_4 // Header RFD Bit +#define RFD_SF_BIT BIT_3 // RFD Flexible Mode + +//- RFD misc bits +#define RFD_EOF_BIT BIT_15 // RFD End-Of-Frame Bit +#define RFD_F_BIT BIT_14 // RFD Buffer Fetch Bit +#define RFD_ACT_COUNT_MASK BIT_0_13 // RFD Actual Count Mask +#define RFD_HEADER_SIZE 0x10 // Size of RFD Header (16 bytes) + +//------------------------------------------------------------------------- +// Receive Buffer Descriptor Fields +//------------------------------------------------------------------------- +#define RBD_EOF_BIT BIT_15 // RBD End-Of-Frame Bit +#define RBD_F_BIT BIT_14 // RBD Buffer Fetch Bit +#define RBD_ACT_COUNT_MASK BIT_0_13 // RBD Actual Count Mask + +#define SIZE_FIELD_MASK BIT_0_13 // Size of the associated buffer +#define RBD_EL_BIT BIT_15 // RBD EL Bit + + +//------------------------------------------------------------------------- +// Size Of Dump Buffer +//------------------------------------------------------------------------- +#define DUMP_BUFFER_SIZE 600 // size of the dump buffer + + +//------------------------------------------------------------------------- +// Self Test Results +//------------------------------------------------------------------------- +#define CB_SELFTEST_FAIL_BIT BIT_12 +#define CB_SELFTEST_DIAG_BIT BIT_5 +#define CB_SELFTEST_REGISTER_BIT BIT_3 +#define CB_SELFTEST_ROM_BIT BIT_2 + +#define CB_SELFTEST_ERROR_MASK ( \ + CB_SELFTEST_FAIL_BIT | CB_SELFTEST_DIAG_BIT | \ + CB_SELFTEST_REGISTER_BIT | CB_SELFTEST_ROM_BIT) + + +//------------------------------------------------------------------------- +// Driver Configuration Default Parameters for the 557 +// Note: If the driver uses any defaults that are different from the chip's +// defaults, it will be noted below +//------------------------------------------------------------------------- +// Byte 0 (byte count) default +#define CB_557_CFIG_DEFAULT_PARM0 CB_CFIG_BYTE_COUNT + +// Byte 1 (fifo limits) default +#define DEFAULT_TX_FIFO_LIMIT 0x08 +#define DEFAULT_RX_FIFO_LIMIT 0x08 +#define CB_557_CFIG_DEFAULT_PARM1 0x88 + +// Byte 2 (IFS) default +#define CB_557_CFIG_DEFAULT_PARM2 0x00 + +// Byte 3 (reserved) default +#define CB_557_CFIG_DEFAULT_PARM3 0x00 + +// Byte 4 (Rx DMA min count) default +#define CB_557_CFIG_DEFAULT_PARM4 0x00 + +// Byte 5 (Tx DMA min count, DMA min count enable) default +#define CB_557_CFIG_DEFAULT_PARM5 0x00 + +// Byte 6 (Late SCB, TNO int, CI int, Save bad frames) default +#define CB_557_CFIG_DEFAULT_PARM6 0x32 + +// Byte 7 (Discard short frames, underrun retry) default +// note: disc short frames will be enabled +#define DEFAULT_UNDERRUN_RETRY 0x01 +#define CB_557_CFIG_DEFAULT_PARM7 0x01 + +// Byte 8 (MII or 503) default +// note: MII will be the default +#define CB_557_CFIG_DEFAULT_PARM8 0x01 + +// Byte 9 - Power management for 82558B, 82559 +#define CB_WAKE_ON_LINK_BYTE9 0x20 +#define CB_WAKE_ON_ARP_PKT_BYTE9 0x40 + +#define CB_557_CFIG_DEFAULT_PARM9 0 + +// Byte 10 (scr addr insertion, preamble, loopback) default +#define CB_557_CFIG_DEFAULT_PARM10 0x2e + +// Byte 11 (linear priority) default +#define CB_557_CFIG_DEFAULT_PARM11 0x00 + +// Byte 12 (IFS,linear priority mode) default +#define CB_557_CFIG_DEFAULT_PARM12 0x60 + +// Byte 13 (reserved) default +#define CB_557_CFIG_DEFAULT_PARM13 0x00 + +// Byte 14 (reserved) default +#define CB_557_CFIG_DEFAULT_PARM14 0xf2 + +// Byte 15 (promiscuous, broadcast, CRS/CDT) default +#define CB_557_CFIG_DEFAULT_PARM15 0xea + +// Byte 16 (reserved) default +#define CB_557_CFIG_DEFAULT_PARM16 0x00 + +// Byte 17 (reserved) default +#define CB_557_CFIG_DEFAULT_PARM17 0x40 + +// Byte 18 (Stripping, padding, Rcv CRC in mem) default +// note: padding will be enabled +#define CB_557_CFIG_DEFAULT_PARM18 0xf2 + +// Byte 19 (reserved) default +// note: full duplex is enabled if FDX# pin is 0 +#define CB_557_CFIG_DEFAULT_PARM19 0x80 + +// Byte 20 (multi-IA) default +#define CB_557_CFIG_DEFAULT_PARM20 0x3f + +// Byte 21 (multicast all) default +#define CB_557_CFIG_DEFAULT_PARM21 0x05 + + +#pragma pack(1) + +//------------------------------------------------------------------------- +// Ethernet Frame Structure +//------------------------------------------------------------------------- +//- Ethernet 6-byte Address +typedef struct _ETH_ADDRESS_STRUC { + UCHAR EthNodeAddress[ETHERNET_ADDRESS_LENGTH]; +} ETH_ADDRESS_STRUC, *PETH_ADDRESS_STRUC; + + +//- Ethernet 14-byte Header +typedef struct _ETH_HEADER_STRUC { + UCHAR Destination[ETHERNET_ADDRESS_LENGTH]; + UCHAR Source[ETHERNET_ADDRESS_LENGTH]; + USHORT TypeLength; +} ETH_HEADER_STRUC, *PETH_HEADER_STRUC; + + +//- Ethernet Buffer (Including Ethernet Header) for Transmits +typedef struct _ETH_TX_BUFFER_STRUC { + ETH_HEADER_STRUC TxMacHeader; + UCHAR TxBufferData[(TCB_BUFFER_SIZE - sizeof(ETH_HEADER_STRUC))]; +} ETH_TX_BUFFER_STRUC, *PETH_TX_BUFFER_STRUC; + +typedef struct _ETH_RX_BUFFER_STRUC { + ETH_HEADER_STRUC RxMacHeader; + UCHAR RxBufferData[(RCB_BUFFER_SIZE - sizeof(ETH_HEADER_STRUC))]; +} ETH_RX_BUFFER_STRUC, *PETH_RX_BUFFER_STRUC; + + + +//------------------------------------------------------------------------- +// 82557 Data Structures +//------------------------------------------------------------------------- + +//------------------------------------------------------------------------- +// Self test +//------------------------------------------------------------------------- +typedef struct _SELF_TEST_STRUC { + ULONG StSignature; // Self Test Signature + ULONG StResults; // Self Test Results +} SELF_TEST_STRUC, *PSELF_TEST_STRUC; + + +//------------------------------------------------------------------------- +// Control/Status Registers (CSR) +//------------------------------------------------------------------------- +typedef struct _CSR_STRUC { + USHORT ScbStatus; // SCB Status register + UCHAR ScbCommandLow; // SCB Command register (low byte) + UCHAR ScbCommandHigh; // SCB Command register (high byte) + ULONG ScbGeneralPointer; // SCB General pointer + ULONG Port; // PORT register + USHORT FlashControl; // Flash Control register + USHORT EepromControl; // EEPROM control register + ULONG MDIControl; // MDI Control Register + ULONG RxDMAByteCount; // Receive DMA Byte count register +} CSR_STRUC, *PCSR_STRUC; + +//------------------------------------------------------------------------- +// Error Counters +//------------------------------------------------------------------------- +typedef struct _ERR_COUNT_STRUC { + ULONG XmtGoodFrames; // Good frames transmitted + ULONG XmtMaxCollisions; // Fatal frames -- had max collisions + ULONG XmtLateCollisions; // Fatal frames -- had a late coll. + ULONG XmtUnderruns; // Transmit underruns (fatal or re-transmit) + ULONG XmtLostCRS; // Frames transmitted without CRS + ULONG XmtDeferred; // Deferred transmits + ULONG XmtSingleCollision; // Transmits that had 1 and only 1 coll. + ULONG XmtMultCollisions; // Transmits that had multiple coll. + ULONG XmtTotalCollisions; // Transmits that had 1+ collisions. + ULONG RcvGoodFrames; // Good frames received + ULONG RcvCrcErrors; // Aligned frames that had a CRC error + ULONG RcvAlignmentErrors; // Receives that had alignment errors + ULONG RcvResourceErrors; // Good frame dropped due to lack of resources + ULONG RcvOverrunErrors; // Overrun errors - bus was busy + ULONG RcvCdtErrors; // Received frames that encountered coll. + ULONG RcvShortFrames; // Received frames that were to short + ULONG CommandComplete; // A005h indicates cmd completion +} ERR_COUNT_STRUC, *PERR_COUNT_STRUC; + + +//------------------------------------------------------------------------- +// Command Block (CB) Generic Header Structure +//------------------------------------------------------------------------- +typedef struct _CB_HEADER_STRUC { + USHORT CbStatus; // Command Block Status + USHORT CbCommand; // Command Block Command + ULONG CbLinkPointer; // Link To Next CB +} CB_HEADER_STRUC, *PCB_HEADER_STRUC; + + +//------------------------------------------------------------------------- +// NOP Command Block (NOP_CB) +//------------------------------------------------------------------------- +typedef struct _NOP_CB_STRUC { + CB_HEADER_STRUC NopCBHeader; +} NOP_CB_STRUC, *PNOP_CB_STRUC; + + +//------------------------------------------------------------------------- +// Individual Address Command Block (IA_CB) +//------------------------------------------------------------------------- +typedef struct _IA_CB_STRUC { + CB_HEADER_STRUC IaCBHeader; + UCHAR IaAddress[ETHERNET_ADDRESS_LENGTH]; +} IA_CB_STRUC, *PIA_CB_STRUC; + + +//------------------------------------------------------------------------- +// Configure Command Block (CONFIG_CB) +//------------------------------------------------------------------------- +typedef struct _CONFIG_CB_STRUC { + CB_HEADER_STRUC ConfigCBHeader; + UCHAR ConfigBytes[CB_CFIG_BYTE_COUNT]; +} CONFIG_CB_STRUC, *PCONFIG_CB_STRUC; + + +//------------------------------------------------------------------------- +// MultiCast Command Block (MULTICAST_CB) +//------------------------------------------------------------------------- +typedef struct _MULTICAST_CB_STRUC { + CB_HEADER_STRUC McCBHeader; + USHORT McCount; // Number of multicast addresses + UCHAR McAddress[(ETHERNET_ADDRESS_LENGTH * MAX_MULTICAST_ADDRESSES)]; +} MULTICAST_CB_STRUC, *PMULTICAST_CB_STRUC; + +//------------------------------------------------------------------------- +// WakeUp Filter Command Block (FILTER_CB) +//------------------------------------------------------------------------- +typedef struct _FILTER_CB_STRUC { + CB_HEADER_STRUC FilterCBHeader; + ULONG Pattern[16]; +}FILTER_CB_STRUC , *PFILTER_CB_STRUC ; + +//------------------------------------------------------------------------- +// Dump Command Block (DUMP_CB) +//------------------------------------------------------------------------- +typedef struct _DUMP_CB_STRUC { + CB_HEADER_STRUC DumpCBHeader; + ULONG DumpAreaAddress; // Dump Buffer Area Address +} DUMP_CB_STRUC, *PDUMP_CB_STRUC; + + +//------------------------------------------------------------------------- +// Dump Area structure definition +//------------------------------------------------------------------------- +typedef struct _DUMP_AREA_STRUC { + UCHAR DumpBuffer[DUMP_BUFFER_SIZE]; +} DUMP_AREA_STRUC, *PDUMP_AREA_STRUC; + + +//------------------------------------------------------------------------- +// Diagnose Command Block (DIAGNOSE_CB) +//------------------------------------------------------------------------- +typedef struct _DIAGNOSE_CB_STRUC { + CB_HEADER_STRUC DiagCBHeader; +} DIAGNOSE_CB_STRUC, *PDIAGNOSE_CB_STRUC; + +//------------------------------------------------------------------------- +// Transmit Command Block (TxCB) +//------------------------------------------------------------------------- +typedef struct _GENERIC_TxCB { + CB_HEADER_STRUC TxCbHeader; + ULONG TxCbTbdPointer; // TBD address + USHORT TxCbCount; // Data Bytes In TCB past header + UCHAR TxCbThreshold; // TX Threshold for FIFO Extender + UCHAR TxCbTbdNumber; + ETH_TX_BUFFER_STRUC TxCbData; + ULONG pad0; + ULONG pad1; + ULONG pad2; + ULONG pad3; +} TXCB_STRUC, *PTXCB_STRUC; + +//------------------------------------------------------------------------- +// Transmit Buffer Descriptor (TBD) +//------------------------------------------------------------------------- +typedef struct _TBD_STRUC { + ULONG TbdBufferAddress; // Physical Transmit Buffer Address + unsigned TbdCount :14; + unsigned :1 ; // always 0 + unsigned EndOfList:1 ; // EL bit in Tbd + unsigned :16; // field that is always 0's in a TBD +} TBD_STRUC, *PTBD_STRUC; + + +//------------------------------------------------------------------------- +// Receive Frame Descriptor (RFD) +//------------------------------------------------------------------------- +typedef struct _RFD_STRUC { + CB_HEADER_STRUC RfdCbHeader; + ULONG RfdRbdPointer; // Receive Buffer Descriptor Addr + USHORT RfdActualCount; // Number Of Bytes Received + USHORT RfdSize; // Number Of Bytes In RFD + ETH_RX_BUFFER_STRUC RfdBuffer; // Data buffer in RFD +} RFD_STRUC, *PRFD_STRUC; + + +//------------------------------------------------------------------------- +// Receive Buffer Descriptor (RBD) +//------------------------------------------------------------------------- +typedef struct _RBD_STRUC { + USHORT RbdActualCount; // Number Of Bytes Received + USHORT RbdFiller; + ULONG RbdLinkAddress; // Link To Next RBD + ULONG RbdRcbAddress; // Receive Buffer Address + USHORT RbdSize; // Receive Buffer Size + USHORT RbdFiller1; +} RBD_STRUC, *PRBD_STRUC; + +#pragma pack() + +//------------------------------------------------------------------------- +// 82557 PCI Register Definitions +// Refer To The PCI Specification For Detailed Explanations +//------------------------------------------------------------------------- +//- Register Offsets +#define PCI_VENDOR_ID_REGISTER 0x00 // PCI Vendor ID Register +#define PCI_DEVICE_ID_REGISTER 0x02 // PCI Device ID Register +#define PCI_CONFIG_ID_REGISTER 0x00 // PCI Configuration ID Register +#define PCI_COMMAND_REGISTER 0x04 // PCI Command Register +#define PCI_STATUS_REGISTER 0x06 // PCI Status Register +#define PCI_REV_ID_REGISTER 0x08 // PCI Revision ID Register +#define PCI_CLASS_CODE_REGISTER 0x09 // PCI Class Code Register +#define PCI_CACHE_LINE_REGISTER 0x0C // PCI Cache Line Register +#define PCI_LATENCY_TIMER 0x0D // PCI Latency Timer Register +#define PCI_HEADER_TYPE 0x0E // PCI Header Type Register +#define PCI_BIST_REGISTER 0x0F // PCI Built-In SelfTest Register +#define PCI_BAR_0_REGISTER 0x10 // PCI Base Address Register 0 +#define PCI_BAR_1_REGISTER 0x14 // PCI Base Address Register 1 +#define PCI_BAR_2_REGISTER 0x18 // PCI Base Address Register 2 +#define PCI_BAR_3_REGISTER 0x1C // PCI Base Address Register 3 +#define PCI_BAR_4_REGISTER 0x20 // PCI Base Address Register 4 +#define PCI_BAR_5_REGISTER 0x24 // PCI Base Address Register 5 +#define PCI_SUBVENDOR_ID_REGISTER 0x2C // PCI SubVendor ID Register +#define PCI_SUBDEVICE_ID_REGISTER 0x2E // PCI SubDevice ID Register +#define PCI_EXPANSION_ROM 0x30 // PCI Expansion ROM Base Register +#define PCI_INTERRUPT_LINE 0x3C // PCI Interrupt Line Register +#define PCI_INTERRUPT_PIN 0x3D // PCI Interrupt Pin Register +#define PCI_MIN_GNT_REGISTER 0x3E // PCI Min-Gnt Register +#define PCI_MAX_LAT_REGISTER 0x3F // PCI Max_Lat Register +#define PCI_NODE_ADDR_REGISTER 0x40 // PCI Node Address Register + + +//------------------------------------------------------------------------- +// PHY 100 MDI Register/Bit Definitions +//------------------------------------------------------------------------- +// MDI register set +#define MDI_CONTROL_REG 0x00 // MDI control register +#define MDI_STATUS_REG 0x01 // MDI Status regiser +#define PHY_ID_REG_1 0x02 // Phy indentification reg (word 1) +#define PHY_ID_REG_2 0x03 // Phy indentification reg (word 2) +#define AUTO_NEG_ADVERTISE_REG 0x04 // Auto-negotiation advertisement +#define AUTO_NEG_LINK_PARTNER_REG 0x05 // Auto-negotiation link partner ability +#define AUTO_NEG_EXPANSION_REG 0x06 // Auto-negotiation expansion +#define AUTO_NEG_NEXT_PAGE_REG 0x07 // Auto-negotiation next page transmit +#define EXTENDED_REG_0 0x10 // Extended reg 0 (Phy 100 modes) +#define EXTENDED_REG_1 0x14 // Extended reg 1 (Phy 100 error indications) +#define NSC_CONG_CONTROL_REG 0x17 // National (TX) congestion control +#define NSC_SPEED_IND_REG 0x19 // National (TX) speed indication +#define PHY_EQUALIZER_REG 0x1A // Register for the Phy Equalizer values + +// MDI Control register bit definitions +#define MDI_CR_COLL_TEST_ENABLE BIT_7 // Collision test enable +#define MDI_CR_FULL_HALF BIT_8 // FDX =1, half duplex =0 +#define MDI_CR_RESTART_AUTO_NEG BIT_9 // Restart auto negotiation +#define MDI_CR_ISOLATE BIT_10 // Isolate PHY from MII +#define MDI_CR_POWER_DOWN BIT_11 // Power down +#define MDI_CR_AUTO_SELECT BIT_12 // Auto speed select enable +#define MDI_CR_10_100 BIT_13 // 0 = 10Mbs, 1 = 100Mbs +#define MDI_CR_LOOPBACK BIT_14 // 0 = normal, 1 = loopback +#define MDI_CR_RESET BIT_15 // 0 = normal, 1 = PHY reset + +// MDI Status register bit definitions +#define MDI_SR_EXT_REG_CAPABLE BIT_0 // Extended register capabilities +#define MDI_SR_JABBER_DETECT BIT_1 // Jabber detected +#define MDI_SR_LINK_STATUS BIT_2 // Link Status -- 1 = link +#define MDI_SR_AUTO_SELECT_CAPABLE BIT_3 // Auto speed select capable +#define MDI_SR_REMOTE_FAULT_DETECT BIT_4 // Remote fault detect +#define MDI_SR_AUTO_NEG_COMPLETE BIT_5 // Auto negotiation complete +#define MDI_SR_10T_HALF_DPX BIT_11 // 10BaseT Half Duplex capable +#define MDI_SR_10T_FULL_DPX BIT_12 // 10BaseT full duplex capable +#define MDI_SR_TX_HALF_DPX BIT_13 // TX Half Duplex capable +#define MDI_SR_TX_FULL_DPX BIT_14 // TX full duplex capable +#define MDI_SR_T4_CAPABLE BIT_15 // T4 capable + +// Auto-Negotiation advertisement register bit definitions +#define NWAY_AD_SELCTOR_FIELD BIT_0_4 // identifies supported protocol +#define NWAY_AD_ABILITY BIT_5_12 // technologies that are supported +#define NWAY_AD_10T_HALF_DPX BIT_5 // 10BaseT Half Duplex capable +#define NWAY_AD_10T_FULL_DPX BIT_6 // 10BaseT full duplex capable +#define NWAY_AD_TX_HALF_DPX BIT_7 // TX Half Duplex capable +#define NWAY_AD_TX_FULL_DPX BIT_8 // TX full duplex capable +#define NWAY_AD_T4_CAPABLE BIT_9 // T4 capable +#define NWAY_AD_REMOTE_FAULT BIT_13 // indicates local remote fault +#define NWAY_AD_RESERVED BIT_14 // reserved +#define NWAY_AD_NEXT_PAGE BIT_15 // Next page (not supported) + +// Auto-Negotiation link partner ability register bit definitions +#define NWAY_LP_SELCTOR_FIELD BIT_0_4 // identifies supported protocol +#define NWAY_LP_ABILITY BIT_5_9 // technologies that are supported +#define NWAY_LP_REMOTE_FAULT BIT_13 // indicates partner remote fault +#define NWAY_LP_ACKNOWLEDGE BIT_14 // acknowledge +#define NWAY_LP_NEXT_PAGE BIT_15 // Next page (not supported) + +// Auto-Negotiation expansion register bit definitions +#define NWAY_EX_LP_NWAY BIT_0 // link partner is NWAY +#define NWAY_EX_PAGE_RECEIVED BIT_1 // link code word received +#define NWAY_EX_NEXT_PAGE_ABLE BIT_2 // local is next page able +#define NWAY_EX_LP_NEXT_PAGE_ABLE BIT_3 // partner is next page able +#define NWAY_EX_PARALLEL_DET_FLT BIT_4 // parallel detection fault +#define NWAY_EX_RESERVED BIT_5_15 // reserved + + +// PHY 100 Extended Register 0 bit definitions +#define PHY_100_ER0_FDX_INDIC BIT_0 // 1 = FDX, 0 = half duplex +#define PHY_100_ER0_SPEED_INDIC BIT_1 // 1 = 100mbs, 0= 10mbs +#define PHY_100_ER0_WAKE_UP BIT_2 // Wake up DAC +#define PHY_100_ER0_RESERVED BIT_3_4 // Reserved +#define PHY_100_ER0_REV_CNTRL BIT_5_7 // Revsion control (A step = 000) +#define PHY_100_ER0_FORCE_FAIL BIT_8 // Force Fail is enabled +#define PHY_100_ER0_TEST BIT_9_13 // Revsion control (A step = 000) +#define PHY_100_ER0_LINKDIS BIT_14 // Link integrity test is disabled +#define PHY_100_ER0_JABDIS BIT_15 // Jabber function is disabled + + +// PHY 100 Extended Register 1 bit definitions +#define PHY_100_ER1_RESERVED BIT_0_8 // Reserved +#define PHY_100_ER1_CH2_DET_ERR BIT_9 // Channel 2 EOF detection error +#define PHY_100_ER1_MANCH_CODE_ERR BIT_10 // Manchester code error +#define PHY_100_ER1_EOP_ERR BIT_11 // EOP error +#define PHY_100_ER1_BAD_CODE_ERR BIT_12 // bad code error +#define PHY_100_ER1_INV_CODE_ERR BIT_13 // invalid code error +#define PHY_100_ER1_DC_BAL_ERR BIT_14 // DC balance error +#define PHY_100_ER1_PAIR_SKEW_ERR BIT_15 // Pair skew error + +// PHY TX Register/Bit definitions +#define PHY_TX_STATUS_CTRL_REG 0x10 +#define PHY_TX_POLARITY_MASK BIT_8 // register 10h bit 8 (the polarity bit) +#define PHY_TX_NORMAL_POLARITY 0 // register 10h bit 8 =0 (normal polarity) + +#define PHY_TX_SPECIAL_CTRL_REG 0x11 +#define AUTO_POLARITY_DISABLE BIT_4 // register 11h bit 4 (0=enable, 1=disable) + +#define PHY_TX_REG_18 0x18 // Error counter register +// National Semiconductor TX phy congestion control register bit definitions +#define NSC_TX_CONG_TXREADY BIT_10 // Makes TxReady an input +#define NSC_TX_CONG_ENABLE BIT_8 // Enables congestion control +#define NSC_TX_CONG_F_CONNECT BIT_5 // Enables congestion control + +// National Semiconductor TX phy speed indication register bit definitions +#define NSC_TX_SPD_INDC_SPEED BIT_6 // 0 = 100mb, 1=10mb + +#endif // _E100_557_H + diff --git a/general/pcidrv/kmdf/HW/e100_equ.h b/general/pcidrv/kmdf/HW/e100_equ.h new file mode 100644 index 00000000..c1e0bbde --- /dev/null +++ b/general/pcidrv/kmdf/HW/e100_equ.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + e100_equ.h (equates.h) + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +#ifndef _E100_EQU_H +#define _E100_EQU_H + +//------------------------------------------------------------------------- +// OEM Message Tags +//------------------------------------------------------------------------- +#define stringTag 0xFEFA // Length Byte After String +#define lStringTag 0xFEFB // Length Byte Before String +#define zStringTag 0xFEFC // Zero-Terminated String Tag +#define nStringTag 0xFEFD // No Length Byte Or 0-Term + +//------------------------------------------------------------------------- +// Adapter Types Supported +//------------------------------------------------------------------------- +#define FLASH32_EISA (0 * 4) +#define FLASH32_PCI (1 * 4) +#define D29C_EISA (2 * 4) +#define D29C_PCI (3 * 4) +#define D100_PCI (4 * 4) + +//------------------------------------------------------------------------- +// Phy related constants +//------------------------------------------------------------------------- +#define PHY_503 0 +#define PHY_100_A 0x000003E0 +#define PHY_100_C 0x035002A8 +#define PHY_TX_ID 0x015002A8 +#define PHY_NSC_TX 0x5c002000 +#define PHY_OTHER 0xFFFF + +#define PHY_MODEL_REV_ID_MASK 0xFFF0FFFF +#define PARALLEL_DETECT 0 +#define N_WAY 1 + +#define RENEGOTIATE_TIME 35 // (3.5 Seconds) + +#define CONNECTOR_AUTO 0 +#define CONNECTOR_TPE 1 +#define CONNECTOR_MII 2 + +//------------------------------------------------------------------------- +// Ethernet Frame Sizes +//------------------------------------------------------------------------- +#define ETHERNET_ADDRESS_LENGTH 6 +#define ETHERNET_HEADER_SIZE 14 +#define MINIMUM_ETHERNET_PACKET_SIZE 60 +#define MAXIMUM_ETHERNET_PACKET_SIZE 1514 + +#define MAX_MULTICAST_ADDRESSES 32 +#define TCB_BUFFER_SIZE 0XE0 // 224 +#define COALESCE_BUFFER_SIZE 2048 +#define ETH_MAX_COPY_LENGTH 0x80 // 128 + +// Make receive area 1536 for 16 bit alignment. +//#define RCB_BUFFER_SIZE MAXIMUM_ETHERNET_PACKET_SIZE +#define RCB_BUFFER_SIZE 1520 // 0x5F0 + +//- Area reserved for all Non Transmit command blocks +#define MAX_NON_TX_CB_AREA 512 + +//------------------------------------------------------------------------- +// Ndis/Adapter driver constants +//------------------------------------------------------------------------- +#define MAX_PHYS_DESC 16 +#define MAX_RECEIVE_DESCRIPTORS 1024 // 0x400 +#define NUM_RMD 10 + +//-------------------------------------------------------------------------- +// System wide Equates +//-------------------------------------------------------------------------- +#define MAX_NUMBER_OF_EISA_SLOTS 15 +#define MAX_NUMBER_OF_PCI_SLOTS 15 + +//-------------------------------------------------------------------------- +// Equates Added for NDIS 4 +//-------------------------------------------------------------------------- +#define NUM_BYTES_PROTOCOL_RESERVED_SECTION 16 +#define MAX_NUM_ALLOCATED_RFDS 64 +#define MIN_NUM_RFD 4 +#define MAX_ARRAY_SEND_PACKETS 8 +// limit our receive routine to indicating this many at a time +#define MAX_ARRAY_RECEIVE_PACKETS 16 +#define MAC_RESERVED_SWRFDPTR 0 +#define MAX_PACKETS_TO_ADD 32 + +//------------------------------------------------------------------------- +//- Miscellaneous Equates +//------------------------------------------------------------------------- +#define CR 0x0D // Carriage Return +#define LF 0x0A // Line Feed + +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#define DRIVER_NULL ((ULONG)0xffffffff) +#define DRIVER_ZERO 0 + +//------------------------------------------------------------------------- +// Bit Mask definitions +//------------------------------------------------------------------------- +#define BIT_0 0x0001 +#define BIT_1 0x0002 +#define BIT_2 0x0004 +#define BIT_3 0x0008 +#define BIT_4 0x0010 +#define BIT_5 0x0020 +#define BIT_6 0x0040 +#define BIT_7 0x0080 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_24 0x01000000 +#define BIT_28 0x10000000 + +#define BIT_0_2 0x0007 +#define BIT_0_3 0x000F +#define BIT_0_4 0x001F +#define BIT_0_5 0x003F +#define BIT_0_6 0x007F +#define BIT_0_7 0x00FF +#define BIT_0_8 0x01FF +#define BIT_0_13 0x3FFF +#define BIT_0_15 0xFFFF +#define BIT_1_2 0x0006 +#define BIT_1_3 0x000E +#define BIT_2_5 0x003C +#define BIT_3_4 0x0018 +#define BIT_4_5 0x0030 +#define BIT_4_6 0x0070 +#define BIT_4_7 0x00F0 +#define BIT_5_7 0x00E0 +#define BIT_5_9 0x03E0 +#define BIT_5_12 0x1FE0 +#define BIT_5_15 0xFFE0 +#define BIT_6_7 0x00c0 +#define BIT_7_11 0x0F80 +#define BIT_8_10 0x0700 +#define BIT_9_13 0x3E00 +#define BIT_12_15 0xF000 +#define BIT_8_15 0xFF00 + +#define BIT_16_20 0x001F0000 +#define BIT_21_25 0x03E00000 +#define BIT_26_27 0x0C000000 + +// in order to make our custom oids hopefully somewhat unique +// we will use 0xFF (indicating implementation specific OID) +// A0 (first byte of non zero intel unique identifier) +// C9 (second byte of non zero intel unique identifier) +// XX (the custom OID number - providing 255 possible custom oids) +#define OID_CUSTOM_DRIVER_SET 0xFFA0C901 +#define OID_CUSTOM_DRIVER_QUERY 0xFFA0C902 +#define OID_CUSTOM_ARRAY 0xFFA0C903 +#define OID_CUSTOM_STRING 0xFFA0C904 + +#define CMD_BUS_MASTER BIT_2 + +#endif // _E100_EQU_H + diff --git a/general/pcidrv/kmdf/HW/eeprom.c b/general/pcidrv/kmdf/HW/eeprom.c new file mode 100644 index 00000000..42354f38 --- /dev/null +++ b/general/pcidrv/kmdf/HW/eeprom.c @@ -0,0 +1,306 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + eeprom.c + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +#include "precomp.h" + +#define EEPROM_MAX_SIZE 256 + +//***************************************************************************** +// +// I/O based Read EEPROM Routines +// +//***************************************************************************** + +//----------------------------------------------------------------------------- +// Procedure: EEpromAddressSize +// +// Description: determines the number of bits in an address for the eeprom +// acceptable values are 64, 128, and 256 +// +// Arguments: +// Size -- size of the eeprom +// +// Returns: +// bits in an address for that size eeprom +//----------------------------------------------------------------------------- + +USHORT GetEEpromAddressSize( + IN USHORT Size) +{ + switch (Size) + { + case 64: return 6; + case 128: return 7; + case 256: return 8; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Procedure: GetEEpromSize +// +// Description: This routine determines the size of the EEPROM. +// +// Arguments: +// Reg - EEPROM word to read. +// +// Returns: +// Size of the EEPROM, or zero if TRACE_LEVEL_ERROR. +//----------------------------------------------------------------------------- + +USHORT GetEEpromSize( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress) +{ + USHORT x, data; + USHORT size = 1; + + // select EEPROM, reset bits, set EECS + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); + + // write the read opcode + ShiftOutBits(FdoData, EEPROM_READ_OPCODE, 3, CSRBaseIoAddress); + + // experiment to discover the size of the eeprom. request register zero + // and wait for the eeprom to tell us it has accepted the entire address. + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + do + { + size *= 2; // each bit of address doubles eeprom size + x |= EEDO; // set bit to detect "dummy zero" + x &= ~EEDI; // address consists of all zeros + + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); + KeStallExecutionProcessor(100); + RaiseClock(FdoData, &x, CSRBaseIoAddress); + LowerClock(FdoData, &x, CSRBaseIoAddress); + + // check for "dummy zero" + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + if (size > EEPROM_MAX_SIZE) + { + size = 0; + break; + } + } + while (x & EEDO); + + // Now read the data (16 bits) in from the selected EEPROM word + data = ShiftInBits(FdoData, CSRBaseIoAddress); + + EEpromCleanup(FdoData, CSRBaseIoAddress); + + return size; +} + +//----------------------------------------------------------------------------- +// Procedure: ReadEEprom +// +// Description: This routine serially reads one word out of the EEPROM. +// +// Arguments: +// Reg - EEPROM word to read. +// +// Returns: +// Contents of EEPROM word (Reg). +//----------------------------------------------------------------------------- + +USHORT ReadEEprom( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress, + IN USHORT Reg, + IN USHORT AddressSize) +{ + USHORT x; + USHORT data; + + // select EEPROM, reset bits, set EECS + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~(EEDI | EEDO | EESK); + x |= EECS; + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); + + // write the read opcode and register number in that order + // The opcode is 3bits in length, reg is 6 bits long + ShiftOutBits(FdoData, EEPROM_READ_OPCODE, 3, CSRBaseIoAddress); + ShiftOutBits(FdoData, Reg, AddressSize, CSRBaseIoAddress); + + // Now read the data (16 bits) in from the selected EEPROM word + data = ShiftInBits(FdoData, CSRBaseIoAddress); + + EEpromCleanup(FdoData, CSRBaseIoAddress); + return data; +} + +//----------------------------------------------------------------------------- +// Procedure: ShiftOutBits +// +// Description: This routine shifts data bits out to the EEPROM. +// +// Arguments: +// data - data to send to the EEPROM. +// count - number of data bits to shift out. +// +// Returns: (none) +//----------------------------------------------------------------------------- + +VOID ShiftOutBits( + IN PFDO_DATA FdoData, + IN USHORT data, + IN USHORT count, + IN PUCHAR CSRBaseIoAddress) +{ + USHORT x,mask; + + mask = 0x01 << (count - 1); + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~(EEDO | EEDI); + + do + { + x &= ~EEDI; + if(data & mask) + x |= EEDI; + + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); + KeStallExecutionProcessor(100); + RaiseClock(FdoData, &x, CSRBaseIoAddress); + LowerClock(FdoData, &x, CSRBaseIoAddress); + mask = mask >> 1; + } while(mask); + + x &= ~EEDI; + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); +} + +//----------------------------------------------------------------------------- +// Procedure: ShiftInBits +// +// Description: This routine shifts data bits in from the EEPROM. +// +// Arguments: +// +// Returns: +// The contents of that particular EEPROM word +//----------------------------------------------------------------------------- + +USHORT ShiftInBits( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress) +{ + USHORT x,d,i; + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~( EEDO | EEDI); + d = 0; + + for(i=0; i<16; i++) + { + d = d << 1; + RaiseClock(FdoData, &x, CSRBaseIoAddress); + + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~(EEDI); + if(x & EEDO) + d |= 1; + + LowerClock(FdoData, &x, CSRBaseIoAddress); + } + + return d; +} + +//----------------------------------------------------------------------------- +// Procedure: RaiseClock +// +// Description: This routine raises the EEPOM's clock input (EESK) +// +// Arguments: +// x - Ptr to the EEPROM control register's current value +// +// Returns: (none) +//----------------------------------------------------------------------------- + +VOID RaiseClock( + IN PFDO_DATA FdoData, + IN OUT USHORT *x, + IN PUCHAR CSRBaseIoAddress) +{ + *x = *x | EESK; + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x); + KeStallExecutionProcessor(100); +} + + +//----------------------------------------------------------------------------- +// Procedure: LowerClock +// +// Description: This routine lower's the EEPOM's clock input (EESK) +// +// Arguments: +// x - Ptr to the EEPROM control register's current value +// +// Returns: (none) +//----------------------------------------------------------------------------- + +VOID LowerClock( + IN PFDO_DATA FdoData, + IN OUT USHORT *x, + IN PUCHAR CSRBaseIoAddress) +{ + *x = *x & ~EESK; + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x); + KeStallExecutionProcessor(100); +} + +//----------------------------------------------------------------------------- +// Procedure: EEpromCleanup +// +// Description: This routine returns the EEPROM to an idle state +// +// Arguments: +// +// Returns: (none) +//----------------------------------------------------------------------------- + +VOID EEpromCleanup( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress) +{ + USHORT x; + x = FdoData->ReadPort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG)); + + x &= ~(EECS | EEDI); + FdoData->WritePort((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x); + + RaiseClock(FdoData, &x, CSRBaseIoAddress); + LowerClock(FdoData, &x, CSRBaseIoAddress); +} + + diff --git a/general/pcidrv/kmdf/HW/isrdpc.c b/general/pcidrv/kmdf/HW/isrdpc.c new file mode 100644 index 00000000..ebc2a3a6 --- /dev/null +++ b/general/pcidrv/kmdf/HW/isrdpc.c @@ -0,0 +1,904 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + ISRDPC.C + +Abstract: + + Contains routine to handle interrupts, interrupt DPCs and WatchDogTimer DPC + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "ISRDPC.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, NICEvtDeviceD0ExitPreInterruptsDisabled) +#endif + + +BOOLEAN +NICEvtInterruptIsr( + IN WDFINTERRUPT Interrupt, + IN ULONG MessageID + ) +/*++ +Routine Description: + + Interrupt handler for the device. + +Arguments: + + Interupt - Address of the framework interrupt object + MessageID - + +Return Value: + + TRUE if our device is interrupting, FALSE otherwise. + +--*/ +{ + BOOLEAN InterruptRecognized = FALSE; + PFDO_DATA FdoData = NULL; + USHORT IntStatus; + + UNREFERENCED_PARAMETER( MessageID ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "--> NICEvtInterruptIsr\n"); + + FdoData = FdoGetData(WdfInterruptGetDevice(Interrupt)); + + // + // We process the interrupt if it's not disabled and it's active + // + if (!NIC_INTERRUPT_DISABLED(FdoData) && NIC_INTERRUPT_ACTIVE(FdoData)) + { + InterruptRecognized = TRUE; + + // + // Disable the interrupt (will be re-enabled in NICEvtInterruptDpc + // + NICDisableInterrupt(FdoData); + + // + // Acknowledge the interrupt(s) and get the interrupt status + // + + NIC_ACK_INTERRUPT(FdoData, IntStatus); + + WdfInterruptQueueDpcForIsr( Interrupt ); + + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INTERRUPT, "<-- NICEvtInterruptIsr\n"); + + return InterruptRecognized; +} + +VOID +NICEvtInterruptDpc( + IN WDFINTERRUPT WdfInterrupt, + IN WDFOBJECT WdfDevice + ) + +/*++ + +Routine Description: + + DPC callback for ISR. + +Arguments: + + WdfInterrupt - Handle to the framework interrupt object + + WdfDevice - Associated device object. + +Return Value: + +--*/ +{ + PFDO_DATA fdoData = NULL; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "--> NICEvtInterruptDpc\n"); + + fdoData = FdoGetData(WdfDevice); + + + WdfSpinLockAcquire(fdoData->RcvLock); + + NICHandleRecvInterrupt(fdoData); + + + WdfSpinLockRelease(fdoData->RcvLock); + + // + // Handle send interrupt + // + + WdfSpinLockAcquire(fdoData->SendLock); + + NICHandleSendInterrupt(fdoData); + + + WdfSpinLockRelease(fdoData->SendLock); + + // + // Check if any queued Sends need to be reprocessed. + // + NICCheckForQueuedSends(fdoData); + + // + // Start the receive unit if it had stopped + // + + WdfSpinLockAcquire(fdoData->RcvLock); + + NICStartRecv(fdoData); + + + WdfSpinLockRelease(fdoData->RcvLock); + + // + // Re-enable the interrupt (disabled in MPIsr) + // + WdfInterruptSynchronize( + WdfInterrupt, + NICEnableInterrupt, + fdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<-- NICEvtInterruptDpc\n"); + +} + +NTSTATUS +NICEvtInterruptEnable( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE AssociatedDevice + ) +/*++ + +Routine Description: + + This event is called when the Framework moves the device to D0, and after + EvtDeviceD0Entry. The driver should enable its interrupt here. + + This function will be called at the device's assigned interrupt + IRQL (DIRQL.) + +Arguments: + + Interrupt - Handle to a Framework interrupt object. + + AssociatedDevice - Handle to a Framework device object. + +Return Value: + + BOOLEAN - TRUE indicates that the interrupt was successfully enabled. + +--*/ +{ + PFDO_DATA fdoData; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtInterruptEnable\n"); + + fdoData = FdoGetData(AssociatedDevice); + NICEnableInterrupt(Interrupt, fdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtInterruptEnable\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS +NICEvtInterruptDisable( + IN WDFINTERRUPT Interrupt, + IN WDFDEVICE AssociatedDevice + ) +/*++ + +Routine Description: + + This event is called before the Framework moves the device to D1, D2 or D3 + and before EvtDeviceD0Exit. The driver should disable its interrupt here. + + This function will be called at the device's assigned interrupt + IRQL (DIRQL.) + +Arguments: + + Interrupt - Handle to a Framework interrupt object. + + AssociatedDevice - Handle to a Framework device object. + +Return Value: + + STATUS_SUCCESS - indicates success. + +--*/ +{ + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(Interrupt); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtInterruptDisable\n"); + + fdoData = FdoGetData(AssociatedDevice); + NICDisableInterrupt(fdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtInterruptDisable\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS +NICEvtDeviceD0EntryPostInterruptsEnabled( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + This event is called so that driver can do PASSIVE_LEVEL work after + the interrupt is connected and enabled. Here we start the watchdog timer. + Watch dog timer is used to do the initial link detection during + start and then used to make sure the device is not stuck for any reason. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Interrupt - Handle to a Framework interrupt object. + + AssociatedDevice - Handle to a Framework device object. + +Return Value: + + STATUS_SUCCESS - indicates success. + +--*/ +{ + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER( PreviousState ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtDeviceD0EntryPostInterruptsEnabled\n"); + + fdoData = FdoGetData(Device); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtDeviceD0EntryPostInterruptsEnabled\n"); + + return STATUS_SUCCESS; + +} + +NTSTATUS +NICEvtDeviceD0ExitPreInterruptsDisabled( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This event is called so that driver can do PASSIVE_LEVEL work before + the interrupt is disconnected and disabled. + +Arguments: + + Interrupt - Handle to a Framework interrupt object. + + AssociatedDevice - Handle to a Framework device object. + +Return Value: + + STATUS_SUCCESS - indicates success. + +--*/ +{ + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(TargetState); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "--> NICEvtDeviceD0ExitPreInterruptsDisabled\n"); + + fdoData = FdoGetData(Device); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, "<-- NICEvtDeviceD0ExitPreInterruptsDisabled\n"); + + return STATUS_SUCCESS; + +} + +VOID +NICStartWatchDogTimer( + IN PFDO_DATA FdoData + ) +{ + LARGE_INTEGER dueTime; + + if(!FdoData->CheckForHang){ + + // + // Set the link detection flag to indicate that NICWatchDogEvtTimerFunc + // is first doing link-detection. + // + MP_SET_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION); + FdoData->CheckForHang = FALSE; + FdoData->bLinkDetectionWait = FALSE; + FdoData->bLookForLink = FALSE; + dueTime.QuadPart = NIC_LINK_DETECTION_DELAY; + + } else { + dueTime.QuadPart = NIC_CHECK_FOR_HANG_DELAY; + } + + WdfTimerStart(FdoData->WatchDogTimer, + dueTime.QuadPart + ); + +} + +VOID +NICWatchDogEvtTimerFunc( + IN WDFTIMER Timer + ) +/*++ + +Routine Description: + + This DPC is used to do both link detection during hardware init and + after that for hardware hang detection. + +Arguments: + + +Return Value: + + None + +--*/ +{ + PFDO_DATA FdoData = NULL; + LARGE_INTEGER DueTime; + NTSTATUS status = STATUS_SUCCESS; + + FdoData = FdoGetData(WdfTimerGetParentObject(Timer)); + + DueTime.QuadPart = NIC_CHECK_FOR_HANG_DELAY; + + + if(!FdoData->CheckForHang){ + // + // We are still doing link detection + // + status = NICLinkDetection(FdoData); + if(status == STATUS_PENDING) { + // Wait for 100 ms + FdoData->bLinkDetectionWait = TRUE; + DueTime.QuadPart = NIC_LINK_DETECTION_DELAY; + }else { + FdoData->CheckForHang = TRUE; + } + }else { + // + // Link detection is over, let us check to see + // if the hardware is stuck. + // + if(NICCheckForHang(FdoData)){ + + status = NICReset(FdoData); + if(!NT_SUCCESS(status)){ + goto Exit; + } + } + } + + WdfTimerStart(FdoData->WatchDogTimer, // Timer + DueTime.QuadPart // DueTime + ); + + return; + +Exit: + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_DPC, "WatchDogTimer is exiting %x\n", status); + return; + +} + +BOOLEAN +NICCheckForHang( + IN PFDO_DATA FdoData + ) +/*++ + +Routine Description: + + CheckForHang handler is called in the context of a timer DPC. + take advantage of this fact when acquiring/releasing spinlocks + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + TRUE This NIC needs a reset + FALSE Everything is fine + +--*/ +{ + PMP_TCB pMpTcb; + + // + // Just skip this part if the adapter is doing link detection + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) + { + return(FALSE); + } + + // + // any nonrecoverable hardware error? + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_NON_RECOVER_ERROR)) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Non recoverable error - remove\n"); + return (TRUE); + } + + // + // hardware failure? + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR)) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "hardware error - reset\n"); + return(TRUE); + } + + // + // Is send stuck? + // + + + WdfSpinLockAcquire(FdoData->SendLock); + + if (FdoData->nBusySend > 0) + { + pMpTcb = FdoData->CurrSendHead; + pMpTcb->Count++; + if (pMpTcb->Count > NIC_SEND_HANG_THRESHOLD) + { + + WdfSpinLockRelease(FdoData->SendLock); + TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Send is stuck - reset\n"); + return(TRUE); + } + } + + + WdfSpinLockRelease(FdoData->SendLock); + + + WdfSpinLockAcquire(FdoData->RcvLock); + + // + // Update the RFD shrink count + // + if (FdoData->CurrNumRfd > FdoData->NumRfd) + { + FdoData->RfdShrinkCount++; + } + + + WdfSpinLockRelease(FdoData->RcvLock); + + NICIndicateMediaState(FdoData); + + return(FALSE); +} + +NTSTATUS +NICReset( + IN PFDO_DATA FdoData + ) +/*++ + +Routine Description: + + Function to reset the device. + +Arguments: + + FdoData Pointer to our adapter + + +Return Value: + + NT Status code. + +Note: + NICReset is called at DPC. Take advantage of this fact + when acquiring or releasing spinlocks + +--*/ +{ + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "---> MPReset\n"); + + + WdfSpinLockAcquire(FdoData->Lock); + + WdfSpinLockAcquire(FdoData->SendLock); + + WdfSpinLockAcquire(FdoData->RcvLock); + + do + { + // + // Is this adapter already doing a reset? + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS)) + { + status = STATUS_SUCCESS; + goto exit; + } + + MP_SET_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS); + + // + // Is this adapter doing link detection? + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_DPC, "Reset is pended...\n"); + status = STATUS_SUCCESS; + goto exit; + } + // + // Is this adapter going to be removed + // + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_NON_RECOVER_ERROR)) + { + status = STATUS_DEVICE_DATA_ERROR; + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS)) + { + goto exit; + } + + // This is an unrecoverable hardware failure. + // We need to tell NDIS to remove this miniport + MP_SET_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS); + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS); + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->SendLock); + + WdfSpinLockRelease(FdoData->Lock); + + // TODO: Log an entry into the eventlog + WdfDeviceSetFailed(FdoData->WdfDevice, WdfDeviceFailedAttemptRestart); + + TraceEvents(TRACE_LEVEL_FATAL, DBG_DPC, "<--- MPReset, status=%x\n", status); + + return status; + } + + + // + // Disable the interrupt and issue a reset to the NIC + // + NICDisableInterrupt(FdoData); + NICIssueSelectiveReset(FdoData); + + + // + // Release all the locks and then acquire back the send lock + // we are going to clean up the send queues + // which may involve calling Ndis APIs + // release all the locks before grabbing the send lock to + // avoid deadlocks + // + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->SendLock); + + WdfSpinLockRelease(FdoData->Lock); + + + WdfSpinLockAcquire(FdoData->SendLock); + + // + // Free the packets on SendQueueList + // + NICFreeQueuedSendPackets(FdoData); + + // + // Free the packets being actively sent & stopped + // + NICFreeBusySendPackets(FdoData); + + + RtlZeroMemory(FdoData->MpTcbMem, FdoData->MpTcbMemSize); + + // + // Re-initialize the send structures + // + NICInitSendBuffers(FdoData); + + + WdfSpinLockRelease(FdoData->SendLock); + + // + // get all the locks again in the right order + // + + + WdfSpinLockAcquire(FdoData->Lock); + + WdfSpinLockAcquire(FdoData->SendLock); + + WdfSpinLockAcquire(FdoData->RcvLock); + + // + // Reset the RFD list and re-start RU + // + NICResetRecv(FdoData); + status = NICStartRecv(FdoData); + if (status != STATUS_SUCCESS) + { + // Are we having failures in a few consecutive resets? + if (FdoData->HwErrCount < NIC_HARDWARE_ERROR_THRESHOLD) + { + // It's not over the threshold yet, let it to continue + FdoData->HwErrCount++; + } + else + { + // This is an unrecoverable hardware failure. + // We need to tell NDIS to remove this miniport + MP_SET_FLAG(FdoData, fMP_ADAPTER_REMOVE_IN_PROGRESS); + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS); + + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->SendLock); + + WdfSpinLockRelease(FdoData->Lock); + + // TODO: Log an entry into the eventlog + // + // Tell the system that the device has failed. + // + WdfDeviceSetFailed(FdoData->WdfDevice, WdfDeviceFailedAttemptRestart); + + TraceEvents(TRACE_LEVEL_ERROR, DBG_DPC, "<--- MPReset, status=%x\n", status); + return(status); + } + + break; + } + + FdoData->HwErrCount = 0; + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR); + + NICEnableInterrupt(FdoData->WdfInterrupt, FdoData); + + } WHILE (FALSE); + + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS); + + exit: + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->SendLock); + + WdfSpinLockRelease(FdoData->Lock); + + + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "<--- MPReset, status=%x\n", status); + return(status); +} + + +NTSTATUS +NICLinkDetection( + PFDO_DATA FdoData + ) +/*++ + +Routine Description: + + Timer function for postponed link negotiation. Called from + the NICWatchDogEvtTimerFunc. After the link detection is over + we will complete any pending ioctl or send IRPs. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + NT status + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + MEDIA_STATE CurrMediaState; + PNDISPROT_QUERY_OID pQuery = NULL; + PNDISPROT_SET_OID pSet = NULL; + PVOID DataBuffer; + ULONG BytesWritten; + NDIS_OID Oid; + PVOID InformationBuffer; + size_t bufSize; + WDFREQUEST request; + + // + // Handle the link negotiation. + // + if (FdoData->bLinkDetectionWait) + { + status = ScanAndSetupPhy(FdoData); + } + else + { + status = PhyDetect(FdoData); + } + + if (status == STATUS_PENDING) + { + return status; + } + + // + // Reset some variables for link detection + // + FdoData->bLinkDetectionWait = FALSE; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_DPC, "NICLinkDetection - negotiation done\n"); + + + WdfSpinLockAcquire(FdoData->Lock); + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION); + + WdfSpinLockRelease(FdoData->Lock); + + // + // Any OID query request pending? + // + + status = NICGetIoctlRequest(FdoData->PendingIoctlQueue, + IOCTL_NDISPROT_QUERY_OID_VALUE, + &request); + + if(NT_SUCCESS(status)) { + status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_QUERY_OID), &DataBuffer, &bufSize); + if(NT_SUCCESS(status)) { + + pQuery = (PNDISPROT_QUERY_OID)DataBuffer; + Oid = pQuery->Oid; + InformationBuffer = &pQuery->Data[0]; + switch(Oid) + { + case OID_GEN_LINK_SPEED: + *((PULONG)InformationBuffer) = FdoData->usLinkSpeed * 10000; + BytesWritten = sizeof(ULONG); + + break; + + case OID_GEN_MEDIA_CONNECT_STATUS: + default: + ASSERT(Oid == OID_GEN_MEDIA_CONNECT_STATUS); + + CurrMediaState = NICIndicateMediaState(FdoData); + + RtlMoveMemory(InformationBuffer, + &CurrMediaState, + sizeof(NDIS_MEDIA_STATE)); + + BytesWritten = sizeof(NDIS_MEDIA_STATE); + } + + WdfRequestCompleteWithInformation(request, status, BytesWritten); + } + } + + // + // Any OID set request pending? + // + status = NICGetIoctlRequest(FdoData->PendingIoctlQueue, + IOCTL_NDISPROT_SET_OID_VALUE, + &request); + + if(NT_SUCCESS(status)) { + ULONG PacketFilter; + + status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_SET_OID), &DataBuffer, &bufSize); + if(NT_SUCCESS(status)) { + + pSet = (PNDISPROT_SET_OID)DataBuffer; + Oid = pSet->Oid; + InformationBuffer = &pSet->Data[0]; + if (Oid == OID_GEN_CURRENT_PACKET_FILTER) + { + + RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG)); + + + WdfSpinLockAcquire(FdoData->Lock); + + status = NICSetPacketFilter( + FdoData, + PacketFilter); + + + WdfSpinLockRelease(FdoData->Lock); + + if (status == STATUS_SUCCESS) + { + FdoData->PacketFilter = PacketFilter; + } + + WdfRequestCompleteWithInformation(request, status, 0); + } + } + } + + // + // Any read pending? + // + + WdfSpinLockAcquire(FdoData->RcvLock); + + // + // Start the NIC receive unit + // + status = NICStartRecv(FdoData); + if (status != STATUS_SUCCESS) + { + MP_SET_HARDWARE_ERROR(FdoData); + } + + + WdfSpinLockRelease(FdoData->RcvLock); + + // + // Send packets which have been queued while link detection was going on. + // + NICCheckForQueuedSends(FdoData); + + return status; +} + + diff --git a/general/pcidrv/kmdf/HW/localwpp.ini b/general/pcidrv/kmdf/HW/localwpp.ini new file mode 100644 index 00000000..c290070a --- /dev/null +++ b/general/pcidrv/kmdf/HW/localwpp.ini @@ -0,0 +1,17 @@ +// +// This defines how to log a len/buffer pair. +// This function should be in trace.h +// + +DEFINE_CPLX_TYPE(HEXDUMP, WPP_LOGHEXDUMP, xstr_t, ItemHEXDump,"s", _HEX_, 0,2); + +// DEFINE_CPLX_TYPE( +// name, // i.e. HEXDUMP // %!HEXDUMP! +// macro, // i.e. WPP_LOGHEXDUMP // Marshalling macro, defined in trace.h +// structure, // i.e. xstr_t // Argument type (structure to be created by above macro) +// item type, // i.e. ItemHEXDump // MOF type that TracePrt can understand +// format specifier, // i.e. "s" // a format specifier that TracePrt can understand +// ???? // i.e. _HEX_ // Type signature (becomes a part of function name) +// ???? // i.e. 0 // Weight (0 is variable data length) +// ???? // i.e. 2 // Slots used by this entry (optional, 1 default) +// ) diff --git a/general/pcidrv/kmdf/HW/macros.h b/general/pcidrv/kmdf/HW/macros.h new file mode 100644 index 00000000..61ed01d6 --- /dev/null +++ b/general/pcidrv/kmdf/HW/macros.h @@ -0,0 +1,312 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + macros.h (inlinef.h) + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +__inline BOOLEAN +WaitScb( + IN PFDO_DATA FdoData + ); + + +//----------------------------------------------------------------------------- +// Procedure: D100IssueScbCommand +// +// Description: This general routine will issue a command to the D100. +// +// Arguments: +// FdoData - ptr to FdoData object instance. +// ScbCommand - The command that is to be issued +// WaitForSCB - A boolean value indicating whether or not a wait for SCB +// must be done before the command is issued to the chip +// +// Returns: +// TRUE if the command was issued to the chip successfully +// FALSE if the command was not issued to the chip +//----------------------------------------------------------------------------- +__inline NTSTATUS +D100IssueScbCommand( + IN PFDO_DATA FdoData, + IN UCHAR ScbCommandLow, + IN BOOLEAN WaitForScb + ) +{ + if(WaitForScb == TRUE) + { + if(!WaitScb(FdoData)) + { + return(STATUS_DEVICE_DATA_ERROR); + } + } + + FdoData->CSRAddress->ScbCommandLow = ScbCommandLow; + + return(STATUS_SUCCESS); +} + + +__inline NTSTATUS +MP_GET_STATUS_FROM_FLAGS( + IN PFDO_DATA FdoData + ) +{ + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_RESET_IN_PROGRESS)) + { + Status = STATUS_DEVICE_NOT_READY; + } + else if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_HARDWARE_ERROR)) + { + Status = STATUS_DEVICE_OFF_LINE; + } + else if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_NO_CABLE)) + { + Status = STATUS_DEVICE_NOT_CONNECTED; + } + + return Status; +} + +__inline VOID +NICDisableInterrupt( + IN PFDO_DATA FdoData + ) +{ + FdoData->CSRAddress->ScbCommandHigh = SCB_INT_MASK; +} + +EVT_WDF_INTERRUPT_SYNCHRONIZE NICEnableInterrupt; + +__inline BOOLEAN NICEnableInterrupt( + IN WDFINTERRUPT WdfInterrupt, + IN WDFCONTEXT Context + ) +{ + PFDO_DATA FdoData = (PFDO_DATA)Context; + + UNREFERENCED_PARAMETER(WdfInterrupt); + + FdoData->CSRAddress->ScbCommandHigh = 0; + + return TRUE; +} + +__inline +BOOLEAN +IsPoMgmtSupported( + IN PFDO_DATA FdoData + ) +{ + + if (FdoData->RevsionID >= E100_82559_A_STEP + /*&& FdoData->RevsionID <= E100_82559_C_STEP*/) + { + return TRUE; + } + else + { + return FALSE; + } + +} + +__inline +USHORT +NICReadPortUShort ( + IN USHORT * x + ) +{ + return READ_PORT_USHORT (x); +} +__inline +VOID +NICWritePortUShort ( + IN USHORT * x, + IN USHORT y + ) +{ + WRITE_PORT_USHORT (x,y); +} + +__inline +USHORT +NICReadRegisterUShort ( + IN USHORT * x + ) +{ + return READ_REGISTER_USHORT (x); +} + +__inline +VOID +NICWriteRegisterUShort ( + IN USHORT * x, + IN USHORT y + ) +{ + WRITE_REGISTER_USHORT (x,y); +} + + + +// routines.c + +BOOLEAN +MdiRead( + IN PFDO_DATA Adapter, + IN ULONG RegAddress, + IN ULONG PhyAddress, + IN BOOLEAN Recoverable, + IN OUT PUSHORT DataValue + ); + +VOID +MdiWrite( + IN PFDO_DATA FdoData, + IN ULONG RegAddress, + IN ULONG PhyAddress, + IN USHORT DataValue + ); + +NTSTATUS +D100IssueScbCommand( + IN PFDO_DATA FdoData, + IN UCHAR ScbCommandLow, + IN BOOLEAN WaitForScb + ); + +MEDIA_STATE +GetMediaState( + IN PFDO_DATA Adapter + ); + +NTSTATUS +D100SubmitCommandBlockAndWait( + IN PFDO_DATA Adapter + ); + +VOID +NICIssueFullReset( + PFDO_DATA Adapter + ); + +VOID +NICIssueSelectiveReset( + PFDO_DATA Adapter + ); + +VOID +DumpStatsCounters( + IN PFDO_DATA Adapter + ); + + + +// physet.c + +VOID +ResetPhy( + IN PFDO_DATA FdoData + ); + +NTSTATUS +PhyDetect( + IN PFDO_DATA FdoData + ); + +NTSTATUS +ScanAndSetupPhy( + IN PFDO_DATA FdoData + ); + +VOID +SelectPhy( + IN PFDO_DATA FdoData, + IN UINT SelectPhyAddress, + IN BOOLEAN WaitAutoNeg + ); + +NTSTATUS +SetupPhy( + IN PFDO_DATA FdoData + ); + +VOID +FindPhySpeedAndDpx( + IN PFDO_DATA FdoData, + IN UINT PhyId + ); + + + +// eeprom.c +USHORT +GetEEpromAddressSize( + IN USHORT Size + ); + +USHORT +GetEEpromSize( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress + ); + +USHORT +ReadEEprom( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress, + IN USHORT Reg, + IN USHORT AddressSize + ); + +VOID +ShiftOutBits( + IN PFDO_DATA FdoData, + IN USHORT data, + IN USHORT count, + IN PUCHAR CSRBaseIoAddress + ); + +USHORT +ShiftInBits( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress + ); + +VOID +RaiseClock( + IN PFDO_DATA FdoData, + IN OUT USHORT *x, + IN PUCHAR CSRBaseIoAddress + ); + +VOID +LowerClock( + IN PFDO_DATA FdoData, + IN OUT USHORT *x, + IN PUCHAR CSRBaseIoAddress + ); + +VOID +EEpromCleanup( + IN PFDO_DATA FdoData, + IN PUCHAR CSRBaseIoAddress + ); + diff --git a/general/pcidrv/kmdf/HW/nic_def.h b/general/pcidrv/kmdf/HW/nic_def.h new file mode 100644 index 00000000..6e129be0 --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_def.h @@ -0,0 +1,800 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + + +#ifndef _NIC_DEF_H +#define _NIC_DEF_H + +#if !defined(WIN2K) + +#include "xfilter.h" // for ETH_* macros + +#else + +#define ETH_LENGTH_OF_ADDRESS 6 + +// +// ZZZ This is a little-endian specific check. +// +#define ETH_IS_MULTICAST(Address) \ + (BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x01)) + +// +// Check whether an address is broadcast. +// +#define ETH_IS_BROADCAST(Address) \ + ((((PUCHAR)(Address))[0] == ((UCHAR)0xff)) && (((PUCHAR)(Address))[1] == ((UCHAR)0xff))) + +// +// This macro is used to copy from one network address to +// another. +// +#define ETH_COPY_NETWORK_ADDRESS(_D, _S) \ +{ \ + *((ULONG UNALIGNED *)(_D)) = *((ULONG UNALIGNED *)(_S)); \ + *((USHORT UNALIGNED *)((UCHAR *)(_D)+4)) = *((USHORT UNALIGNED *)((UCHAR *)(_S)+4)); \ +} + +#endif + + + +// packet and header sizes +#define NIC_MAX_PACKET_SIZE 1514 +#define NIC_MIN_PACKET_SIZE 60 +#define NIC_HEADER_SIZE 14 + +// multicast list size +#define NIC_MAX_MCAST_LIST 32 + + +// media type, we use ethernet, change if necessary +#define NIC_MEDIA_TYPE NdisMedium802_3 + +#define NIC_INTERRUPT_MODE NdisInterruptLevelSensitive + +// NIC PCI Device and vendor IDs +#define NIC_PCI_DEVICE_ID 0x1229 +#define NIC_PCI_VENDOR_ID 0x8086 + + // IO space length +#define NIC_MAP_IOSPACE_LENGTH sizeof(CSR_STRUC) + +// PCS config space including the Device Specific part of it/ +#define NIC_PCI_E100_HDR_LENGTH 0xe2 + +// define some types for convenience +// TXCB_STRUC, RFD_STRUC and CSR_STRUC are hardware specific structures +// hardware TCB (Transmit Control Block) structure +typedef TXCB_STRUC HW_TCB; +typedef PTXCB_STRUC PHW_TCB; + +// hardware RFD (Receive Frame Descriptor) structure +typedef RFD_STRUC HW_RFD; +typedef PRFD_STRUC PHW_RFD; + +// hardware CSR (Control Status Register) structure +typedef CSR_STRUC HW_CSR; +typedef PCSR_STRUC PHW_CSR; +// change to your company name instead of using Microsoft +#define NIC_VENDOR_DESC "Microsoft" + +// number of TCBs per processor - min, default and max +#define NIC_MIN_TCBS 1 +#define NIC_DEF_TCBS 32 +#define NIC_MAX_TCBS 64 + +// max number of physical fragments supported per TCB +#define NIC_MAX_PHYS_BUF_COUNT 8 + +// number of RFDs - min, default and max +#define NIC_MIN_RFDS 4 +#define NIC_DEF_RFDS 20 +#define NIC_MAX_RFDS 1024 + +// only grow the RFDs up to this number +#define NIC_MAX_GROW_RFDS 128 + +// How many intervals before the RFD list is shrinked? +#define NIC_RFD_SHRINK_THRESHOLD 10 + +// local data buffer size (to copy send packet data into a local buffer) +#define NIC_BUFFER_SIZE 1520 + +// max lookahead size +#define NIC_MAX_LOOKAHEAD (NIC_MAX_PACKET_SIZE - NIC_HEADER_SIZE) + +// max number of send packets the MiniportSendPackets function can accept +#define NIC_MAX_SEND_PACKETS 10 + +// supported filters +#define NIC_SUPPORTED_FILTERS ( \ + NDIS_PACKET_TYPE_DIRECTED | \ + NDIS_PACKET_TYPE_MULTICAST | \ + NDIS_PACKET_TYPE_BROADCAST | \ + NDIS_PACKET_TYPE_PROMISCUOUS | \ + NDIS_PACKET_TYPE_ALL_MULTICAST) + +// Threshold for a remove +#define NIC_HARDWARE_ERROR_THRESHOLD 5 + +// The CheckForHang intervals before we decide the send is stuck +#define NIC_SEND_HANG_THRESHOLD 5 + +// NIC specific macros +#define NIC_RFD_GET_STATUS(_HwRfd) ((_HwRfd)->RfdCbHeader.CbStatus) +#define NIC_RFD_STATUS_COMPLETED(_Status) ((_Status) & RFD_STATUS_COMPLETE) +#define NIC_RFD_STATUS_SUCCESS(_Status) ((_Status) & RFD_STATUS_OK) +#define NIC_RFD_GET_PACKET_SIZE(_HwRfd) (((_HwRfd)->RfdActualCount) & RFD_ACT_COUNT_MASK) +#define NIC_RFD_VALID_ACTUALCOUNT(_HwRfd) ((((_HwRfd)->RfdActualCount) & (RFD_EOF_BIT | RFD_F_BIT)) == (RFD_EOF_BIT | RFD_F_BIT)) + +#define ListNext(_pL) (_pL)->Flink + +#define ListPrev(_pL) (_pL)->Blink + +// Constants for various purposes of KeStallExecutionProcessor + +#define NIC_DELAY_POST_RESET 20 +// Wait 5 milliseconds for the self-test to complete +#define NIC_DELAY_POST_SELF_TEST_MS 5 + + +// delay used for link detection to minimize the init time +// change this value to match your hardware +#define NIC_LINK_DETECTION_DELAY ((LONGLONG) -MILLISECONDS_TO_100NS * 100) // 100ms +#define NIC_CHECK_FOR_HANG_DELAY ((LONGLONG) -MILLISECONDS_TO_100NS * 400) // 400ms + +// MP_TCB flags +#define fMP_TCB_IN_USE 0x00000001 +#define fMP_TCB_USE_LOCAL_BUF 0x00000002 +#define fMP_TCB_MULTICAST 0x00000004 // a hardware workaround using multicast + +// MP_RFD flags +#define fMP_RFD_RECV_PEND 0x00000001 +#define fMP_RFD_ALLOC_PEND 0x00000002 +#define fMP_RFD_RECV_READY 0x00000004 +#define fMP_RFD_RESOURCES 0x00000008 + +// MP_ADAPTER flags +#define fMP_ADAPTER_SCATTER_GATHER 0x00000001 // obsolete +#define fMP_ADAPTER_RECV_LOOKASIDE 0x00000004 +#define fMP_ADAPTER_INTERRUPT_IN_USE 0x00000008 + +#define fMP_ADAPTER_NON_RECOVER_ERROR 0x00800000 + +#define fMP_ADAPTER_RESET_IN_PROGRESS 0x01000000 +#define fMP_ADAPTER_NO_CABLE 0x02000000 +#define fMP_ADAPTER_HARDWARE_ERROR 0x04000000 +#define fMP_ADAPTER_REMOVE_IN_PROGRESS 0x08000000 +#define fMP_ADAPTER_HALT_IN_PROGRESS 0x10000000 + +#define fMP_ADAPTER_LINK_DETECTION 0x20000000 + +#define NIC_INTERRUPT_DISABLED(_adapter) \ + (_adapter->CSRAddress->ScbCommandHigh & SCB_INT_MASK) + +#define NIC_INTERRUPT_ACTIVE(_adapter) \ + (((_adapter->CSRAddress->ScbStatus & SCB_ALL_INTERRUPT_BITS) != SCB_ALL_INTERRUPT_BITS) \ + && (_adapter->CSRAddress->ScbStatus & SCB_ACK_MASK)) + + +#define NIC_ACK_INTERRUPT(_adapter, _value) { \ + _value = _adapter->CSRAddress->ScbStatus & SCB_ACK_MASK; \ + _adapter->CSRAddress->ScbStatus = _value; } + +#define NIC_IS_RECV_READY(_adapter) \ + ((_adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) == SCB_RUS_READY) + +//------------------------------------------------------------------------- +// NON_TRANSMIT_CB -- Generic Non-Transmit Command Block +//------------------------------------------------------------------------- +typedef struct _NON_TRANSMIT_CB +{ + union + { + MULTICAST_CB_STRUC Multicast; + CONFIG_CB_STRUC Config; + IA_CB_STRUC Setup; + DUMP_CB_STRUC Dump; + FILTER_CB_STRUC Filter; + } NonTxCb; + +} NON_TRANSMIT_CB, *PNON_TRANSMIT_CB; + +typedef enum _MEDIA_STATE { + + Connected = 0, + Disconnected + +} MEDIA_STATE; + +#define ALIGN_16 16 + +// +// The driver should put the data(after Ethernet header) at 8-bytes boundary +// +#define ETH_DATA_ALIGN 8 // the data(after Ethernet header) should be 8-byte aligned +// +// Shift HW_RFD 0xA bytes to make Tcp data 8-byte aligned +// Since the ethernet header is 14 bytes long. If a packet is at 0xA bytes +// offset, its data(ethernet user data) will be at 8 byte boundary +// +#define HWRFD_SHIFT_OFFSET 0xA // Shift HW_RFD 0xA bytes to make Tcp data 8-byte aligned + +// +// The driver has to allocate more data then HW_RFD needs to allow shifting data +// +#define MORE_DATA_FOR_ALIGN (ETH_DATA_ALIGN + HWRFD_SHIFT_OFFSET) +// +// Get a 8-bytes aligned memory address from a given the memory address. +// If the given address is not 8-bytes aligned, return the closest bigger memory address +// which is 8-bytes aligned. +// +#define DATA_ALIGN(_Va) ((PVOID)(((ULONG_PTR)(_Va) + (ETH_DATA_ALIGN - 1)) & ~(ETH_DATA_ALIGN - 1))) +// +// Get the number of bytes the final address shift from the original address +// +#define BYTES_SHIFT(_NewVa, _OrigVa) ((PUCHAR)(_NewVa) - (PUCHAR)(_OrigVa)) + +#define ETH_IS_LOCALLY_ADMINISTERED(Address) \ + (BOOLEAN)(((PUCHAR)(Address))[0] & ((UCHAR)0x02)) + + +//-------------------------------------- +// Some utility macros +//-------------------------------------- +#ifndef min +#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +#ifndef max +#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + +#define MP_ALIGNMEM(_p, _align) (((_align) == 0) ? (_p) : (PUCHAR)(((ULONG_PTR)(_p) + ((_align)-1)) & (~((ULONG_PTR)(_align)-1)))) +#define MP_ALIGNMEM_PHYS(_p, _align) (((_align) == 0) ? (_p) : (((ULONG)(_p) + ((_align)-1)) & (~((ULONG)(_align)-1)))) +#define MP_ALIGNMEM_PA(_p, _align) (((_align) == 0) ? (_p).QuadPart : (((_p).QuadPart + ((_align)-1)) & (~((ULONGLONG)(_align)-1)))) + +#define GetListHeadEntry(ListHead) ((ListHead)->Flink) +#define GetListTailEntry(ListHead) ((ListHead)->Blink) +#define GetListFLink(ListEntry) ((ListEntry)->Flink) + +#define IsSListEmpty(ListHead) (((PSINGLE_LIST_ENTRY)ListHead)->Next == NULL) + +//-------------------------------------- +// Macros for flag and ref count operations +//-------------------------------------- +#define MP_SET_FLAG(_M, _F) ((_M)->Flags |= (_F)) +#define MP_CLEAR_FLAG(_M, _F) ((_M)->Flags &= ~(_F)) +#define MP_CLEAR_FLAGS(_M) ((_M)->Flags = 0) +#define MP_TEST_FLAG(_M, _F) (((_M)->Flags & (_F)) != 0) +#define MP_TEST_FLAGS(_M, _F) (((_M)->Flags & (_F)) == (_F)) + +#if 0 // Not implemented + +//-------------------------------------- +// Coalesce Tx buffer for local data copying +//-------------------------------------- +typedef struct _MP_TXBUF +{ + SINGLE_LIST_ENTRY SList; + PMDL Mdl; + + ULONG AllocSize; + PVOID AllocVa; + PHYSICAL_ADDRESS AllocLa; // Logical Address + + PUCHAR pBuffer; + PHYSICAL_ADDRESS BufferLa; // Logical Address + ULONG BufferSize; + +} MP_TXBUF, *PMP_TXBUF; + +#endif + +//-------------------------------------- +// TCB (Transmit Control Block) +//-------------------------------------- +typedef struct _MP_TCB +{ + struct _MP_TCB *Next; + ULONG Flags; + ULONG Count; + WDFDMATRANSACTION DmaTransaction; + + PHW_TCB HwTcb; // ptr to HW TCB VA + ULONG HwTcbPhys; // ptr to HW TCB PA + PHW_TCB PrevHwTcb; // ptr to previous HW TCB VA + + PTBD_STRUC HwTbd; // ptr to first TBD + ULONG HwTbdPhys; // ptr to first TBD PA + +} MP_TCB, *PMP_TCB; + +//-------------------------------------- +// RFD (Receive Frame Descriptor) +//-------------------------------------- +typedef struct _MP_RFD +{ + LIST_ENTRY List; + PVOID Buffer; // Pointer to Buffer + PMDL Mdl; + PHW_RFD HwRfd; // ptr to hardware RFD + WDFCOMMONBUFFER WdfCommonBuffer; + PHW_RFD OriginalHwRfd; // ptr to shared memory + PHYSICAL_ADDRESS HwRfdLa; // logical address of RFD + PHYSICAL_ADDRESS OriginalHwRfdLa; // Original physical address allocated by NDIS + ULONG HwRfdPhys; // lower part of HwRfdPa + BOOLEAN DeleteCommonBuffer; // Indicates if WdfObjectDelete + // is to be called when freeing MD_RFD. + ULONG Flags; + ULONG PacketSize; // total size of receive frame + WDFMEMORY LookasideMemoryHdl; +} MP_RFD, *PMP_RFD; + +//-------------------------------------- +// Structure for Power Management Info +//-------------------------------------- +typedef struct _MP_POWER_MGMT +{ + + // List of Wake Up Patterns + LIST_ENTRY PatternList; + + // Current Power state of the adapter + UINT PowerState; + + // Is PME_En on this adapter + BOOLEAN PME_En; + + // Wake-up capabailities of the adapter + BOOLEAN bWakeFromD0; + BOOLEAN bWakeFromD1; + BOOLEAN bWakeFromD2; + BOOLEAN bWakeFromD3Hot; + BOOLEAN bWakeFromD3Aux; + // Pad + BOOLEAN Pad[2]; + +} MP_POWER_MGMT, *PMP_POWER_MGMT; + + + +typedef struct _MP_WAKE_PATTERN +{ + // Link to the next Pattern + LIST_ENTRY linkListEntry; + + // E100 specific signature of the pattern + ULONG Signature; + + // Size of this allocation + ULONG AllocationSize; + + // Pattern - This contains the NDIS_PM_PACKET_PATTERN + UCHAR Pattern[1]; + +} MP_WAKE_PATTERN , *PMP_WAKE_PATTERN ; + + +//-------------------------------------- +// Macros specific to miniport adapter structure +//-------------------------------------- +#define MP_TCB_RESOURCES_AVAIABLE(_M) ((_M)->nBusySend < (_M)->NumTcb) + +#define MP_SHOULD_FAIL_SEND(_M) ((_M)->Flags & fMP_ADAPTER_FAIL_SEND_MASK) +#define MP_IS_NOT_READY(_M) ((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) +#define MP_IS_READY(_M) !((_M)->Flags & fMP_ADAPTER_NOT_READY_MASK) + +#define MP_SET_HARDWARE_ERROR(adapter) MP_SET_FLAG(adapter, fMP_ADAPTER_HARDWARE_ERROR) +#define MP_SET_NON_RECOVER_ERROR(adapter) MP_SET_FLAG(adapter, fMP_ADAPTER_NON_RECOVER_ERROR) + +#define MP_OFFSET(field) ((UINT)FIELD_OFFSET(MP_ADAPTER,field)) +#define MP_SIZE(field) sizeof(((PMP_ADAPTER)0)->field) + + +//-------------------------------------- +// Stall execution and wait with timeout +//-------------------------------------- +/*++ + _condition - condition to wait for + _timeout_ms - timeout value in milliseconds + _result - TRUE if condition becomes true before it times out +--*/ +#define MP_STALL_AND_WAIT(_condition, _timeout_ms, _result) \ +{ \ + int counter; \ + _result = FALSE; \ + for(counter = _timeout_ms * 50; counter != 0; counter--) \ + { \ + if(_condition) \ + { \ + _result = TRUE; \ + break; \ + } \ + KeStallExecutionProcessor(20); \ + } \ +} + +__inline VOID MP_STALL_EXECUTION( + IN ULONG MsecDelay) +{ + // Delay in 100 usec increments + MsecDelay *= 10; + while (MsecDelay) + { + KeStallExecutionProcessor(100); + MsecDelay--; + } +} + +typedef struct _FDO_DATA FDO_DATA, *PFDO_DATA; + + +NTSTATUS +NICGetDeviceInformation( + IN OUT PFDO_DATA FdoData + ); + +NTSTATUS +NICAllocateSoftwareResources( + IN OUT PFDO_DATA FdoData + ); + +NTSTATUS +NICMapHWResources( + IN OUT PFDO_DATA FdoData, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ); + +NTSTATUS +NICUnmapHWResources( + IN OUT PFDO_DATA FdoData + ); + + +NTSTATUS +NICFreeSoftwareResources( + IN OUT PFDO_DATA FdoData + ); + +NTSTATUS +NICInitializeAdapter( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICReadAdapterInfo( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICSelfTest( + IN PFDO_DATA FdoData + ); + +VOID +HwSoftwareReset( + IN PFDO_DATA FdoData + ); + +EVT_WDF_INTERRUPT_ISR NICEvtInterruptIsr; +EVT_WDF_INTERRUPT_DPC NICEvtInterruptDpc; +EVT_WDF_INTERRUPT_ENABLE NICEvtInterruptEnable; +EVT_WDF_INTERRUPT_DISABLE NICEvtInterruptDisable; + +EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED NICEvtDeviceD0EntryPostInterruptsEnabled; +EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED NICEvtDeviceD0ExitPreInterruptsDisabled; + +EVT_WDF_IO_QUEUE_IO_WRITE PciDrvEvtIoWrite; + +EVT_WDF_PROGRAM_DMA NICEvtProgramDmaFunction; + +EVT_WDF_TIMER NICWatchDogEvtTimerFunc; + +EVT_WDF_WORKITEM NICAllocRfdWorkItem; +EVT_WDF_WORKITEM NICFreeRfdWorkItem; + +NTSTATUS +NICAllocAdapterMemory( + IN PFDO_DATA FdoData + ); + +VOID +NICFreeAdapterMemory( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICAllocRfd( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ); + +VOID +NICFreeRfd( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ); + +VOID +NICReturnRFD( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ); + +NTSTATUS +HwConfigure( + IN PFDO_DATA FdoData + ); + +NTSTATUS +HwSetupIAAddress( + IN PFDO_DATA FdoData + ); + +NTSTATUS +HwClearAllCounters( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICInitRecvBuffers( + IN PFDO_DATA FdoData + ); + +VOID +NICInitSendBuffers( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICLinkDetection( + IN PFDO_DATA FdoData + ); + +VOID +NICHandleQueryOidRequest( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + WDF_REQUEST_PARAMETERS *Params + ); + +VOID +NICHandleSetOidRequest( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + WDF_REQUEST_PARAMETERS *Params + ); + +VOID +NICServiceIndicateStatusIrp( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICGetStatsCounters( + IN PFDO_DATA FdoData, + IN NDIS_OID Oid, + OUT PULONG64 pCounter); + +NTSTATUS +NICSetPacketFilter( + IN PFDO_DATA FdoData, + IN ULONG PacketFilter); + +NTSTATUS +NICSetMulticastList( + IN PFDO_DATA FdoData); + +ULONG +NICGetMediaConnectStatus( + IN PFDO_DATA FdoData); + +NTSTATUS +NICWritePacket( + IN PFDO_DATA FdoData, + IN WDFDMATRANSACTION DmaTransaction, + IN PSCATTER_GATHER_LIST SGList + ); + +NTSTATUS +NICSendPacket( + IN PFDO_DATA FdoData, + IN PMP_TCB pMpTcb, + IN PSCATTER_GATHER_LIST ScatterGather); + +NTSTATUS +NICStartSend( + IN PFDO_DATA FdoData, + IN PMP_TCB pMpTcb); + +_Requires_lock_held_(FdoData->SendLock) +NTSTATUS +NICHandleSendInterrupt( + IN PFDO_DATA FdoData + ); + +VOID +NICCheckForQueuedSends( + IN PFDO_DATA FdoData + ); + +_IRQL_requires_same_ +_IRQL_requires_(DISPATCH_LEVEL) +_Requires_lock_held_(FdoData->SendLock) +VOID +NICFreeQueuedSendPackets( + IN PFDO_DATA FdoData + ); + +_Requires_lock_held_(FdoData->SendLock) +VOID +NICFreeBusySendPackets( + IN PFDO_DATA FdoData + ); + +VOID +NICCompleteSendRequest( + PFDO_DATA FdoData, + WDFREQUEST Request, + NTSTATUS Status, + ULONG Information + ); + +VOID +NICShutdown( + IN PFDO_DATA FdoData + ); + +_IRQL_requires_same_ +_IRQL_requires_(DISPATCH_LEVEL) +_Requires_lock_held_(FdoData->RcvLock) +VOID +NICHandleRecvInterrupt( + IN PFDO_DATA FdoData + ); + +_Requires_lock_held_(FdoData->RcvLock) +NTSTATUS +NICStartRecv( + IN PFDO_DATA FdoData + ); + +VOID +NICResetRecv( + IN PFDO_DATA FdoData + ); + +VOID +NICServiceReadIrps( + PFDO_DATA FdoData, + PMP_RFD *PacketArray, + ULONG PacketArrayCount + ); + +BOOLEAN +NICCheckForHang( + IN PFDO_DATA FdoData + ); + +NTSTATUS +NICReset( + IN PFDO_DATA FdoData + ); + +MEDIA_STATE +NICIndicateMediaState( + IN PFDO_DATA FdoData + ); + +MEDIA_STATE +NICGetMediaState( + IN PFDO_DATA FdoData + ); + +VOID +NICExtractPMInfoFromPciSpace( + PFDO_DATA FdoData, + PUCHAR pPciConfig + ); + +NTSTATUS +NICSetPower( + PFDO_DATA FdoData , + WDF_POWER_DEVICE_STATE PowerState + ); + +NTSTATUS +MPSetPowerD0( + PFDO_DATA FdoData + ); + +NTSTATUS +MPSetPowerLow( + PFDO_DATA FdoData, + WDF_POWER_DEVICE_STATE PowerState + ); + +VOID +NICFillPoMgmtCaps ( + IN PFDO_DATA FdoData, + IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities, + IN OUT PNDIS_STATUS pStatus, + IN OUT PULONG pulInfoLen + ); + +NTSTATUS +NICAddWakeUpPattern( + IN PFDO_DATA FdoData, + IN PVOID InformationBuffer, + IN UINT InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +NTSTATUS +NICRemoveWakeUpPattern( + IN PFDO_DATA FdoData, + IN PVOID InformationBuffer, + IN UINT InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +VOID +NICRemoveAllWakeUpPatterns( + PFDO_DATA FdoData + ); + +NTSTATUS +NICConfigureForWakeUp( + IN PFDO_DATA FdoData, + IN BOOLEAN AddPattern + ); + +NTSTATUS +NICGetIoctlRequest( + IN WDFQUEUE Queue, + IN ULONG FunctionCode, + OUT WDFREQUEST* Request + ); + +VOID +NICGetDeviceInfSettings( + IN OUT PFDO_DATA FdoData + ); + +NTSTATUS +NICInitiateDmaTransfer( + IN PFDO_DATA FdoData, + IN WDFREQUEST Request + ); + +VOID +NICStartWatchDogTimer( + IN PFDO_DATA FdoData + ); + +typedef +USHORT +(*PREAD_PORT)( + IN USHORT *Register + ); + +typedef +VOID +(*PWRITE_PORT)( + IN USHORT *Register, + IN USHORT Value + ); + +#endif + + diff --git a/general/pcidrv/kmdf/HW/nic_init.c b/general/pcidrv/kmdf/HW/nic_init.c new file mode 100644 index 00000000..947b1d65 --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_init.c @@ -0,0 +1,2378 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + NIC_INIT.c + +Abstract: + + Contains rotuines to do resource allocation and hardware + initialization & shutdown. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "nic_init.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, NICAllocateSoftwareResources) +#pragma alloc_text (PAGE, NICFreeSoftwareResources) +#pragma alloc_text (PAGE, NICMapHWResources) +#pragma alloc_text (PAGE, NICUnmapHWResources) +#pragma alloc_text (PAGE, NICGetDeviceInformation) +#pragma alloc_text (PAGE, NICReadAdapterInfo) +#pragma alloc_text (PAGE, NICAllocAdapterMemory) +#pragma alloc_text (PAGE, NICFreeAdapterMemory) +#pragma alloc_text (PAGE, NICInitRecvBuffers) +#pragma alloc_text (PAGE, NICSelfTest) +#pragma alloc_text (PAGE, HwClearAllCounters) +#pragma alloc_text (PAGE, NICAllocRfd) +#pragma alloc_text (PAGE, NICFreeRfd) +#pragma alloc_text (PAGE, NICFreeRfdWorkItem) +#endif + +PVOID LocalMmMapIoSpace( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ SIZE_T NumberOfBytes + ) +{ + typedef + PVOID + (*PFN_MM_MAP_IO_SPACE_EX) ( + _In_ PHYSICAL_ADDRESS PhysicalAddress, + _In_ SIZE_T NumberOfBytes, + _In_ ULONG Protect + ); + + UNICODE_STRING name; + PFN_MM_MAP_IO_SPACE_EX pMmMapIoSpaceEx; + + RtlInitUnicodeString(&name, L"MmMapIoSpaceEx"); + pMmMapIoSpaceEx = (PFN_MM_MAP_IO_SPACE_EX) (ULONG_PTR)MmGetSystemRoutineAddress(&name); + + if (pMmMapIoSpaceEx != NULL){ + // + // Call WIN10 API if available + // + return pMmMapIoSpaceEx(PhysicalAddress, + NumberOfBytes, + PAGE_READWRITE | PAGE_NOCACHE); + } + + return MmMapIoSpace(PhysicalAddress, NumberOfBytes, MmNonCached); +} + +NTSTATUS +NICAllocateSoftwareResources( + IN OUT PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This routine creates two parallel queues and 3 manual queues to hold + Read, Write and IOCTL requests. It also creates the interrupt object and + DMA object, and performs some additional initialization. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + NTSTATUS status; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDF_DMA_ENABLER_CONFIG dmaConfig; + ULONG maximumLength, maxLengthSupported; + WDF_OBJECT_ATTRIBUTES attributes; + ULONG maxMapRegistersRequired, miniMapRegisters; + ULONG mapRegistersAllocated; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "-->NICAllocateSoftwareResources\n"); + + PAGED_CODE(); + + // + // Initialize all the static data first to make sure we don't touch + // uninitialized list in the ContextCleanup callback if the + // AddDevice fails for any reason. + // + InitializeListHead(&FdoData->PoMgmt.PatternList); + InitializeListHead(&FdoData->RecvList); + + // + // This a global lock, to synchonize access to device context. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = FdoData->WdfDevice; + status = WdfSpinLockCreate(&attributes,&FdoData->Lock); + if(!NT_SUCCESS(status)){ + return status; + } + + + // + // Get the BUS_INTERFACE_STANDARD for our device so that we can + // read & write to PCI config space. + // + status = WdfFdoQueryForInterface(FdoData->WdfDevice, + &GUID_BUS_INTERFACE_STANDARD, + (PINTERFACE) &FdoData->BusInterface, + sizeof(BUS_INTERFACE_STANDARD), + 1, // Version + NULL); //InterfaceSpecificData + if (!NT_SUCCESS (status)){ + return status; + } + + // + // First make sure this is our device before doing whole lot + // of other things. + // + status = NICGetDeviceInformation(FdoData); + if (!NT_SUCCESS (status)){ + return status; + } + + NICGetDeviceInfSettings(FdoData); + + // + // We will create and configure a queue for receiving + // write requests. If these requests have to be pended for any + // reason, they will be forwarded to a manual queue created after this one. + // Framework automatically takes the responsibility of handling + // cancellation when the requests are waiting in the queue. This is + // a managed queue. So the framework will take care of queueing + // incoming requests when the pnp/power state transition takes place. + // Since we have configured the queue to dispatch all the specific requests + // we care about, we don't need a default queue. A default queue is + // used to receive requests that are not preconfigured to go to + // a specific queue. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchParallel + ); + + ioQueueConfig.EvtIoWrite = PciDrvEvtIoWrite; + + status = WdfIoQueueCreate( + FdoData->WdfDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WriteQueue // queue handle + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfIoQueueCreate failed 0x%x\n", status); + return status; + } + + status = WdfDeviceConfigureRequestDispatching( + FdoData->WdfDevice, + FdoData->WriteQueue, + WdfRequestTypeWrite); + + if(!NT_SUCCESS (status)){ + ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing write Queue 0x%x\n", status); + return status; + } + + // + // Manual internal queue for write reqeusts. This will be used to queue + // the write requests presented to us from the parallel default queue + // when we are low in TCB resources or when the device + // is busy doing link detection. + // Requests can be canceled while waiting in the queue without any + // notification to the driver. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchManual + ); + + status = WdfIoQueueCreate ( + FdoData->WdfDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->PendingWriteQueue + ); + + if(!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating manual write Queue 0x%x\n", status); + return status; + } + + + // + // Manual queue for read requests (WdfRequestTypeRead). We will configure the queue + // so that incoming read requests are directly dispatched to this queue. We will + // manually remove the requests from the queue and service them in our recv + // interrupt handler. WDF_IO_QUEUE_CONFIG_INIT initializes queues to be + // auto managed by default. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchManual + ); + + status = WdfIoQueueCreate ( + FdoData->WdfDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->PendingReadQueue + ); + + if(!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating read Queue 0x%x\n", status); + return status; + } + + status = WdfDeviceConfigureRequestDispatching( + FdoData->WdfDevice, + FdoData->PendingReadQueue, + WdfRequestTypeRead); + + if(!NT_SUCCESS (status)){ + ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing read Queue 0x%x\n", status); + return status; + } + + + // + // Parallel queue for device I/O control (WdfRequestTypeDeviceControl) requests. + // We will configure the queue so that all the incoming ioctl requests + // go directly to this queue. We will try to service the requests immediately. + // If we can't, we will forward the request to a manual queue created below + // and try to service it from a DPC when the appropriate event happens. + // + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchParallel + ); + + ioQueueConfig.EvtIoDeviceControl = PciDrvEvtIoDeviceControl; + + status = WdfIoQueueCreate ( + FdoData->WdfDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->IoctlQueue + ); + + if(!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error Creating ioctl Queue 0x%x\n", status); + return status; + } + + status = WdfDeviceConfigureRequestDispatching( + FdoData->WdfDevice, + FdoData->IoctlQueue, + WdfRequestTypeDeviceControl); + + if(!NT_SUCCESS (status)){ + ASSERT(NT_SUCCESS(status)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Error in config'ing ioctl Queue 0x%x\n", status); + return status; + } + + // + // Manual internal queue for device I/O control requests. This will be used to + // queue the ioctl requests presented to us from the parallel ioctl queue + // when we cannot handle them immediately. This is a managed queue. + // Requests be get canceled while waiting in the queue without any + // notification to the driver. + // + + WDF_IO_QUEUE_CONFIG_INIT( + &ioQueueConfig, + WdfIoQueueDispatchManual + ); + + status = WdfIoQueueCreate ( + FdoData->WdfDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->PendingIoctlQueue + ); + + if(!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "Error Creating manual Ioctl Queue 0x%x\n", status); + return status; + } + +#ifndef PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE + { + WDF_INTERRUPT_CONFIG interruptConfig; + + // + // Create WDFINTERRUPT object. + // + WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, + NICEvtInterruptIsr, + NICEvtInterruptDpc); + + // + // These first two callbacks will be called at DIRQL. Their job is to + // enable and disable interrupts. + // + interruptConfig.EvtInterruptEnable = NICEvtInterruptEnable; + interruptConfig.EvtInterruptDisable = NICEvtInterruptDisable; + + status = WdfInterruptCreate(FdoData->WdfDevice, + &interruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WdfInterrupt); + + if (!NT_SUCCESS (status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfInterruptCreate failed: %!STATUS!\n", status); + return status; + } + } +#endif + + // + // Alignment requirement must be 16-byte for this device. This alignment + // value will be inherits by the DMA enabler and used when you allocate + // common buffers. + // + WdfDeviceSetAlignmentRequirement( FdoData->WdfDevice, FILE_OCTA_ALIGNMENT); + + // + // Bare minimum number of map registers required to do + // a single NIC_MAX_PACKET_SIZE transfer. + // + miniMapRegisters = BYTES_TO_PAGES(NIC_MAX_PACKET_SIZE) + 1; + + // + // Maximum map registers required to do simultaneous transfer + // of all TCBs assuming each packet spanning NIC_MAX_PHYS_BUF_COUNT + // Buffer can span multiple MDLs. + // + maxMapRegistersRequired = FdoData->NumTcb * NIC_MAX_PHYS_BUF_COUNT; + + // + // The maximum length of buffer for maxMapRegistersRequired number of + // map registers would be. + // + maximumLength = (maxMapRegistersRequired-1) << PAGE_SHIFT; + + // + // Create a new DMA Object for Scatter/Gather DMA mode. + // + + WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, + WdfDmaProfileScatterGather, + maximumLength ); + + status = WdfDmaEnablerCreate( FdoData->WdfDevice, + &dmaConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WdfDmaEnabler ); + + if (!NT_SUCCESS (status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDmaEnblerCreate failed: %08X\n", status); + return status; + } + + maxLengthSupported = (ULONG) WdfDmaEnablerGetFragmentLength(FdoData->WdfDmaEnabler, + WdfDmaDirectionReadFromDevice); + + mapRegistersAllocated = BYTES_TO_PAGES(maxLengthSupported) + 1; + + if(mapRegistersAllocated < miniMapRegisters) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "Not enough map registers: Allocated %d, Required %d\n", + mapRegistersAllocated, miniMapRegisters); + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + + // + // Adjust our TCB count based on the MapRegisters we got. We will + // take the best case scenario where the packet is going to span + // no more than 2 pages. + // + FdoData->NumTcb = mapRegistersAllocated/miniMapRegisters; + + // + // Make sure it doesn't exceed NIC_MAX_TCBS. + // + FdoData->NumTcb = min(FdoData->NumTcb, NIC_MAX_TCBS); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "MapRegisters Allocated %d\n", mapRegistersAllocated); + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Adjusted TCB count is %d\n", FdoData->NumTcb); + + // + // Set the maximum allowable DMA Scatter/Gather list fragmentation size. + // + WdfDmaEnablerSetMaximumScatterGatherElements( FdoData->WdfDmaEnabler, + NIC_MAX_PHYS_BUF_COUNT ); + + // + // Create a lock to protect all the write-related buffer lists. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = FdoData->WdfDevice; + status = WdfSpinLockCreate(&attributes,&FdoData->SendLock); + if(!NT_SUCCESS(status)){ + return status; + } + + // + // Create a lock to protect all the read-related buffer lists + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = FdoData->WdfDevice; + status = WdfSpinLockCreate(&attributes,&FdoData->RcvLock); + if(!NT_SUCCESS(status)){ + return status; + } + + status = NICAllocAdapterMemory(FdoData); + + if (NT_SUCCESS(status)) { + + // + // This sets up send buffers. It doesn't actually touch hardware. + // + + NICInitSendBuffers(FdoData); + + // + // This sets up receive buffers. It doesn't actually touch hardware. + // + + status = NICInitRecvBuffers(FdoData); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- NICAllocateSoftwareResources\n"); + + return status; +} + + +NTSTATUS +NICFreeSoftwareResources( + IN OUT PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Free all the software resources. We shouldn't touch the hardware. + This functions is called in the context of EvtDeviceContextCleanup. + Most of the resources created in NICAllocateResources such as queues, + DMA enabler, SpinLocks, CommonBuffer, are already freed by + framework because they are associated with the WDFDEVICE directly + or indirectly as child objects. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "-->NICFreeSoftwareResources\n"); + + PAGED_CODE(); + + NICFreeAdapterMemory(FdoData); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<--NICFreeSoftwareResources\n"); + + return STATUS_SUCCESS; + +} + +NTSTATUS +NICMapHWResources( + IN OUT PFDO_DATA FdoData, + IN WDFCMRESLIST ResourcesRaw, + IN WDFCMRESLIST ResourcesTranslated + ) +/*++ +Routine Description: + + Gets the HW resources assigned by the bus driver and: + 1) Maps them to system address space. + 2) If PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE is defined, + it creates a WDFINTERRUPT object. + + Called during EvtDevicePrepareHardware callback. + + Three base address registers are supported by the 8255x: + 1) CSR Memory Mapped Base Address Register (BAR 0 at offset 10) + 2) CSR I/O Mapped Base Address Register (BAR 1 at offset 14) + 3) Flash Memory Mapped Base Address Register (BAR 2 at offset 18) + + The 8255x requires one BAR for I/O mapping and one BAR for memory + mapping of these registers anywhere within the 32-bit memory address space. + The driver determines which BAR (I/O or Memory) is used to access the + Control/Status Registers. + + Just for illustration, this driver maps both memory and I/O registers and + shows how to use READ_PORT_xxx or READ_REGISTER_xxx functions to perform + I/O in a platform independent basis. On some platforms, the I/O registers + can get mapped into memory space and your driver should be able to handle + this transparently. + + One BAR is also required to map the accesses to an optional Flash memory. + The 82557 implements this register regardless of the presence or absence + of a Flash chip on the adapter. The 82558 and 82559 implement this + register only if a bit is set in the EEPROM. The size of the space requested + by this register is 1Mbyte, and it is always mapped anywhere in the 32-bit + memory address space. + + Note: Although the 82558 only supports up to 64 Kbytes of Flash memory + and the 82559 only supports 128 Kbytes of Flash memory, the driver + requests 1 Mbyte of address space. Software should not access Flash + addresses above 64 Kbytes for the 82558 or 128 Kbytes for the 82559 + because Flash accesses above the limits are aliased to lower addresses. + +Arguments: + + FdoData Pointer to our FdoData + ResourcesRaw - Pointer to list of raw resources passed to + EvtDevicePrepareHardware callback + ResourcesTranslated - Pointer to list of translated resources passed to + EvtDevicePrepareHardware callback + +Return Value: + + NTSTATUS + +--*/ +{ + PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; + ULONG i; + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN bResPort = FALSE; + BOOLEAN bResInterrupt = FALSE; + BOOLEAN bResMemory = FALSE; + ULONG numberOfBARs = 0; + + UNREFERENCED_PARAMETER(ResourcesRaw); + + PAGED_CODE(); + + for (i=0; i<WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); + + if(!descriptor){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfResourceCmGetDescriptor"); + return STATUS_DEVICE_CONFIGURATION_ERROR; + } + + switch (descriptor->Type) { + + case CmResourceTypePort: + // + // We will increment the BAR count only for valid resources. We will + // not count the private device types added by the PCI bus driver. + // + numberOfBARs++; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "I/O mapped CSR: (%x) Length: (%d)\n", + descriptor->u.Port.Start.LowPart, + descriptor->u.Port.Length); + + // + // The resources are listed in the same order the as + // BARs in the config space, so this should be the second one. + // + if(numberOfBARs != 2) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "I/O mapped CSR is not in the right order\n"); + status = STATUS_DEVICE_CONFIGURATION_ERROR; + return status; + } + + // + // The port is in I/O space on this machine. + // We should use READ_PORT_Xxx, and WRITE_PORT_Xxx routines + // to read or write to the port. + // + + FdoData->IoBaseAddress = ULongToPtr(descriptor->u.Port.Start.LowPart); + FdoData->IoRange = descriptor->u.Port.Length; + // + // Since all our accesses are USHORT wide, we will create an accessor + // table just for these two functions. + // + FdoData->ReadPort = NICReadPortUShort; + FdoData->WritePort = NICWritePortUShort; + + bResPort = TRUE; + FdoData->MappedPorts = FALSE; + break; + + case CmResourceTypeMemory: + + numberOfBARs++; + + if(numberOfBARs == 1) { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Memory mapped CSR:(%x:%x) Length:(%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Start.HighPart, + descriptor->u.Memory.Length); + // + // Our CSR memory space should be 0x1000 in size. + // + ASSERT(descriptor->u.Memory.Length == 0x1000); + FdoData->MemPhysAddress = descriptor->u.Memory.Start; + FdoData->CSRAddress = LocalMmMapIoSpace( + descriptor->u.Memory.Start, + NIC_MAP_IOSPACE_LENGTH); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "CSRAddress=%p\n", FdoData->CSRAddress); + + bResMemory = TRUE; + + } else if(numberOfBARs == 2){ + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "I/O mapped CSR in Memory Space: (%x) Length: (%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Length); + // + // The port is in memory space on this machine. + // We should call LocalMmMapIoSpace to map the physical to virtual + // address, and also use the READ/WRITE_REGISTER_xxx function + // to read or write to the port. + // + + FdoData->IoBaseAddress = LocalMmMapIoSpace( + descriptor->u.Memory.Start, + descriptor->u.Memory.Length); + + FdoData->ReadPort = NICReadRegisterUShort; + FdoData->WritePort = NICWriteRegisterUShort; + FdoData->MappedPorts = TRUE; + bResPort = TRUE; + + } else if(numberOfBARs == 3){ + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Flash memory:(%x:%x) Length:(%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Start.HighPart, + descriptor->u.Memory.Length); + // + // Our flash memory should be 1MB in size. Since we don't + // access the memory, let us not bother mapping it. + // + //ASSERT(descriptor->u.Memory.Length == 0x100000); + } else { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "Memory Resources are not in the right order\n"); + status = STATUS_DEVICE_CONFIGURATION_ERROR; + return status; + } + + break; + + case CmResourceTypeInterrupt: + + ASSERT(!bResInterrupt); + +#ifdef PCIDRV_CREATE_INTERRUPT_IN_PREPARE_HARDWARE + { + WDF_INTERRUPT_CONFIG interruptConfig; + + // + // Create WDFINTERRUPT object. + // + WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, + NICEvtInterruptIsr, + NICEvtInterruptDpc); + + // + // These first two callbacks will be called at DIRQL. Their job is to + // enable and disable interrupts. + // + interruptConfig.EvtInterruptEnable = NICEvtInterruptEnable; + interruptConfig.EvtInterruptDisable = NICEvtInterruptDisable; + interruptConfig.InterruptTranslated = descriptor; + interruptConfig.InterruptRaw = + WdfCmResourceListGetDescriptor(ResourcesRaw, i); + + status = WdfInterruptCreate(FdoData->WdfDevice, + &interruptConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WdfInterrupt); + + if (!NT_SUCCESS (status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfInterruptCreate failed: %!STATUS!\n", status); + return status; + } + } +#endif + + bResInterrupt = TRUE; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "Interrupt level: 0x%0x, Vector: 0x%0x\n", + descriptor->u.Interrupt.Level, + descriptor->u.Interrupt.Vector); + + break; + + default: + // + // This could be device-private type added by the PCI bus driver. We + // shouldn't filter this or change the information contained in it. + // + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Unhandled resource type (0x%x)\n", + descriptor->Type); + break; + } + + } + + // + // Make sure we got all the 3 resources to work with. + // + if (!(bResPort && bResInterrupt && bResMemory)) { + status = STATUS_DEVICE_CONFIGURATION_ERROR; + return status; + } + + // + // Read additional info from NIC such as MAC address + // + status = NICReadAdapterInfo(FdoData); + if (status != STATUS_SUCCESS) + { + return status; + } + + // + // Test our adapter hardware + // + status = NICSelfTest(FdoData); + if (status != STATUS_SUCCESS) + { + return status; + } + + return status; + +} + +NTSTATUS +NICUnmapHWResources( + IN OUT PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Disconnect the interrupt and unmap all the memory and I/O resources. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + PAGED_CODE(); + + // + // Free hardware resources + // + if (FdoData->CSRAddress) + { + MmUnmapIoSpace(FdoData->CSRAddress, NIC_MAP_IOSPACE_LENGTH); + FdoData->CSRAddress = NULL; + } + + if(FdoData->MappedPorts){ + MmUnmapIoSpace(FdoData->IoBaseAddress, FdoData->IoRange); + FdoData->IoBaseAddress = NULL; + } + + return STATUS_SUCCESS; + +} + + +NTSTATUS +NICGetDeviceInformation( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This function reads the PCI config space and make sure that it's our + device and stores the device IDs and power information in the device + extension. Should be done in the StartDevice. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) UCHAR buffer[NIC_PCI_E100_HDR_LENGTH ]; + PPCI_COMMON_CONFIG pPciConfig = (PPCI_COMMON_CONFIG) buffer; + USHORT usPciCommand; + ULONG bytesRead =0; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "---> NICGetDeviceInformation\n"); + + PAGED_CODE(); + + RtlZeroMemory(buffer, sizeof(buffer)); + bytesRead = FdoData->BusInterface.GetBusData( + FdoData->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, //READ + buffer, + FIELD_OFFSET(PCI_COMMON_CONFIG, VendorID), + NIC_PCI_E100_HDR_LENGTH); + + if (bytesRead != NIC_PCI_E100_HDR_LENGTH) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "GetBusData (NIC_PCI_E100_HDR_LENGTH) failed =%d\n", + bytesRead); + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Is this our device? + // + + if (pPciConfig->VendorID != NIC_PCI_VENDOR_ID || + pPciConfig->DeviceID != NIC_PCI_DEVICE_ID) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "VendorID/DeviceID don't match - %x/%x\n", + pPciConfig->VendorID, pPciConfig->DeviceID); + //return STATUS_DEVICE_DOES_NOT_EXIST; + + } + + // + // save TRACE_LEVEL_INFORMATION from config space + // + FdoData->RevsionID = pPciConfig->RevisionID; + FdoData->SubVendorID = pPciConfig->u.type0.SubVendorID; + FdoData->SubSystemID = pPciConfig->u.type0.SubSystemID; + + NICExtractPMInfoFromPciSpace (FdoData, (PUCHAR)pPciConfig); + + usPciCommand = pPciConfig->Command; + + if ((usPciCommand & PCI_ENABLE_WRITE_AND_INVALIDATE) && (FdoData->MWIEnable)){ + FdoData->MWIEnable = TRUE; + } else { + FdoData->MWIEnable = FALSE; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICGetDeviceInformation\n"); + + return status; +} + +NTSTATUS +NICReadAdapterInfo( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Read the mac addresss from the adapter + +Arguments: + + FdoData Pointer to our device context + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + USHORT usValue; + int i; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICReadAdapterInfo\n"); + + PAGED_CODE(); + + FdoData->EepromAddressSize = GetEEpromAddressSize( + GetEEpromSize(FdoData, (PUCHAR)FdoData->IoBaseAddress)); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "EepromAddressSize = %d\n", + FdoData->EepromAddressSize); + + + // + // Read node address from the EEPROM + // + for (i=0; i< ETH_LENGTH_OF_ADDRESS; i += 2) + { + usValue = ReadEEprom(FdoData, (PUCHAR)FdoData->IoBaseAddress, + (USHORT)(EEPROM_NODE_ADDRESS_BYTE_0 + (i/2)), + FdoData->EepromAddressSize); + + *((PUSHORT)(&FdoData->PermanentAddress[i])) = usValue; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + FdoData->PermanentAddress[0], FdoData->PermanentAddress[1], + FdoData->PermanentAddress[2], FdoData->PermanentAddress[3], + FdoData->PermanentAddress[4], FdoData->PermanentAddress[5]); + + if (ETH_IS_MULTICAST(FdoData->PermanentAddress) || + ETH_IS_BROADCAST(FdoData->PermanentAddress)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Permanent address is invalid\n"); + + status = STATUS_INVALID_ADDRESS; + } + else + { + if (!FdoData->bOverrideAddress) + { + ETH_COPY_NETWORK_ADDRESS(FdoData->CurrentAddress, FdoData->PermanentAddress); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "Current Address = %02x-%02x-%02x-%02x-%02x-%02x\n", + FdoData->CurrentAddress[0], FdoData->CurrentAddress[1], + FdoData->CurrentAddress[2], FdoData->CurrentAddress[3], + FdoData->CurrentAddress[4], FdoData->CurrentAddress[5]); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICReadAdapterInfo, status=%x\n", + status); + + return status; +} + + + +NTSTATUS +NICAllocAdapterMemory( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Allocate all the memory blocks for send, receive and others + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PUCHAR pMem; + ULONG MemPhys; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICAllocAdapterMemory\n"); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NumTcb=%d\n", FdoData->NumTcb); + + do + { + // + // Send + Misc + // + // + // Allocate MP_TCB's + // + status = RtlULongMult(FdoData->NumTcb, + sizeof(MP_TCB), + &FdoData->MpTcbMemSize); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "RtlUlongMult failed 0x%x\n", status); + break; + } + + pMem = ExAllocatePoolWithTag(NonPagedPool, + FdoData->MpTcbMemSize, PCIDRV_POOL_TAG); + if (NULL == pMem ) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "Failed to allocate MP_TCB's\n"); + break; + } + + RtlZeroMemory(pMem, FdoData->MpTcbMemSize); + FdoData->MpTcbMem = pMem; + + // HW_START + + // + // Allocate shared memory for send + // + FdoData->HwSendMemAllocSize = FdoData->NumTcb * (sizeof(TXCB_STRUC) + + NIC_MAX_PHYS_BUF_COUNT * sizeof(TBD_STRUC)); + + _Analysis_assume_(FdoData->HwSendMemAllocSize > 0); + status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler, + FdoData->HwSendMemAllocSize, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WdfSendCommonBuffer ); + + if (status != STATUS_SUCCESS) + { + FdoData->HwSendMemAllocSize = 0; + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfCommonBufferCreate(Send) " + "failed %08X\n", status ); + break; + } + + FdoData->HwSendMemAllocVa = WdfCommonBufferGetAlignedVirtualAddress( + FdoData->WdfSendCommonBuffer); + + FdoData->HwSendMemAllocLa = WdfCommonBufferGetAlignedLogicalAddress( + FdoData->WdfSendCommonBuffer); + + RtlZeroMemory(FdoData->HwSendMemAllocVa, + FdoData->HwSendMemAllocSize); + + // + // Allocate shared memory for other uses + // + // FIXME-NOTE: The WdfCommonBufferGetAlignedVirtualAddress functions + // return device-specified aligned pointers...use them. + // + FdoData->HwMiscMemAllocSize = + sizeof(SELF_TEST_STRUC) + ALIGN_16 + + sizeof(DUMP_AREA_STRUC) + ALIGN_16 + + sizeof(NON_TRANSMIT_CB) + ALIGN_16 + + sizeof(ERR_COUNT_STRUC) + ALIGN_16; + + // + // Allocate the shared memory for the command block data structures. + // + status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler, + FdoData->HwMiscMemAllocSize, + WDF_NO_OBJECT_ATTRIBUTES, + &FdoData->WdfMiscCommonBuffer ); + + if (status != STATUS_SUCCESS) + { + FdoData->HwMiscMemAllocSize = 0; + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "WdfCommonBufferCreate(Misc) " + "failed %08X\n", status ); + break; + } + + FdoData->HwMiscMemAllocVa = WdfCommonBufferGetAlignedVirtualAddress( + FdoData->WdfMiscCommonBuffer); + + FdoData->HwMiscMemAllocLa = WdfCommonBufferGetAlignedLogicalAddress( + FdoData->WdfMiscCommonBuffer); + + RtlZeroMemory(FdoData->HwMiscMemAllocVa, + FdoData->HwMiscMemAllocSize); + + pMem = FdoData->HwMiscMemAllocVa; + MemPhys = FdoData->HwMiscMemAllocLa.LowPart ; + + FdoData->SelfTest = (PSELF_TEST_STRUC)MP_ALIGNMEM(pMem, ALIGN_16); + FdoData->SelfTestPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16); + pMem = (PUCHAR)FdoData->SelfTest + sizeof(SELF_TEST_STRUC); + MemPhys = FdoData->SelfTestPhys + sizeof(SELF_TEST_STRUC); + + FdoData->NonTxCmdBlock = (PNON_TRANSMIT_CB)MP_ALIGNMEM(pMem, ALIGN_16); + FdoData->NonTxCmdBlockPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16); + pMem = (PUCHAR)FdoData->NonTxCmdBlock + sizeof(NON_TRANSMIT_CB); + MemPhys = FdoData->NonTxCmdBlockPhys + sizeof(NON_TRANSMIT_CB); + + FdoData->DumpSpace = (PDUMP_AREA_STRUC)MP_ALIGNMEM(pMem, ALIGN_16); + FdoData->DumpSpacePhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16); + pMem = (PUCHAR)FdoData->DumpSpace + sizeof(DUMP_AREA_STRUC); + MemPhys = FdoData->DumpSpacePhys + sizeof(DUMP_AREA_STRUC); + + FdoData->StatsCounters = (PERR_COUNT_STRUC)MP_ALIGNMEM(pMem, ALIGN_16); + FdoData->StatsCounterPhys = MP_ALIGNMEM_PHYS(MemPhys, ALIGN_16); + + // HW_END + + // + // Recv + // + + // set the max number of RFDs + // disable the RFD grow/shrink scheme if user specifies a NumRfd value + // larger than NIC_MAX_GROW_RFDS + FdoData->MaxNumRfd = max(FdoData->NumRfd, NIC_MAX_GROW_RFDS); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "NumRfd = %d\n", FdoData->NumRfd); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "MaxNumRfd = %d\n", FdoData->MaxNumRfd); + + // + // The driver should allocate more data than sizeof(RFD_STRUC) to allow the + // driver to align the data(after ethernet header) at 8 byte boundary + // + FdoData->HwRfdSize = sizeof(RFD_STRUC) + MORE_DATA_FOR_ALIGN; + + status = STATUS_SUCCESS; + + } WHILE( FALSE ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "<-- NICAllocAdapterMemory, status=%x\n", status); + + return status; + +} + +VOID +NICFreeAdapterMemory( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Free all the resources and MP_ADAPTER data block + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + None + +--*/ +{ + PMP_RFD pMpRfd; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICFreeAdapterMemory\n"); + + PAGED_CODE(); + + // No active and waiting sends + ASSERT(FdoData->nBusySend == 0); + ASSERT(FdoData->nWaitSend == 0); + + ASSERT(FdoData->nReadyRecv == FdoData->CurrNumRfd); + + while (!IsListEmpty(&FdoData->RecvList)) + { + pMpRfd = (PMP_RFD)RemoveHeadList(&FdoData->RecvList); + + pMpRfd->DeleteCommonBuffer = FALSE; + + NICFreeRfd(FdoData, pMpRfd); + } + + FdoData->WdfSendCommonBuffer = NULL; + FdoData->HwSendMemAllocVa = NULL; + + FdoData->WdfMiscCommonBuffer = NULL; + FdoData->HwMiscMemAllocVa = NULL; + FdoData->SelfTest = NULL; + FdoData->StatsCounters = NULL; + FdoData->NonTxCmdBlock = NULL; + FdoData->DumpSpace = NULL; + + // Free the memory for MP_TCB structures + if (FdoData->MpTcbMem) + { + ExFreePoolWithTag(FdoData->MpTcbMem, PCIDRV_POOL_TAG); + FdoData->MpTcbMem = NULL; + } + + //Free all the wake up patterns on this adapter + NICRemoveAllWakeUpPatterns(FdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICFreeAdapterMemory\n"); +} + + + +VOID +NICInitSendBuffers( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Initialize send data structures. Can be called at DISPATCH_LEVEL. + +Arguments: + + FdoData - Pointer to our adapter context + +Return Value: + + None + +--*/ +{ + PMP_TCB pMpTcb; + PHW_TCB pHwTcb; + ULONG HwTcbPhys; + ULONG TcbCount; + + PTBD_STRUC pHwTbd; + ULONG HwTbdPhys; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitSendBuffers\n"); + + FdoData->TransmitIdle = TRUE; + FdoData->ResumeWait = TRUE; + + // Setup the initial pointers to the SW and HW TCB data space + pMpTcb = (PMP_TCB) FdoData->MpTcbMem; + pHwTcb = (PHW_TCB) FdoData->HwSendMemAllocVa; + HwTcbPhys = FdoData->HwSendMemAllocLa.LowPart; + + // Setup the initial pointers to the TBD data space. + // TBDs are located immediately following the TCBs + pHwTbd = (PTBD_STRUC) (FdoData->HwSendMemAllocVa + + (sizeof(TXCB_STRUC) * FdoData->NumTcb)); + HwTbdPhys = HwTcbPhys + (sizeof(TXCB_STRUC) * FdoData->NumTcb); + + _Analysis_assume_(FdoData->HwSendMemAllocSize >= (FdoData->NumTcb * sizeof(HW_TCB))); + _Analysis_assume_(FdoData->MpTcbMemSize >= (FdoData->NumTcb * sizeof(MP_TCB))); + + // Go through and set up each TCB + for (TcbCount = 0; TcbCount < FdoData->NumTcb; TcbCount++) + { + pMpTcb->HwTcb = pHwTcb; // save ptr to HW TCB + pMpTcb->HwTcbPhys = HwTcbPhys; // save HW TCB physical address + pMpTcb->HwTbd = pHwTbd; // save ptr to TBD array + pMpTcb->HwTbdPhys = HwTbdPhys; // save TBD array physical address + + if (TcbCount){ + pMpTcb->PrevHwTcb = pHwTcb - 1; + } + else { + pMpTcb->PrevHwTcb = (PHW_TCB)((PUCHAR)FdoData->HwSendMemAllocVa + + ((FdoData->NumTcb - 1) * sizeof(HW_TCB))); + } + pHwTcb->TxCbHeader.CbStatus = 0; // clear the status + pHwTcb->TxCbHeader.CbCommand = CB_EL_BIT | CB_TX_SF_BIT | CB_TRANSMIT; + + + // Set the link pointer in HW TCB to the next TCB in the chain. + // If this is the last TCB in the chain, then set it to the first TCB. + if (TcbCount < FdoData->NumTcb - 1) + { + pMpTcb->Next = pMpTcb + 1; + pHwTcb->TxCbHeader.CbLinkPointer = HwTcbPhys + sizeof(HW_TCB); + } + else + { + pMpTcb->Next = (PMP_TCB) FdoData->MpTcbMem; + pHwTcb->TxCbHeader.CbLinkPointer = + FdoData->HwSendMemAllocLa.LowPart; + } + + pHwTcb->TxCbThreshold = (UCHAR) FdoData->AiThreshold; + pHwTcb->TxCbTbdPointer = HwTbdPhys; + + pMpTcb++; + pHwTcb++; + HwTcbPhys += sizeof(TXCB_STRUC); + pHwTbd = (PTBD_STRUC)((PUCHAR)pHwTbd + sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT); + HwTbdPhys += sizeof(TBD_STRUC) * NIC_MAX_PHYS_BUF_COUNT; + } + + // set the TCB head/tail indexes + // head is the olded one to free, tail is the next one to use + FdoData->CurrSendHead = (PMP_TCB) FdoData->MpTcbMem; + FdoData->CurrSendTail = (PMP_TCB) FdoData->MpTcbMem; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitSendBuffers\n"); +} + +NTSTATUS +NICInitRecvBuffers( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Initialize receive data structures + +Arguments: + + FdoData - Pointer to our adapter context + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; + PMP_RFD pMpRfd; + ULONG RfdCount; + WDFMEMORY memoryHdl; + PDRIVER_CONTEXT driverContext = GetDriverContext(WdfGetDriver()); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitRecvBuffers\n"); + + PAGED_CODE(); + + // Setup each RFD + for (RfdCount = 0; RfdCount < FdoData->NumRfd; RfdCount++) + { + status = WdfMemoryCreateFromLookaside( + driverContext->RecvLookaside, + &memoryHdl + ); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Failed to get lookaside buffer\n"); + continue; + } + pMpRfd = WdfMemoryGetBuffer(memoryHdl, NULL); + if (!pMpRfd) + { + //ErrorValue = ERRLOG_OUT_OF_LOOKASIDE_MEMORY; + continue; + } + pMpRfd->LookasideMemoryHdl = memoryHdl; + // + // Allocate the shared memory for this RFD. + // + _Analysis_assume_(FdoData->HwRfdSize > 0); + status = WdfCommonBufferCreate( FdoData->WdfDmaEnabler, + FdoData->HwRfdSize, + WDF_NO_OBJECT_ATTRIBUTES, + &pMpRfd->WdfCommonBuffer ); + + if (status != STATUS_SUCCESS) + { + pMpRfd->WdfCommonBuffer = NULL; + WdfObjectDelete(pMpRfd->LookasideMemoryHdl); + continue; + } + + pMpRfd->OriginalHwRfd = + WdfCommonBufferGetAlignedVirtualAddress(pMpRfd->WdfCommonBuffer); + + pMpRfd->OriginalHwRfdLa = + WdfCommonBufferGetAlignedLogicalAddress(pMpRfd->WdfCommonBuffer); + + // + // Get a 8-byts aligned memory from the original HwRfd + // + pMpRfd->HwRfd = (PHW_RFD)DATA_ALIGN(pMpRfd->OriginalHwRfd); + + // + // Now HwRfd is already 8-bytes aligned, and the size of HwPfd + // header(not data part) is a multiple of 8, + // If we shift HwRfd 0xA bytes up, the Ethernet header size + // is 14 bytes long, then the data will be at + // 8 byte boundary. + // + pMpRfd->HwRfd = (PHW_RFD)((PUCHAR)(pMpRfd->HwRfd) + HWRFD_SHIFT_OFFSET); + + // + // Update physical address accordingly + // + pMpRfd->HwRfdLa.QuadPart = pMpRfd->OriginalHwRfdLa.QuadPart + + BYTES_SHIFT(pMpRfd->HwRfd, pMpRfd->OriginalHwRfd); + + status = NICAllocRfd(FdoData, pMpRfd); + if (!NT_SUCCESS(status)) + { + WdfObjectDelete(pMpRfd->LookasideMemoryHdl); + continue; + } + // + // Add this RFD to the RecvList + // + FdoData->CurrNumRfd++; + NICReturnRFD(FdoData, pMpRfd); + } + + if (FdoData->CurrNumRfd > NIC_MIN_RFDS) + { + status = STATUS_SUCCESS; + } + + // + // FdoData->CurrNumRfd < NIC_MIN_RFDs + // + if (status != STATUS_SUCCESS) + { + // TODO: Log an entry into the eventlog + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitRecvBuffers, status=%x\n", status); + + return status; +} + +NTSTATUS +NICAllocRfd( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ) +/*++ +Routine Description: + + Allocate NDIS_PACKET and NDIS_BUFFER associated with a RFD. + Can be called at DISPATCH_LEVEL. + +Arguments: + + FdoData Pointer to our adapter + pMpRfd pointer to a RFD + +Return Value: + + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PHW_RFD pHwRfd; + + UNREFERENCED_PARAMETER(FdoData); + + PAGED_CODE(); + + do{ + pHwRfd = pMpRfd->HwRfd; + pMpRfd->HwRfdPhys = pMpRfd->HwRfdLa.LowPart; + + pMpRfd->Flags = 0; + + pMpRfd->Mdl = IoAllocateMdl((PVOID)&pHwRfd->RfdBuffer.RxMacHeader, + NIC_MAX_PACKET_SIZE, + FALSE, + FALSE, + NULL); + if (!pMpRfd->Mdl) + { + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + MmBuildMdlForNonPagedPool(pMpRfd->Mdl); + + pMpRfd->Buffer = &pHwRfd->RfdBuffer.RxMacHeader; + + // Init each RFD header + pHwRfd->RfdRbdPointer = DRIVER_NULL; + pHwRfd->RfdSize = NIC_MAX_PACKET_SIZE; + + } WHILE (FALSE); + + + if (!NT_SUCCESS(status)) + { + if (pMpRfd->WdfCommonBuffer) + { + // + // Free HwRfd, we need to free the original memory + // pointed by OriginalHwRfd. + // + WdfObjectDelete( pMpRfd->WdfCommonBuffer ); + + pMpRfd->WdfCommonBuffer = NULL; + pMpRfd->HwRfd = NULL; + pMpRfd->OriginalHwRfd = NULL; + + pMpRfd->DeleteCommonBuffer = TRUE; + } + } + + return status; + +} + +VOID +NICFreeRfd( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ) +/*++ +Routine Description: + + Free a RFD. + Can be called at DISPATCH_LEVEL. + +Arguments: + + FdoData Pointer to our adapter + pMpRfd Pointer to a RFD + +Return Value: + + None + +--*/ +{ + UNREFERENCED_PARAMETER(FdoData); + PAGED_CODE(); + + ASSERT(pMpRfd->HwRfd); + ASSERT(pMpRfd->Mdl); + + IoFreeMdl(pMpRfd->Mdl); + + // + // Free HwRfd, we need to free the original memory pointed + // by OriginalHwRfd. + // + if (pMpRfd->DeleteCommonBuffer == TRUE) { + + WdfObjectDelete( pMpRfd->WdfCommonBuffer ); + } + + pMpRfd->WdfCommonBuffer = NULL; + pMpRfd->HwRfd = NULL; + pMpRfd->OriginalHwRfd = NULL; + + WdfObjectDelete(pMpRfd->LookasideMemoryHdl); +} + +VOID +NICAllocRfdWorkItem( + IN WDFWORKITEM WorkItem +) +/*++ + +Routine Description: + + Worker routine to allocate memory for RFD at PASSIVE_LEVEL. + +Arguments: + + WorkItem - Handle to framework item object. + +Return Value: + + VOID + +--*/ +{ + PFDO_DATA FdoData; + //KIRQL oldIrql; + PMP_RFD TempMpRfd; + NTSTATUS status; + PWORKER_ITEM_CONTEXT item; + WDFMEMORY tempMpRfdMemHdl; + PDRIVER_CONTEXT driverContext = GetDriverContext(WdfGetDriver()); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICAllocRfdWorkItem\n"); + + item = GetWorkItemContext(WorkItem); + FdoData = item->FdoData; + + status = WdfMemoryCreateFromLookaside(driverContext->RecvLookaside, &tempMpRfdMemHdl); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "Failed to get lookaside buffer\n"); + return ; + } + TempMpRfd = WdfMemoryGetBuffer(tempMpRfdMemHdl, NULL); + if (TempMpRfd) + { + TempMpRfd->LookasideMemoryHdl = tempMpRfdMemHdl; + // + // Allocate the shared memory for this RFD. + // + _Analysis_assume_(FdoData->HwRfdSize > 0); + status = WdfCommonBufferCreate(FdoData->WdfDmaEnabler, + FdoData->HwRfdSize, + WDF_NO_OBJECT_ATTRIBUTES, + &TempMpRfd->WdfCommonBuffer); + + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, + "WdfCommonBufferCreate failed %X\n", status); + WdfObjectDelete(TempMpRfd->LookasideMemoryHdl); + goto Exit; + } + + TempMpRfd->OriginalHwRfd = + WdfCommonBufferGetAlignedVirtualAddress( + TempMpRfd->WdfCommonBuffer); + + TempMpRfd->OriginalHwRfdLa = + WdfCommonBufferGetAlignedLogicalAddress( + TempMpRfd->WdfCommonBuffer); + + // + // First get a HwRfd at 8 byte boundary from OriginalHwRfd + // + TempMpRfd->HwRfd = (PHW_RFD)DATA_ALIGN(TempMpRfd->OriginalHwRfd); + // + // Then shift HwRfd so that the data(after ethernet header) is at 8 bytes boundary + // + TempMpRfd->HwRfd = (PHW_RFD)((PUCHAR)TempMpRfd->HwRfd + HWRFD_SHIFT_OFFSET); + // + // Update physical address as well + // + TempMpRfd->HwRfdLa.QuadPart = TempMpRfd->OriginalHwRfdLa.QuadPart + + BYTES_SHIFT(TempMpRfd->HwRfd, TempMpRfd->OriginalHwRfd); + + status = NICAllocRfd(FdoData, TempMpRfd); + if (!NT_SUCCESS(status)) + { + // + // NICAllocRfd frees common buffer when it returns an TRACE_LEVEL_ERROR. + // So, let us not worry about freeing that here. + // + WdfObjectDelete(TempMpRfd->LookasideMemoryHdl); + TraceEvents(TRACE_LEVEL_ERROR, DBG_READ, "Recv: NICAllocRfd failed %x\n", status); + goto Exit; + } + + + WdfSpinLockAcquire(FdoData->RcvLock); + + // + // Add this RFD to the RecvList + // + FdoData->CurrNumRfd++; + NICReturnRFD(FdoData, TempMpRfd); + + + WdfSpinLockRelease(FdoData->RcvLock); + + ASSERT(FdoData->CurrNumRfd <= FdoData->MaxNumRfd); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, + "CurrNumRfd=%d\n", FdoData->CurrNumRfd); + + } + +Exit: + FdoData->AllocNewRfd = FALSE; + + WdfObjectDelete(WorkItem); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICAllocRfdWorkItem\n"); + + return; +} + +VOID +NICFreeRfdWorkItem( + IN WDFWORKITEM WorkItem +) +/*++ + +Routine Description: + + Worker routine to RFD memory at PASSIVE_LEVEL. + +Arguments: + + WorkItem - Handle to framework item object. + +Return Value: + + VOID + +--*/ +{ + PFDO_DATA fdoData; + PMP_RFD pMpRfd; + PWORKER_ITEM_CONTEXT item; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICFreeRfdWorkItem\n"); + + PAGED_CODE(); + + item = GetWorkItemContext(WorkItem); + fdoData = item->FdoData; + pMpRfd = (PMP_RFD)item->Argument1; + + NICFreeRfd(fdoData, pMpRfd); + + WdfObjectDelete(WorkItem); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICFreeRfdWorkItem\n"); + + return; +} + + + +NTSTATUS +NICSelfTest( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Perform a NIC self-test + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + NT status code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG SelfTestCommandCode; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICSelfTest\n"); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "SelfTest=%p, SelfTestPhys=%x\n", + FdoData->SelfTest, FdoData->SelfTestPhys); + + // + // Issue a software reset to the adapter + // + HwSoftwareReset(FdoData); + + // + // Execute The PORT Self Test Command On The 82558. + // + ASSERT(FdoData->SelfTestPhys != 0); + SelfTestCommandCode = FdoData->SelfTestPhys; + + // + // Setup SELF TEST Command Code in D3 - D0 + // + SelfTestCommandCode |= PORT_SELFTEST; + + // + // Initialize the self-test signature and results DWORDS + // + FdoData->SelfTest->StSignature = 0; + FdoData->SelfTest->StResults = 0xffffffff; + + // + // Do the port command + // + FdoData->CSRAddress->Port = SelfTestCommandCode; + + MP_STALL_EXECUTION(NIC_DELAY_POST_SELF_TEST_MS); + + // + // if The First Self Test DWORD Still Zero, We've timed out. If the second + // DWORD is not zero then we have an TRACE_LEVEL_ERROR. + // + if ((FdoData->SelfTest->StSignature == 0) || (FdoData->SelfTest->StResults != 0)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, "StSignature=%x, StResults=%x\n", + FdoData->SelfTest->StSignature, FdoData->SelfTest->StResults); + + status = STATUS_DEVICE_CONFIGURATION_ERROR; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICSelfTest, status=%x\n", status); + + return status; +} + +NTSTATUS +NICInitializeAdapter( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Initialize the adapter and set up everything + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + NT Status Code + +--*/ +{ + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "--> NICInitializeAdapter\n"); + + do + { + + // set up our link indication variable + // it doesn't matter what this is right now because it will be + // set correctly if link fails + FdoData->MediaState = Connected; + + // Issue a software reset to the D100 + HwSoftwareReset(FdoData); + + // Load the CU BASE (set to 0, because we use linear mode) + FdoData->CSRAddress->ScbGeneralPointer = 0; + status = D100IssueScbCommand(FdoData, SCB_CUC_LOAD_BASE, FALSE); + if (status != STATUS_SUCCESS) + { + break; + } + + // Wait for the SCB command word to clear before we set the general pointer + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + // Load the RU BASE (set to 0, because we use linear mode) + FdoData->CSRAddress->ScbGeneralPointer = 0; + status = D100IssueScbCommand(FdoData, SCB_RUC_LOAD_BASE, FALSE); + if (status != STATUS_SUCCESS) + { + break; + } + + // Configure the adapter + status = HwConfigure(FdoData); + if (status != STATUS_SUCCESS) + { + break; + } + + status = HwSetupIAAddress(FdoData); + if (status != STATUS_SUCCESS) + { + break; + } + + // Clear the internal counters + HwClearAllCounters(FdoData); + + + } WHILE (FALSE); + + if (status != STATUS_SUCCESS) + { + // TODO: Log an entry into the eventlog + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "<-- NICInitializeAdapter, Status=%x\n", status); + + return status; +} + +VOID +NICShutdown( + IN PFDO_DATA FdoData) +/*++ + +Routine Description: + + Shutdown the device + +Arguments: + + FdoData - Pointer to our adapter + +Return Value: + + None + +--*/ +{ + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "---> NICShutdown\n"); + + if(FdoData->CSRAddress) { + // + // Disable interrupt and issue a full reset + // + NICDisableInterrupt(FdoData); + NICIssueFullReset(FdoData); + // + // Reset the PHY chip. We do this so that after a warm boot, the PHY will + // be in a known state, with auto-negotiation enabled. + // + ResetPhy(FdoData); + } + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<--- NICShutdown\n"); +} + +VOID +HwSoftwareReset( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Issue a software reset to the hardware + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + None + +--*/ +{ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwSoftwareReset\n"); + + // Issue a PORT command with a data word of 0 + FdoData->CSRAddress->Port = PORT_SOFTWARE_RESET; + + // wait after the port reset command + KeStallExecutionProcessor(NIC_DELAY_POST_RESET); + + // Mask off our interrupt line -- its unmasked after reset + NICDisableInterrupt(FdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- HwSoftwareReset\n"); +} + + + +NTSTATUS +HwConfigure( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Configure the hardware + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + NT Status + + +--*/ +{ + NTSTATUS status; + PCB_HEADER_STRUC NonTxCmdBlockHdr = + (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock; + UINT i; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwConfigure\n"); + + // + // Init the packet filter to nothing. + // + FdoData->OldPacketFilter = FdoData->PacketFilter; + FdoData->PacketFilter = 0; + + // + // Store the current setting for BROADCAST/PROMISCUOS modes + FdoData->OldParameterField = CB_557_CFIG_DEFAULT_PARM15; + + // Setup the non-transmit command block header for the configure command. + NonTxCmdBlockHdr->CbStatus = 0; + NonTxCmdBlockHdr->CbCommand = CB_CONFIGURE; + NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL; + + // Fill in the configure command data. + + // First fill in the static (end user can't change) config bytes + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = CB_557_CFIG_DEFAULT_PARM21; + + // Now fill in the rest of the configuration bytes (the bytes that contain + // user configurable parameters). + + // Set the Tx and Rx Fifo limits + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] = + (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo); + + if (FdoData->MWIEnable) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE; + } + + // Set the Tx and Rx DMA maximum byte count fields. + if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount)) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = + FdoData->AiRxDmaCount; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = + (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN); + } + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = + CB_557_CFIG_DEFAULT_PARM4; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = + CB_557_CFIG_DEFAULT_PARM5; + } + + + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] = + (UCHAR) ((CB_557_CFIG_DEFAULT_PARM7 & (~CB_CFIG_URUN_RETRY)) | + (FdoData->AiUnderrunRetry << 1) + ); + + // Setup for MII or 503 operation. The CRS+CDT bit should only be set + // when operating in 503 mode. + if (FdoData->PhyAddress == 32) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = + (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII)); + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = + (CB_557_CFIG_DEFAULT_PARM15 | CB_CFIG_CRS_OR_CDT); + } + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = + (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII); + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = + ((CB_557_CFIG_DEFAULT_PARM15 & (~CB_CFIG_CRS_OR_CDT)) | CB_CFIG_BROADCAST_DIS); + } + + + // Setup Full duplex stuff + + // If forced to half duplex + if (FdoData->AiForceDpx == 1) + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + (CB_557_CFIG_DEFAULT_PARM19 & + (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE))); + + // If forced to full duplex + else if (FdoData->AiForceDpx == 2) + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX); + + // If auto-duplex + else + { + // We must force full duplex on if we are using PHY 0, and we are + // supposed to run in FDX mode. We do this because the D100 has only + // one FDX# input pin, and that pin will be connected to PHY 1. + if ((FdoData->PhyAddress == 0) && (FdoData->usDuplexMode == 2)) + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX); + else + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + CB_557_CFIG_DEFAULT_PARM19; + } + + + // display the config TRACE_LEVEL_INFORMATION to the debugger + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Issuing Configure command\n"); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Config Block at virt addr %p phys address %x\n", + &NonTxCmdBlockHdr->CbStatus, FdoData->NonTxCmdBlockPhys); + + for (i=0; i < CB_CFIG_BYTE_COUNT; i++) + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Config byte %x = %.2x\n", + i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]); + + // Wait for the SCB command word to clear before we set the general pointer + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + } + else + { + ASSERT(FdoData->CSRAddress->ScbCommandLow == 0); + FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; + + // Submit the configure command to the chip, and wait for it to complete. + status = D100SubmitCommandBlockAndWait(FdoData); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, + "<-- HwConfigure, Status=%x\n", status); + + return status; +} + + +NTSTATUS +HwSetupIAAddress( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Set up the individual MAC address + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + NT Status code + +--*/ +{ + NTSTATUS status; + UINT i; + PCB_HEADER_STRUC NonTxCmdBlockHdr = + (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwSetupIAAddress\n"); + + // Individual Address Setup + NonTxCmdBlockHdr->CbStatus = 0; + NonTxCmdBlockHdr->CbCommand = CB_IA_ADDRESS; + NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL; + + // Copy in the station's individual address + for (i = 0; i < ETH_LENGTH_OF_ADDRESS; i++) + FdoData->NonTxCmdBlock->NonTxCb.Setup.IaAddress[i] = FdoData->CurrentAddress[i]; + + // Update the command list pointer. We don't need to do a WaitSCB here + // because this command is either issued immediately after a reset, or + // after another command that runs in polled mode. This guarantees that + // the low byte of the SCB command word will be clear. The only commands + // that don't run in polled mode are transmit and RU-start commands. + ASSERT(FdoData->CSRAddress->ScbCommandLow == 0); + FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; + + // Submit the IA configure command to the chip, and wait for it to complete. + status = D100SubmitCommandBlockAndWait(FdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "<-- HwSetupIAAddress, Status=%x\n", status); + + return status; +} + +NTSTATUS +HwClearAllCounters( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This routine will clear the hardware TRACE_LEVEL_ERROR statistic counters + +Arguments: + + FdoData Pointer to our adapter + +Return Value: + + NT Status code + + +--*/ +{ + NTSTATUS status; + BOOLEAN bResult; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "--> HwClearAllCounters\n"); + + PAGED_CODE(); + + do + { + // Load the dump counters pointer. Since this command is generated only + // after the IA setup has complete, we don't need to wait for the SCB + // command word to clear + ASSERT(FdoData->CSRAddress->ScbCommandLow == 0); + FdoData->CSRAddress->ScbGeneralPointer = FdoData->StatsCounterPhys; + + // Issue the load dump counters address command + status = D100IssueScbCommand(FdoData, SCB_CUC_DUMP_ADDR, FALSE); + if (status != STATUS_SUCCESS) + break; + + // Now dump and reset all of the statistics + status = D100IssueScbCommand(FdoData, SCB_CUC_DUMP_RST_STAT, TRUE); + if (status != STATUS_SUCCESS) + break; + + // Now wait for the dump/reset to complete, timeout value 2 secs + MP_STALL_AND_WAIT(FdoData->StatsCounters->CommandComplete == 0xA007, 2000, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(FdoData); + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + // init packet counts + FdoData->GoodTransmits = 0; + FdoData->GoodReceives = 0; + + // init transmit error counts + FdoData->TxAbortExcessCollisions = 0; + FdoData->TxLateCollisions = 0; + FdoData->TxDmaUnderrun = 0; + FdoData->TxLostCRS = 0; + FdoData->TxOKButDeferred = 0; + FdoData->OneRetry = 0; + FdoData->MoreThanOneRetry = 0; + FdoData->TotalRetries = 0; + + // init receive error counts + FdoData->RcvCrcErrors = 0; + FdoData->RcvAlignmentErrors = 0; + FdoData->RcvResourceErrors = 0; + FdoData->RcvDmaOverrunErrors = 0; + FdoData->RcvCdtFrames = 0; + FdoData->RcvRuntErrors = 0; + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, + "<-- HwClearAllCounters, Status=%x\n", status); + + return status; +} + +VOID +NICGetDeviceInfSettings( + IN OUT PFDO_DATA FdoData + ) +{ + + // + // Number of ReceiveFrameDescriptors + // + if(!PciDrvReadRegistryValue(FdoData, + L"NumRfd", + &FdoData->NumRfd)){ + FdoData->NumRfd = 32; + } + + FdoData->NumRfd = min(FdoData->NumRfd, NIC_MAX_RFDS); + FdoData->NumRfd = max(FdoData->NumRfd, 1); + + // + // Number of Transmit Control Blocks + // + if(!PciDrvReadRegistryValue(FdoData, + L"NumTcb", + &FdoData->NumTcb)){ + FdoData->NumTcb = NIC_DEF_TCBS; + + } + + FdoData->NumTcb = min(FdoData->NumTcb, NIC_MAX_TCBS); + FdoData->NumTcb = max(FdoData->NumTcb, 1); + + // + // Max number of buffers required for coalescing fragmented packet. + // Not implemented in this sample + // + if(!PciDrvReadRegistryValue(FdoData, + L"NumCoalesce", + &FdoData->NumBuffers)){ + FdoData->NumBuffers = 8; + } + + FdoData->NumBuffers = min(FdoData->NumBuffers, 32); + FdoData->NumBuffers = max(FdoData->NumBuffers, 1); + + // + // Get the Link Speed & Duplex. + // + if(!PciDrvReadRegistryValue(FdoData, + L"SpeedDuplex", + &FdoData->SpeedDuplex)){ + FdoData->SpeedDuplex = 0; + } + FdoData->SpeedDuplex = min(FdoData->SpeedDuplex, 4); + FdoData->SpeedDuplex = max(FdoData->SpeedDuplex, 0); + // + // Decode SpeedDuplex + // Value 0 means Auto detect + // Value 1 means 10Mb-Half-Duplex + // Value 2 means 10Mb-Full-Duplex + // Value 3 means 100Mb-Half-Duplex + // Value 4 means 100Mb-Full-Duplex + // + switch(FdoData->SpeedDuplex) + { + case 1: + FdoData->AiTempSpeed = 10; FdoData->AiForceDpx = 1; + break; + + case 2: + FdoData->AiTempSpeed = 10; FdoData->AiForceDpx = 2; + break; + + case 3: + FdoData->AiTempSpeed = 100; FdoData->AiForceDpx = 1; + break; + + case 4: + FdoData->AiTempSpeed = 100; FdoData->AiForceDpx = 2; + break; + } + + // + // Rest of these values are currently not configured thru INF. + // + FdoData->PhyAddress = 0xFF; + FdoData->Connector = 0; + FdoData->AiTxFifo = DEFAULT_TX_FIFO_LIMIT; + FdoData->AiRxFifo = DEFAULT_RX_FIFO_LIMIT; + FdoData->AiTxDmaCount = 0; + FdoData->AiRxDmaCount = 0; + FdoData->AiUnderrunRetry = DEFAULT_UNDERRUN_RETRY; + FdoData->AiThreshold = 200; + FdoData->MWIEnable = 1; + FdoData->Congest = 0; + + return; + } + + diff --git a/general/pcidrv/kmdf/HW/nic_pm.c b/general/pcidrv/kmdf/HW/nic_pm.c new file mode 100644 index 00000000..7bdd3b99 --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_pm.c @@ -0,0 +1,1710 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "nic_pm.tmh" +#endif + + +// Things to note: +// PME_ena bit should be active before the 82558 is set into low power mode +// Default for WOL should generate wake up event after a HW Reset + +// Fixed Packet Filtering +// Need to verify that the micro code is loaded and Micro Machine is active +// Clock signal is active on PCI clock + + +// Address Matching +// Need to enable IAMatch_Wake_En bit and the MCMatch_Wake_En bit is set + +// ARP Wakeup +// Need to set BRCST DISABL bet to 0 (broadcast enable) +// To handle VLAN set the VLAN_ARP bit +// IP address needs to be configured with 16 least significant bits +// Set the IP Address in the IP_Address configuration word. + +// Fixed WakeUp Filters: +// There are 3ight different fixed WakeUp Filters +// ( Unicast, Multicast, Arp. etc). + + +// Link Status Event +// Set Link_Status_Wakeup Enable bit. + +// Flexible filtering: +// Supports: ARP packets, Directed, Magic Packet and Link Event + +// Flexible Filtering Overview: +// driver should program micro-code before setting card into low power +// Incoming packets are compared against the loadable microcode. If PME is +// is enabled then, the system is woken up. + + +// Segments are defined in book - but not implemented here. + +// WakeUp Packet -that causes the machine to wake up will be stored +// in the Micro Machine temporary storage area so that the driver can read it. + + +// Software Work: +// Power Down: +// OS requests the driver to go to a low power state +// SW sets CU and RU to idle by issuing a Selective Reset to the device +// 3rd portion .- Wake Up Segments defintion +// The above three segments are loaded as on chain. The last CB must have +// its EL bit set. +// Device can now be powered down. +// Software driver completes OS request +// OS then physically switches the Device to low power state +// + +// Power Up: +// OS powers up the Device +// driver should NOT initialize the Device. It should NOT issue a Self Test +// Driver Initiates a PORT DUMP command +// Device dumps its internal registers including the wakeup frame storage area +// SW reads the PME register +// SW reads the WakeUp Frame Data, analyzes it and acts accordingly +// SW restores its cvonfiguration and and resumes normal operation. +// + +// +// Power Management definitions from the Intel Handbook +// + +// +// Definitions from Table 4.2, Pg 4.9 +// of the 10/100 Mbit Ethernet Family Software Technical +// Reference Manual +// + +#define PMC_Offset 0xDE +#define E100_PMC_WAKE_FROM_D0 0x1 +#define E100_PMC_WAKE_FROM_D1 0x2 +#define E100_PMC_WAKE_FROM_D2 0x4 +#define E100_PMC_WAKE_FROM_D3HOT 0x8 +#define E100_PMC_WAKE_FROM_D3_AUX 0x10 + +// +// Load Programmable filter definintions. +// Taken from C-19 from the Software Reference Manual. +// It has examples too. The opcode used for load is 0x80000 +// + +#define BIT_15_13 0xA000 + +#define CB_LOAD_PROG_FILTER BIT_3 +#define CU_LOAD_PROG_FILTER_EL BIT_7 +#define CU_SUCCEED_LOAD_PROG_FILTER BIT_15_13 +#define CB_FILTER_EL BIT_7 +#define CB_FILTER_PREDEFINED_FIX BIT_6 +#define CB_FILTER_ARP_WAKEUP BIT_3 +#define CB_FILTER_IA_WAKEUP BIT_1 + +#define CU_SCB_NULL ((UINT)-1) + + +#pragma pack( push, enter_include1, 1 ) + +// +// Define the PM Capabilities register in the device +// portion of the PCI config space +// +typedef struct _MP_PM_CAP_REG { + + #pragma warning(disable:4214) // bit field types other than int warning + + USHORT UnInteresting:11; + USHORT PME_Support:5; + + #pragma warning(default:4214) + +} MP_PM_CAP_REG; + + +// +// Define the PM Control/Status Register +// +typedef struct _MP_PMCSR { + + #pragma warning(disable:4214) // bit field types other than int warning + + USHORT PowerState:2; // Power State; + USHORT Res:2; // reserved + USHORT DynData:1; // Ignored + USHORT Res1:3; // Reserved + USHORT PME_En:1; // Enable device to set the PME Event; + USHORT DataSel:4; // Unused + USHORT DataScale:2; // Data Scale - Unused + USHORT PME_Status:1; // PME Status - Sticky bit; + + #pragma warning(default:4214) + +} MP_PMCSR ; + +typedef struct _MP_PM_PCI_SPACE { + + UCHAR Stuff[PMC_Offset]; + + // PM capabilites + + MP_PM_CAP_REG PMCaps; + + // PM Control Status Register + + MP_PMCSR PMCSR; + + +} MP_PM_PCI_SPACE , *PMP_PM_PCI_SPACE ; + + +// +// This is the Programmable Filter Command Structure +// +typedef struct _MP_PROG_FILTER_COMM_STRUCT +{ + // CB Status Word + USHORT CBStatus; + + // CB Command Word + USHORT CBCommand; + + //Next CB PTR == ffff ffff + ULONG NextCBPTR; + + //Programmable Filters + ULONG FilterData[16]; + + +} MP_PROG_FILTER_COMM_STRUCT,*PMP_PROG_FILTER_COMM_STRUCT; + +typedef struct _MP_PMDR +{ + #pragma warning(disable:4214) // bit field types other than int warning + + // Status of the PME bit + UCHAR PMEStatus:1; + + // Is the TCO busy + UCHAR TCORequest:1; + + // Force TCO indication + UCHAR TCOForce:1; + + // Is the TCO Ready + UCHAR TCOReady:1; + + // Reserved + UCHAR Reserved:1; + + // Has an InterestingPacket been received + UCHAR InterestingPacket:1; + + // Has a Magic Packet been received + UCHAR MagicPacket:1; + + // Has the Link Status been changed + UCHAR LinkStatus:1; + + #pragma warning(default:4214) + +} MP_PMDR , *PMP_PMDR; + +//------------------------------------------------------------------------- +// Structure used to set up a programmable filter. +// This is overlayed over the Control/Status Register (CSR) +//------------------------------------------------------------------------- +typedef struct _CSR_FILTER_STRUC { + + // Status- used to verify if the load prog filter command + // has been accepted .set to 0xa000 + USHORT ScbStatus; // SCB Status register + + // Set to an opcode of 0x8 + // + UCHAR ScbCommandLow; // SCB Command register (low byte) + + // 80. Low + High gives the required opcode 0x80080000 + UCHAR ScbCommandHigh; // SCB Command register (high byte) + + // Set to NULL ff ff ff ff + ULONG NextPointer; // SCB General pointer + + // Set to a hardcoded filter, Arp + IA Match, + IP address + + union + { + ULONG u32; + + struct { + UCHAR IPAddress[2]; + UCHAR Reserved; + UCHAR Set; + + }PreDefined; + + }Programmable; // Wake UP Filter union + +} CSR_FILTER_STRUC, *PCSR_FILTER_STRUC; + +#pragma pack( pop, enter_include1 ) + +#define MP_CLEAR_PMDR(pPMDR) (*pPMDR) = ((*pPMDR) | 0xe0); // clear the 3 uppermost bits in the PMDR + + +//------------------------------------------------------------------------- +// L O C A L P R O T O T Y P E S +//------------------------------------------------------------------------- + +__inline +NTSTATUS +MPIssueScbPoMgmtCommand( + IN PFDO_DATA Adapter, + IN PCSR_FILTER_STRUC pFilter, + IN BOOLEAN WaitForScb + ); + + +VOID +MPCreateProgrammableFilter ( + IN PMP_WAKE_PATTERN pMpWakePattern , + IN PUCHAR pFilter, + IN OUT PULONG pNext + ); + + + +//------------------------------------------------------------------------- +// P O W E R M G M T F U N C T I O N S +//------------------------------------------------------------------------- + +PUCHAR +HwReadPowerPMDR( + IN PFDO_DATA Adapter + ) +/*++ +Routine Description: + + This routine will read Hardware's PM registers + +Arguments: + + Adapter Pointer to our adapter + +Return Value: + + STATUS_SUCCESS + NTSTATUS_HARD_ERRORS + +--*/ +{ + UCHAR PMDR =0; + PUCHAR pPMDR = NULL; + +#define CSR_SIZE sizeof (*Adapter->CSRAddress) + + + + ASSERT (CSR_SIZE == 0x18); + + pPMDR = 0x18 + (PUCHAR)Adapter->CSRAddress ; + + PMDR = *pPMDR; + + return pPMDR; + +} + + +NTSTATUS +MpClearPME_En ( + IN PFDO_DATA FdoData, + IN MP_PMCSR PMCSR + ) +{ + NTSTATUS status; + UINT ulResult; + + PMCSR.PME_En = 0; + + ulResult = FdoData->BusInterface.SetBusData( + FdoData->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&PMCSR, + FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR), + sizeof(PMCSR)); + + ASSERT (ulResult == sizeof(PMCSR)); + if (ulResult == sizeof(PMCSR)) { + status = STATUS_SUCCESS; + + } else { + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + + + +VOID +MPSetPowerLowPrivate( + WDFINTERRUPT WdfInterrupt, + PFDO_DATA FdoData + ) +/*++ +Routine Description: + + The section follows the steps mentioned in + Section C.2.6.2 of the Reference Manual. + + +Arguments: + + Adapter Pointer to our adapter + +Return Value: + +--*/ +{ + CSR_FILTER_STRUC Filter; + USHORT IntStatus; + MP_PMCSR PMCSR = {0}; + ULONG ulResult; + + UNREFERENCED_PARAMETER( WdfInterrupt ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "-->MPSetPowerLowPrivate\n"); + RtlZeroMemory (&Filter, sizeof (Filter)); + + // + // Before issue the command to low power state, we should ack all the + // pending interrupts, then set the adapter's power to low state. + // + NIC_ACK_INTERRUPT(FdoData, IntStatus); + + // + // If the driver should wake up the machine + // + if (FdoData->AllowWakeArming) + { + // + // Send the WakeUp Pattern to the nic + MPIssueScbPoMgmtCommand(FdoData, &Filter, TRUE); + + + // + // Section C.2.6.2 - The driver needs to wait for the CU to idle + // The above function already waits for the CU to idle + // + ASSERT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_IDLE); + } + else + { + + ulResult = FdoData->BusInterface.GetBusData( + FdoData->BusInterface.Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&PMCSR, + FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR), + sizeof(PMCSR)); + + if(ulResult != sizeof(PMCSR)){ + ASSERT(ulResult == sizeof(PMCSR)); + TraceEvents(TRACE_LEVEL_ERROR, DBG_POWER, "GetBusData for PMCSR failed\n"); + return; + } + if (PMCSR.PME_En == 1) + { + // + // PME is enabled. Clear the PME_En bit. + // So that it is not asserted + // + MpClearPME_En (FdoData,PMCSR); + + } + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<--MPSetPowerLowPrivate\n"); + +} + +NTSTATUS +MPSetPowerD0Private ( + IN PFDO_DATA FdoData + ) +{ + PUCHAR pPMDR; + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "-->MPSetPowerD0Private\n"); + + // Dump the packet if necessary + //Cause of Wake Up + + pPMDR = HwReadPowerPMDR(FdoData); + + status = NICInitializeAdapter(FdoData); + + // Clear the PMDR + MP_CLEAR_PMDR(pPMDR); + + NICIssueSelectiveReset(FdoData); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<--MPSetPowerD0Private\n"); + + return status; +} + + +VOID +HwSetWakeUpConfigure( + IN PFDO_DATA FdoData, + PUCHAR pPoMgmtConfigType, + UINT WakeUpParameter + ) +{ + UNREFERENCED_PARAMETER( WakeUpParameter ); + + if (IsPoMgmtSupported( FdoData) == TRUE) + { + (*pPoMgmtConfigType)= ((*pPoMgmtConfigType) | + CB_WAKE_ON_LINK_BYTE9 | + CB_WAKE_ON_ARP_PKT_BYTE9 ); + } +} + +NTSTATUS +MPSetUpFilterCB( + IN PFDO_DATA FdoData + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)FdoData->NonTxCmdBlock; + PFILTER_CB_STRUC pFilterCb = (PFILTER_CB_STRUC)NonTxCmdBlockHdr; + ULONG Curr = 0; + ULONG Next = 0; + PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPSetUpFilterCB\n"); + + RtlZeroMemory (pFilterCb, sizeof(*pFilterCb)); + + // Individual Address Setup + NonTxCmdBlockHdr->CbStatus = 0; + NonTxCmdBlockHdr->CbCommand = CB_EL_BIT | CB_LOAD_PROG_FILTER; + NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL; + + // go through each filter in the list. + + while (pPatternEntry != (&FdoData->PoMgmt.PatternList)) + { + PMP_WAKE_PATTERN pWakeUpPattern = NULL; + //PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;; + + // initialize local variables + pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry); + + // increment the iterator + pPatternEntry = ListNext (pPatternEntry); + + // Update the Curr Array Pointer + Curr = Next; + + // Create the Programmable filter for this device. + MPCreateProgrammableFilter (pWakeUpPattern , (PUCHAR)&pFilterCb->Pattern[Curr], &Next); + + if (Next >=16) + { + break; + } + + } + + { + // Set the EL bit on the last pattern + PUCHAR pLastPattern = (PUCHAR) &pFilterCb->Pattern[Curr]; + + // Get to bit 31 + pLastPattern[3] |= CB_FILTER_EL ; + + + } + + ASSERT(FdoData->CSRAddress->ScbCommandLow == 0); + + // Wait for the CU to Idle before giving it this command + if(!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPSetUpFilterCB\n"); + + return status; + + +} + +NTSTATUS +MPIssueScbPoMgmtCommand( + IN PFDO_DATA FdoData, + IN PCSR_FILTER_STRUC pNewFilter, + IN BOOLEAN WaitForScb + ) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + + UNREFERENCED_PARAMETER( pNewFilter ); + UNREFERENCED_PARAMETER( WaitForScb ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, + "--> MPIssueScbPoMgmtCommand\n"); + + do + { + // Set up SCB to issue this command + + status = MPSetUpFilterCB(FdoData); + + if (status != STATUS_SUCCESS) + { + break; + } + + // Submit the configure command to the chip, and wait for + // it to complete. + + FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; + + status = D100SubmitCommandBlockAndWait(FdoData); + + if(status != STATUS_SUCCESS) + { + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, + "<-- MPIssueScbPoMgmtCommand %x\n", status); + + return status; +} + + + +NTSTATUS +MPCalculateE100PatternForFilter ( + IN PUCHAR pFrame, + IN ULONG FrameLength, + IN PUCHAR pMask, + IN ULONG MaskLength, + OUT PULONG pSignature + ) +/*++ +Routine Description: + + This function outputs the E100 specific Pattern Signature + used to wake up the machine. + + Section C.2.4 - CRC word calculation of a Flexible Filer + + +Arguments: + + pFrame - Pattern Set by the protocols + FrameLength - Length of the Pattern + pMask - Mask set by the Protocols + MaskLength - Length of the Mask + pSignature - caller allocated return structure + +Return Value: + Returns Success + Failure - if the Pattern is greater than 129 bytes + +--*/ +{ + + const ULONG Coefficients = 0x04c11db7; + ULONG Signature = 0; + ULONG n = 0; + ULONG i= 0; + PUCHAR pCurrentMaskByte = pMask - 1; // init to -1 + ULONG MaskOffset = 0; + ULONG BitOffsetInMask = 0; + ULONG MaskBit = 0; + ULONG ShiftBy = 0; + UCHAR FrameByte = 0; + NTSTATUS status = STATUS_UNSUCCESSFUL; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPCalculateE100PatternForFilter\n"); + + *pSignature = 0; + + do + { + if (FrameLength > 128) + { + status = STATUS_UNSUCCESSFUL; + break; + } + + // The E100 driver can only accept 3 DWORDS of Mask in a single pattern + if (MaskLength > (3*sizeof(ULONG))) + { + status = STATUS_UNSUCCESSFUL; + break; + } + + for (n=i=0;(n<128) && (n < FrameLength); ++n) + { + + // The first half deals with the question - + // Is the nth Frame byte to be included in the Filter + // + + BitOffsetInMask = (n % 8); + + if (BitOffsetInMask == 0) + { + // + // We need to move to a new byte. + // [0] for 0th byte, [1] for 8th byte, [2] for 16th byte, etc. + // + MaskOffset = n/8; // This is the new byte we need to go + + // + // + if (MaskOffset == MaskLength) + { + break; + } + + pCurrentMaskByte ++; + ASSERT (*pCurrentMaskByte == pMask[n/8]); + } + + + // Now look at the actual bit in the mask + MaskBit = 1 << BitOffsetInMask ; + + // If the current Mask Bit is set in the Mask then + // we need to use it in the CRC calculation, otherwise we ignore it + + if (! (MaskBit & pCurrentMaskByte[0])) + { + continue; + } + + // We are suppossed to take in the current byte as part of the CRC calculation + // Initialize the variables + FrameByte = pFrame[n]; + ShiftBy = (i % 3 ) * 8; + + ASSERT (ShiftBy!= 24); // Bit 24 is never used + + if (Signature & 0x80000000) + { + Signature = ((Signature << 1) ^ ( FrameByte << ShiftBy) ^ Coefficients); + } + else + { + Signature = ((Signature << 1 ) ^ (FrameByte << ShiftBy)); + } + ++i; + + } + + // Clear bits 22-31 + Signature &= 0x00ffffff; + + // Update the result + *pSignature = Signature; + + // We have succeeded + status = STATUS_SUCCESS; + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPCalculateE100PatternForFilter\n"); + + return status; +} + + +VOID +MPCreateProgrammableFilter ( + IN PMP_WAKE_PATTERN pMpWakePattern , + IN PUCHAR pFilter, + IN OUT PULONG pNext + ) +/*++ +Routine Description: + + This function outputs the E100 specific Pattern Signature + used to wake up the machine. + + Section C.2.4 - Load Programmable Filter page C.20 + + +Arguments: + + pMpWakePattern - Filter will be created for this pattern, + pFilter - Filter will be stored here, + pNext - Used for validation . This Ulong will also be incremented by the size + of the filter (in ulongs) + +Return Value: + +--*/ +{ + PUCHAR pCurrentByte = pFilter; + ULONG NumBytesWritten = 0; + PULONG pCurrentUlong = (PULONG)pFilter; + PNDIS_PM_PACKET_PATTERN pNdisPattern = (PNDIS_PM_PACKET_PATTERN)(&pMpWakePattern->Pattern[0]); + ULONG LengthOfFilter = 0; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> MPCreateProgrammableFilter\n"); + + // Is there enough room for this pattern + // + { + // Length in DWORDS + LengthOfFilter = pNdisPattern->MaskSize /4; + + if (pNdisPattern->MaskSize % 4 != 0) + { + LengthOfFilter++; + } + + // Increment LengthOfFilter to account for the 1st DWORD + LengthOfFilter++; + + // We are only allowed 16 DWORDS in a filter + if (*pNext + LengthOfFilter >= 16) + { + // Failure - early exit + return; + } + + } + // Clear the Predefined bit; already cleared in the previous function. + // first , initialize - + *pCurrentUlong = 0; + + // Mask Length goes into Bits 27-29 of the 1st DWORD. MaskSize is measured in DWORDs + { + ULONG dwMaskSize = pNdisPattern->MaskSize /4; + ULONG dwMLen = 0; + + + // If there is a remainder a remainder then increment + if (pNdisPattern->MaskSize % 4 != 0) + { + dwMaskSize++; + } + + + // + // If we fail this assertion, it means our + // MaskSize is greater than 16 bytes. + // This filter should have been failed upfront at the time of the request + // + + ASSERT (0 < dwMaskSize && dwMaskSize < 5); + // + // In the Spec, 0 - Single DWORD maske, 001 - 2 DWORD mask, + // 011 - 3 DWORD mask, 111 - 4 Dword Mask. + // + + if (dwMaskSize == 1) dwMLen = 0; + if (dwMaskSize == 2) dwMLen = 1; + if (dwMaskSize == 3) dwMLen = 3; + if (dwMaskSize == 4) dwMLen = 7; + + // Adjust the Mlen, so it is in the correct position + + dwMLen = (dwMLen << 3); + + + + if (dwMLen != 0) + { + ASSERT (dwMLen <= 0x38 && dwMLen >= 0x08); + } + + // These go into bits 27,28,29 (bits 3,4 and 5 of the 4th byte) + pCurrentByte[3] |= dwMLen ; + + + } + + // Add the signature to bits 0-23 of the 1st DWORD + { + PUCHAR pSignature = (PUCHAR)&pMpWakePattern->Signature; + + + // Bits 0-23 are also the 1st three bytes of the DWORD + pCurrentByte[0] = pSignature[0]; + pCurrentByte[1] = pSignature[1]; + pCurrentByte[2] = pSignature[2]; + + } + + + // Lets move to the next DWORD. Init variables + pCurrentByte += 4 ; + NumBytesWritten = 4; + pCurrentUlong = (PULONG)pCurrentByte; + + // We Copy in the Mask over here + { + // The Mask is at the end of the pattern + + PUCHAR pMask = (PUCHAR)pNdisPattern + sizeof(*pNdisPattern); + + //Dump (pMask,pNdisPattern->MaskSize, 0,1); + + RtlMoveMemory (pCurrentByte, pMask, pNdisPattern->MaskSize); + + NumBytesWritten += pNdisPattern->MaskSize; + + } + + + // Update the output value + { + ULONG NumUlongs = (NumBytesWritten /4); + + if ((NumBytesWritten %4) != 0) + { + NumUlongs ++; + } + + ASSERT (NumUlongs == LengthOfFilter); + + *pNext = *pNext + NumUlongs; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- MPCreateProgrammableFilter\n"); + + return; +} + +NTSTATUS +MPSetPowerD0( + PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This routine is called when the adapter receives a SetPower + to D0. + +Arguments: + + Adapter Pointer to the adapter structure + PowerState NewPowerState + +Return Value: + + +--*/ +{ + NTSTATUS status; + //KIRQL oldIrql; + + // + // MPSetPowerD0Private Initializes the adapte, issues a selective reset. + // + MPSetPowerD0Private (FdoData); + ASSERT(FdoData->DevicePowerState == PowerDeviceD0); + // + // Set up the packet filter + // + + WdfSpinLockAcquire(FdoData->Lock); + status = NICSetPacketFilter( + FdoData, + FdoData->OldPacketFilter); + // + // If Set Packet Filter succeeds, restore the old packet filter + // + if (status == STATUS_SUCCESS) + { + FdoData->PacketFilter = FdoData->OldPacketFilter; + } + + + WdfSpinLockRelease(FdoData->Lock); + + // + // Set up the multicast list address + // + + WdfSpinLockAcquire(FdoData->RcvLock); + + status = NICSetMulticastList(FdoData); + + NICStartRecv(FdoData); + + + WdfSpinLockRelease(FdoData->RcvLock); + + return status; +} + +NTSTATUS +MPSetPowerLow( + PFDO_DATA FdoData, + WDF_POWER_DEVICE_STATE PowerState + ) +/*++ +Routine Description: + + This routine is called when the FdoData receives a SetPower + to a PowerState > D0 + +Arguments: + + FdoData Pointer to the FdoData structure + PowerState NewPowerState + +Return Value: + NDIS_STATUS_SUCCESS + NDIS_STATUS_PENDING + STATUS_DEVICE_DATA_ERROR + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + UNREFERENCED_PARAMETER( PowerState ); + + // + // Stop sending packets. Create a new flag and make it part + // of the Send Fail Mask. TODO: Does something need to happen here? + // + + // + // Stop hardware from receiving packets - Set the RU to idle. + // TODO: Does something need to happen here? + // + + // + // Check the current status of the receive unit + // + if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) + { + // + // Issue an RU abort. Since an interrupt will be issued, the + // RU will be started by the DPC. + // + status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE); + } + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // MPSetPowerLowPrivate first disables the interrupt, acknowledges all the pending + // interrupts and sets FdoData->DevicePowerState to the given low power state + // then starts Hardware specific part of the transition to low power state + // Setting up wake-up patterns, filters, wake-up events etc + // + // Interrupt is disabled and disconnected before entering D0Exit, so no need to + // sychronize. + // + + MPSetPowerLowPrivate(NULL, FdoData); + + return STATUS_SUCCESS; +} + +BOOLEAN +MPAreTwoPatternsEqual( + IN PNDIS_PM_PACKET_PATTERN pNdisPattern1, + IN PNDIS_PM_PACKET_PATTERN pNdisPattern2 + ) +/*++ +Routine Description: + + This routine will compare two wake up patterns to see if they are equal + +Arguments: + + pNdisPattern1 - Pattern1 + pNdisPattern2 - Pattern 2 + + +Return Value: + + True - if patterns are equal + False - Otherwise +--*/ +{ + BOOLEAN bEqual = FALSE; + + // Local variables used later in the compare section of this function + PUCHAR pMask1, pMask2; + PUCHAR pPattern1, pPattern2; + UINT MaskSize, PatternSize; + + do + { + + bEqual = (BOOLEAN)(pNdisPattern1->Priority == pNdisPattern2->Priority); + + if (bEqual == FALSE) + { + break; + } + + bEqual = (BOOLEAN)(pNdisPattern1->MaskSize == pNdisPattern2->MaskSize); + if (bEqual == FALSE) + { + break; + } + + // + // Verify the Mask + // + MaskSize = pNdisPattern1->MaskSize ; + pMask1 = (PUCHAR) pNdisPattern1 + sizeof (NDIS_PM_PACKET_PATTERN); + pMask2 = (PUCHAR) pNdisPattern2 + sizeof (NDIS_PM_PACKET_PATTERN); + + bEqual = (BOOLEAN)RtlEqualMemory (pMask1, pMask2, MaskSize); + + if (bEqual == FALSE) + { + break; + } + + // + // Verify the Pattern + // + bEqual = (BOOLEAN)(pNdisPattern1->PatternSize == pNdisPattern2->PatternSize); + + if (bEqual == FALSE) + { + break; + } + + PatternSize = pNdisPattern2->PatternSize; + pPattern1 = (PUCHAR) pNdisPattern1 + pNdisPattern1->PatternOffset; + pPattern2 = (PUCHAR) pNdisPattern2 + pNdisPattern2->PatternOffset; + + bEqual = (BOOLEAN)RtlEqualMemory (pPattern1, pPattern2, PatternSize ); + + if (bEqual == FALSE) + { + break; + } + + } WHILE (FALSE); + + return bEqual; +} + +VOID +NICExtractPMInfoFromPciSpace( + PFDO_DATA FdoData, + PUCHAR pPciConfig + ) +/*++ +Routine Description: + + Looks at the PM information in the + device specific section of the PCI Config space. + + Interprets the register values and stores it + in the adapter structure + + Definitions from Table 4.2 & 4.3, Pg 4-9 & 4-10 + of the 10/100 Mbit Ethernet Family Software Technical + Reference Manual + + +Arguments: + + Adapter Pointer to our adapter + pPciConfig Pointer to Common Pci Space + +Return Value: + +--*/ +{ + PMP_PM_PCI_SPACE pPmPciConfig = (PMP_PM_PCI_SPACE )pPciConfig; + MP_PMCSR PMCSR; + + // + // First interpret the PM Capabities register + // + { + MP_PM_CAP_REG PmCaps; + + PmCaps = pPmPciConfig->PMCaps; + + if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D0) + { + FdoData->PoMgmt.bWakeFromD0 = TRUE; + } + + if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D1) + { + FdoData->PoMgmt.bWakeFromD1 = TRUE; + } + + if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D2) + { + FdoData->PoMgmt.bWakeFromD2 = TRUE; + } + + if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3HOT) + { + FdoData->PoMgmt.bWakeFromD3Hot = TRUE; + } + + if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3_AUX) + { + FdoData->PoMgmt.bWakeFromD3Aux = TRUE; + } + + } + + // + // Interpret the PM Control/Status Register + // + { + PMCSR = pPmPciConfig->PMCSR; + + if (PMCSR.PME_En == 1) + { + // + // PME is enabled. Clear the PME_En bit. + // So that it is not asserted + // + MpClearPME_En (FdoData,PMCSR); + + } + + } + +} + + +NTSTATUS +NICSetPower( + PFDO_DATA FdoData , + WDF_POWER_DEVICE_STATE PowerState + ) +/*++ +Routine Description: + + This routine is called when the FdoData receives a SetPower + request. It redirects the call to an appropriate routine to + Set the New PowerState + +Arguments: + + FdoData Pointer to the FdoData structure + PowerState NewPowerState + +Return Value: + + NTSTATUS Code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + if(IsPoMgmtSupported(FdoData)){ + + if (PowerState == PowerDeviceD0) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering fully on state\n"); + MPSetPowerD0 (FdoData); + } + else + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "Entering a deeper sleep state\n"); + status = MPSetPowerLow (FdoData, PowerState); + } + } + + return status; +} + + + +NTSTATUS +NICAddWakeUpPattern( + IN PFDO_DATA FdoData, + IN PVOID InformationBuffer, + IN UINT InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) +/*++ +Routine Description: + + This routine will allocate a local memory structure, copy the pattern, + insert the pattern into a linked list and return success + + We are gauranteed that we wll get only one request at a time, so this is implemented + without locks. + +Arguments: + + FdoData FdoData structure + InformationBuffer Wake up Pattern + InformationBufferLength Wake Up Pattern Length + +Return Value: + + STATUS_Success - if successful. + STATUS_UNSUCCESSFUL - if memory allocation fails. + +--*/ +{ + + NTSTATUS status = STATUS_UNSUCCESSFUL; + PMP_WAKE_PATTERN pWakeUpPattern = NULL; + ULONG AllocationLength = 0; + PNDIS_PM_PACKET_PATTERN pPmPattern = NULL; + ULONG Signature = 0; + ULONG CopyLength = 0; + ULONG safeAddResult; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICAddWakeUpPattern\n"); + + do + { + + if(!FdoData->AllowWakeArming) { + status = STATUS_NOT_SUPPORTED; + break; + } + + pPmPattern = (PNDIS_PM_PACKET_PATTERN) InformationBuffer; + + if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) + { + status = STATUS_BUFFER_TOO_SMALL; + + *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); + break; + } + + // + // safeAddResult = pPmPattern->PatternOffset + pPmPattern->PatternSize + // + status = RtlULongAdd( + pPmPattern->PatternOffset, + pPmPattern->PatternSize, + &safeAddResult) ; + if (!NT_SUCCESS(status)) + { + break; + } + if (InformationBufferLength < safeAddResult) + { + status = STATUS_BUFFER_TOO_SMALL; + + *BytesNeeded = safeAddResult; + break; + } + + *BytesRead = safeAddResult; + + + // + // Calculate the e100 signature + // + status = MPCalculateE100PatternForFilter ( + (PUCHAR)pPmPattern+ pPmPattern->PatternOffset, + pPmPattern->PatternSize, + (PUCHAR)pPmPattern +sizeof(NDIS_PM_PACKET_PATTERN), + pPmPattern->MaskSize, + &Signature ); + + if ( status != STATUS_SUCCESS) + { + break; + } + + CopyLength = safeAddResult; + + // + // Allocate the memory to hold the WakeUp Pattern + // + // AllocationLength = sizeof (MP_WAKE_PATTERN) + CopyLength; + // + status = RtlULongAdd( + sizeof(MP_WAKE_PATTERN), + CopyLength, + &AllocationLength); + if (!NT_SUCCESS(status)) + { + break; + } + + pWakeUpPattern = ExAllocatePoolWithTag(NonPagedPool, AllocationLength, PCIDRV_POOL_TAG); + + if (!pWakeUpPattern) + { + break; + } + + // + // Initialize pWakeUpPattern + // + RtlZeroMemory (pWakeUpPattern, AllocationLength); + + pWakeUpPattern->AllocationSize = AllocationLength; + + pWakeUpPattern->Signature = Signature; + + // + // Copy the pattern into local memory + // + RtlMoveMemory (&pWakeUpPattern->Pattern[0], InformationBuffer, CopyLength); + + ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // + // Insert the pattern into the list + // + /* ExInterlockedInsertHeadList (&FdoData->PoMgmt.PatternList, + &pWakeUpPattern->linkListEntry, + &FdoData->Lock); + */ + + WdfSpinLockAcquire(FdoData->Lock); + InsertHeadList(&FdoData->PoMgmt.PatternList,&pWakeUpPattern->linkListEntry ); + WdfSpinLockRelease(FdoData->Lock); + + + status = STATUS_SUCCESS; + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICAddWakeUpPattern\n"); + + return status; +} + +NTSTATUS +NICRemoveWakeUpPattern( + IN PFDO_DATA FdoData, + IN PVOID InformationBuffer, + IN UINT InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) +/*++ +Routine Description: + + This routine will walk the list of wake up pattern and attempt to match the wake up pattern. + If it finds a copy , it will remove that WakeUpPattern + +Arguments: + + FdoData FdoData structure + InformationBuffer Wake up Pattern + InformationBufferLength Wake Up Pattern Length + +Return Value: + + Success - if successful. + STATUS_UNSUCCESSFUL - if memory allocation fails. + +--*/ +{ + + NTSTATUS status = STATUS_UNSUCCESSFUL; + PNDIS_PM_PACKET_PATTERN pReqPattern = (PNDIS_PM_PACKET_PATTERN)InformationBuffer; + PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICRemoveWakeUpPattern\n"); + + do + { + if(!FdoData->AllowWakeArming) { + status = STATUS_NOT_SUPPORTED; + break; + } + + if (InformationBufferLength < sizeof(NDIS_PM_PACKET_PATTERN)) + { + status = STATUS_BUFFER_TOO_SMALL; + + *BytesNeeded = sizeof(NDIS_PM_PACKET_PATTERN); + break; + } + if (InformationBufferLength < pReqPattern->PatternOffset + pReqPattern->PatternSize) + { + status = STATUS_BUFFER_TOO_SMALL; + + *BytesNeeded = pReqPattern->PatternOffset + pReqPattern->PatternSize; + break; + } + + *BytesRead = pReqPattern->PatternOffset + pReqPattern->PatternSize; + + while (pPatternEntry != (&FdoData->PoMgmt.PatternList)) + { + BOOLEAN bIsThisThePattern = FALSE; + PMP_WAKE_PATTERN pWakeUpPattern = NULL; + PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;; + + // + // initialize local variables + // + pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry); + + pCurrPattern = (PNDIS_PM_PACKET_PATTERN)&pWakeUpPattern->Pattern[0]; + + // + // increment the iterator + // + pPatternEntry = ListNext (pPatternEntry); + + // + // Begin Check : Is (pCurrPattern == pReqPattern) + // + bIsThisThePattern = MPAreTwoPatternsEqual(pReqPattern, pCurrPattern); + + + if (bIsThisThePattern == TRUE) + { + // + // we have a match - remove the entry + // + RemoveEntryList (&pWakeUpPattern->linkListEntry); + + // + // Free the entry + // + ExFreePoolWithTag(pWakeUpPattern, PCIDRV_POOL_TAG); + + status = STATUS_SUCCESS; + break; + } + + } + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICRemoveWakeUpPattern\n"); + + return status; +} + + + +VOID +NICRemoveAllWakeUpPatterns( + PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This routine will walk the list of wake up pattern and free it + +Arguments: + + FdoData FdoData structure + +Return Value: + + Success - if successful. + +--*/ +{ + + PLIST_ENTRY pPatternEntry = ListNext(&FdoData->PoMgmt.PatternList) ; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "--> NICRemoveAllWakeUpPatterns\n"); + + while (pPatternEntry != (&FdoData->PoMgmt.PatternList)) + { + PMP_WAKE_PATTERN pWakeUpPattern = NULL; + + // + // initialize local variables + // + pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN,linkListEntry); + + // + // increment the iterator + // + pPatternEntry = ListNext (pPatternEntry); + + // + // Remove the entry from the list + // + RemoveEntryList (&pWakeUpPattern->linkListEntry); + + // + // Free the memory + // + ExFreePoolWithTag(pWakeUpPattern, PCIDRV_POOL_TAG); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "<-- NICRemoveAllWakeUpPatterns\n"); + +} + + +NTSTATUS +NICConfigureForWakeUp( + IN PFDO_DATA FdoData, + IN BOOLEAN AddPattern + ) +/*++ +Routine Description: + + +Arguments: + + FdoData FdoData structure + +Return Value: + + Success - if successful. + +--*/ +{ +#define MAX_WAKEUP_PATTERN_LENGTH 128 + + UCHAR Buffer[sizeof(NDIS_PM_PACKET_PATTERN) + + MAX_WAKEUP_PATTERN_LENGTH]; + PCHAR patternBuffer, nextMask, nextPattern; + ULONG maskLen; + PNDIS_PM_PACKET_PATTERN ndisPattern; + ULONG bufLen; + NTSTATUS status; + ULONG unUsed; + CHAR wakePattern[]={0xff,0xff,0xff,0xff,0xff,0xff}; //broadcast address + + patternBuffer = (PCHAR)&Buffer[0]; + + ndisPattern = (PNDIS_PM_PACKET_PATTERN)patternBuffer; + RtlZeroMemory(ndisPattern, sizeof(NDIS_PM_PACKET_PATTERN)); + + + ndisPattern->PatternSize = sizeof(wakePattern); + + maskLen = (ndisPattern->PatternSize-1)/8 + 1; + + nextMask = (PCHAR)patternBuffer + sizeof(NDIS_PM_PACKET_PATTERN); + + nextPattern = nextMask + maskLen; + + *nextMask = 0x3f; + + ndisPattern->MaskSize = maskLen; + ndisPattern->PatternOffset = (ULONG) ((ULONG_PTR) nextPattern - (ULONG_PTR) patternBuffer); + + bufLen = sizeof(NDIS_PM_PACKET_PATTERN) + maskLen + ndisPattern->PatternSize; + + RtlCopyMemory(nextPattern, FdoData->CurrentAddress, ETHERNET_ADDRESS_LENGTH); + + if(AddPattern){ + status = NICAddWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICAddWakeupPattern failed %x\n", status); + } + }else{ + status = NICRemoveWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "NICRemoveWakeUpPattern failed %x\n", status); + } + } + + return status; +} + +#if 0 +NTSTATUS +NICConfigureForWakeUp( + IN PFDO_DATA FdoData, + IN BOOLEAN AddPattern + ) +{ +#define MAX_WAKEUP_PATTERN_LENGTH 128 +#define ETHER_IP_ICMP_HEADER_SIZE 14+20+8 + + UCHAR Buffer[sizeof(NDIS_PM_PACKET_PATTERN) + + MAX_WAKEUP_PATTERN_LENGTH]; + PCHAR patternBuffer, nextMask, nextPattern; + ULONG maskLen; + PNDIS_PM_PACKET_PATTERN ndisPattern; + ULONG bufLen; + NTSTATUS status; + ULONG unUsed; + CHAR pingPattern[]={'a','b','c','d','e','f','g','h'}; + + patternBuffer = (PCHAR)&Buffer[0]; + + ndisPattern = (PNDIS_PM_PACKET_PATTERN)patternBuffer; + RtlZeroMemory(ndisPattern, sizeof(NDIS_PM_PACKET_PATTERN)); + + + ndisPattern->PatternSize = ETHER_IP_ICMP_HEADER_SIZE + sizeof(pingPattern); + + maskLen = (ndisPattern->PatternSize-1)/8 + 1; + + nextMask = (PCHAR)patternBuffer + sizeof(NDIS_PM_PACKET_PATTERN); + + nextPattern = nextMask + maskLen; + + *nextMask = 0x0;nextMask++; + *nextMask = 0x0;nextMask++; + *nextMask = 0x0;nextMask++; + *nextMask = 0x0;nextMask++; + *nextMask = 0x0;nextMask++; + *nextMask = 0x3f;nextMask++; + *nextMask = 0x0C; + + ndisPattern->MaskSize = maskLen; + ndisPattern->PatternOffset = (ULONG) ((ULONG_PTR) nextPattern - (ULONG_PTR) patternBuffer); + + bufLen = sizeof(NDIS_PM_PACKET_PATTERN) + maskLen + ndisPattern->PatternSize; + + RtlZeroMemory(nextPattern, ETHER_IP_ICMP_HEADER_SIZE); + nextPattern += ETHER_IP_ICMP_HEADER_SIZE; + + RtlCopyMemory(nextPattern, pingPattern, sizeof(pingPattern)); + + if(AddPattern){ + status = MPAddWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "MpAddWakeupPattern failed %x\n", status); + } + }else{ + status = MPRemoveWakeUpPattern(FdoData, Buffer, bufLen, &unUsed, &unUsed); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, "MPRemoveWakeUpPattern failed %x\n", status); + } + } + + return status; +} + +#endif + + diff --git a/general/pcidrv/kmdf/HW/nic_recv.c b/general/pcidrv/kmdf/HW/nic_recv.c new file mode 100644 index 00000000..41cc0ec7 --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_recv.c @@ -0,0 +1,630 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + NIC_RECV.C + +Abstract: + This module contains miniport receive routines + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "nic_recv.tmh" +#endif + + +_IRQL_requires_same_ +_IRQL_requires_(DISPATCH_LEVEL) +_Requires_lock_held_(FdoData->RcvLock) +VOID +NICHandleRecvInterrupt( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Interrupt handler for receive processing. Put the received packets + into an array and call NICServiceReadIrps. If we run low on + RFDs, allocate another one. + + Assumption: This function is called with the Rcv SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + PMP_RFD pMpRfd = NULL; + PHW_RFD pHwRfd = NULL; + + PMP_RFD PacketArray[NIC_DEF_RFDS]; + PMP_RFD PacketFreeArray[NIC_DEF_RFDS]; + UINT PacketArrayCount; + UINT PacketFreeCount; + UINT Index; + UINT LoopIndex = 0; + UINT LoopCount = NIC_MAX_RFDS / NIC_DEF_RFDS + 1; // avoid staying here too long + + BOOLEAN bContinue = TRUE; + BOOLEAN bAllocNewRfd = FALSE; + USHORT PacketStatus; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICHandleRecvInterrupt\n"); + + ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS); + + while (LoopIndex++ < LoopCount && bContinue) + { + PacketArrayCount = 0; + PacketFreeCount = 0; + + // + // Process up to the array size RFD's + // + while (PacketArrayCount < NIC_DEF_RFDS) + { + if (IsListEmpty(&FdoData->RecvList)) + { + ASSERT(FdoData->nReadyRecv == 0); + bContinue = FALSE; + break; + } + + // + // Get the next MP_RFD to process + // + pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); + + // + // Get the associated HW_RFD + // + pHwRfd = pMpRfd->HwRfd; + + // + // Is this packet completed? + // + PacketStatus = NIC_RFD_GET_STATUS(pHwRfd); + if (!NIC_RFD_STATUS_COMPLETED(PacketStatus)) + { + bContinue = FALSE; + break; + } + + // + // HW specific - check if actual count field has been updated + // + if (!NIC_RFD_VALID_ACTUALCOUNT(pHwRfd)) + { + bContinue = FALSE; + break; + } + + + // + // Remove the RFD from the head of the List + // + RemoveEntryList((PLIST_ENTRY)pMpRfd); + FdoData->nReadyRecv--; + + ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_READY)); + MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_READY); + + // + // A good packet? drop it if not. + // + if (!NIC_RFD_STATUS_SUCCESS(PacketStatus)) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_READ, + "Receive failure = %x\n", PacketStatus); + NICReturnRFD(FdoData, pMpRfd); + continue; + } + + // + // Do not receive any packets until a filter has been set + // + if (!FdoData->PacketFilter) + { + NICReturnRFD(FdoData, pMpRfd); + continue; + } + + // + // Do not receive any packets until we are at D0 + // + if (FdoData->DevicePowerState != PowerDeviceD0) + { + NICReturnRFD(FdoData, pMpRfd); + continue; + } + + pMpRfd->PacketSize = NIC_RFD_GET_PACKET_SIZE(pHwRfd); + + KeFlushIoBuffers(pMpRfd->Mdl, TRUE, TRUE); + + // + // set the status on the packet, either resources or success + // + if (FdoData->nReadyRecv >= MIN_NUM_RFD) + { + MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_PEND); + + } + else + { + MP_SET_FLAG(pMpRfd, fMP_RFD_RESOURCES); + + _Analysis_assume_(PacketFreeCount <= PacketArrayCount); + PacketFreeArray[PacketFreeCount] = pMpRfd; + PacketFreeCount++; + + // + // Reset the RFD shrink count - don't attempt to shrink RFD + // + FdoData->RfdShrinkCount = 0; + + // + // Remember to allocate a new RFD later + // + bAllocNewRfd = TRUE; + } + + PacketArray[PacketArrayCount] = pMpRfd; + PacketArrayCount++; + } + + // + // if we didn't process any receives, just return from here + // + if (PacketArrayCount == 0) + { + break; + } + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockAcquire(FdoData->Lock); + // + // if we have a Recv interrupt and have reported a media disconnect status + // time to indicate the new status + // + + if (Disconnected == FdoData->MediaState) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_READ, "Media state changed to Connected\n"); + + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE); + + FdoData->MediaState = Connected; + + + WdfSpinLockRelease(FdoData->Lock); + // + // Indicate the media event + // + NICServiceIndicateStatusIrp(FdoData); + } + + else + { + + WdfSpinLockRelease(FdoData->Lock); + } + + + NICServiceReadIrps( + FdoData, + PacketArray, + PacketArrayCount); + + + WdfSpinLockAcquire(FdoData->RcvLock); + + // + // Return all the RFDs to the pool. + // + for (Index = 0; Index < PacketFreeCount; Index++) + { + + // + // Get the MP_RFD saved in this packet, in NICAllocRfd + // + pMpRfd = PacketFreeArray[Index]; + + ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RESOURCES)); + MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RESOURCES); + + NICReturnRFD(FdoData, pMpRfd); + } + + } + + // + // If we ran low on RFD's, we need to allocate a new RFD + // + if (bAllocNewRfd) + { + // + // Allocate one more RFD only if it doesn't exceed the max RFD limit + // + if (FdoData->CurrNumRfd < FdoData->MaxNumRfd + && !FdoData->AllocNewRfd) + { + NTSTATUS status; + + FdoData->AllocNewRfd = TRUE; + + // + // Since we are running at DISPATCH_LEVEL, we will queue a workitem + // to allocate RFD memory at PASSIVE_LEVEL. Note that + // AllocateCommonBuffer and FreeCommonBuffer can be called only at + // PASSIVE_LEVEL. + // + status = PciDrvQueuePassiveLevelCallback(FdoData, + NICAllocRfdWorkItem, + NULL, NULL); + if(!NT_SUCCESS(status)){ + FdoData->AllocNewRfd = FALSE; + } + } + } + + ASSERT(FdoData->nReadyRecv >= NIC_MIN_RFDS); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICHandleRecvInterrupt\n"); +} + +VOID +NICReturnRFD( + IN PFDO_DATA FdoData, + IN PMP_RFD pMpRfd + ) +/*++ +Routine Description: + + Recycle a RFD and put it back onto the receive list + + Assumption: This function is called with the Rcv SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + pMpRfd Pointer to the RFD + +Return Value: + + None + +--*/ +{ + PMP_RFD pLastMpRfd; + PHW_RFD pHwRfd = pMpRfd->HwRfd; + + ASSERT(pMpRfd->Flags == 0); + MP_SET_FLAG(pMpRfd, fMP_RFD_RECV_READY); + + // + // HW_SPECIFIC_START + // + pHwRfd->RfdCbHeader.CbStatus = 0; + pHwRfd->RfdActualCount = 0; + pHwRfd->RfdCbHeader.CbCommand = (RFD_EL_BIT); + pHwRfd->RfdCbHeader.CbLinkPointer = DRIVER_NULL; + + // + // Append this RFD to the RFD chain + if (!IsListEmpty(&FdoData->RecvList)) + { + pLastMpRfd = (PMP_RFD)GetListTailEntry(&FdoData->RecvList); + + // Link it onto the end of the chain dynamically + pHwRfd = pLastMpRfd->HwRfd; + pHwRfd->RfdCbHeader.CbLinkPointer = pMpRfd->HwRfdPhys; + pHwRfd->RfdCbHeader.CbCommand = 0; + } + + // + // HW_SPECIFIC_END + // + + // + // The processing on this RFD is done, so put it back on the tail of + // our list + // + InsertTailList(&FdoData->RecvList, (PLIST_ENTRY)pMpRfd); + FdoData->nReadyRecv++; + ASSERT(FdoData->nReadyRecv <= FdoData->CurrNumRfd); +} + +_Requires_lock_held_(FdoData->RcvLock) +NTSTATUS +NICStartRecv( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Start the receive unit if it's not in a ready state + + Assumption: This function is called with the Rcv SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + NT Status code + +--*/ +{ + PMP_RFD pMpRfd; + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "---> NICStartRecv\n"); + + // + // If the receiver is ready, then don't try to restart. + // + if (NIC_IS_RECV_READY(FdoData)) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Receive unit already active\n"); + return STATUS_SUCCESS; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Re-start receive unit...\n"); + ASSERT(!IsListEmpty(&FdoData->RecvList)); + + // + // Get the MP_RFD head + // + pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); + + // + // If more packets are received, clean up RFD chain again + // + if (NIC_RFD_GET_STATUS(pMpRfd->HwRfd)) + { + NICHandleRecvInterrupt(FdoData); + ASSERT(!IsListEmpty(&FdoData->RecvList)); + + // + // Get the new MP_RFD head + // + pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); + } + + // + // Wait for the SCB to clear before we set the general pointer + // + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + goto exit; + } + + if (FdoData->DevicePowerState > PowerDeviceD0) + { + status = STATUS_DEVICE_DATA_ERROR; + goto exit; + } + // + // Set the SCB General Pointer to point the current Rfd + // + FdoData->CSRAddress->ScbGeneralPointer = pMpRfd->HwRfdPhys; + + // + // Issue the SCB RU start command + // + status = D100IssueScbCommand(FdoData, SCB_RUC_START, FALSE); + if (status == STATUS_SUCCESS) + { + // wait for the command to be accepted + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + } + } + + exit: + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<--- NICStartRecv, Status=%x\n", status); + return status; +} + + + +VOID +NICResetRecv( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Reset the receive list + + Assumption: This function is called with the Rcv SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + PMP_RFD pMpRfd; + PHW_RFD pHwRfd; + ULONG RfdCount; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> NICResetRecv\n"); + + ASSERT(!IsListEmpty(&FdoData->RecvList)); + + // + // Get the MP_RFD head + // + pMpRfd = (PMP_RFD)GetListHeadEntry(&FdoData->RecvList); + for (RfdCount = 0; RfdCount < FdoData->nReadyRecv; RfdCount++) + { + pHwRfd = pMpRfd->HwRfd; + pHwRfd->RfdCbHeader.CbStatus = 0; + + pMpRfd = (PMP_RFD)GetListFLink(&pMpRfd->List); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- NICResetRecv\n"); +} + + +VOID +NICServiceReadIrps( + PFDO_DATA FdoData, + PMP_RFD *PacketArray, + ULONG PacketArrayCount + ) +/*++ +Routine Description: + + Copy the data from the recv buffers to pending read IRP buffers + and complete the IRP. When used as network driver, copy operation + can be avoided by devising a private interface between us and the + NDIS-WDM filter and have the NDIS-WDM edge to indicate our buffers + directly to NDIS. + + Called at DISPATCH_LEVEL. Take advantage of that fact while + acquiring spinlocks. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + PMP_RFD pMpRfd = NULL; + ULONG index; + NTSTATUS status; + PVOID buffer; + WDFREQUEST request; + size_t bufLength=0; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "--> NICServiceReadIrps\n"); + + + for(index=0; index < PacketArrayCount; index++) + { + pMpRfd = PacketArray[index]; + ASSERT(pMpRfd); + + status = WdfIoQueueRetrieveNextRequest( FdoData->PendingReadQueue, + &request ); + + if(NT_SUCCESS(status)){ + + WDF_REQUEST_PARAMETERS params; + ULONG length = 0; + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + + WdfRequestGetParameters( + request, + ¶ms + ); + + ASSERT(status == STATUS_SUCCESS); + + bufLength = params.Parameters.Read.Length; + + status = WdfRequestRetrieveOutputBuffer(request, + bufLength, + &buffer, + &bufLength); + if(NT_SUCCESS(status) ) { + + length = min((ULONG)bufLength, pMpRfd->PacketSize); + + RtlCopyMemory(buffer, pMpRfd->Buffer, length); + + Hexdump((TRACE_LEVEL_VERBOSE, DBG_READ, + "Received Packet Data: %!HEXDUMP!\n", + log_xstr(buffer, (USHORT)length))); + FdoData->BytesReceived += length; + } + + WdfRequestCompleteWithInformation(request, status, length); + }else { + ASSERTMSG("WdfIoQueueRetrieveNextRequest failed", + (status == STATUS_NO_MORE_ENTRIES || + status == STATUS_WDF_PAUSED)); + } + + WdfSpinLockAcquire(FdoData->RcvLock); + + ASSERT(MP_TEST_FLAG(pMpRfd, fMP_RFD_RECV_PEND)); + MP_CLEAR_FLAG(pMpRfd, fMP_RFD_RECV_PEND); + + + if (FdoData->RfdShrinkCount < NIC_RFD_SHRINK_THRESHOLD) + { + NICReturnRFD(FdoData, pMpRfd); + } + else + { + ASSERT(FdoData->CurrNumRfd > FdoData->NumRfd); + status = PciDrvQueuePassiveLevelCallback(FdoData, + NICFreeRfdWorkItem, (PVOID)pMpRfd, + NULL); + if(NT_SUCCESS(status)){ + + FdoData->RfdShrinkCount = 0; + FdoData->CurrNumRfd--; + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "Shrink... CurrNumRfd = %d\n", + FdoData->CurrNumRfd); + } else { + // + // We couldn't queue a workitem to free memory, so let us + // put that back in the main pool and try again next time. + // + NICReturnRFD(FdoData, pMpRfd); + } + } + + + WdfSpinLockRelease(FdoData->RcvLock); + + }// end of loop + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, "<-- NICServiceReadIrps\n"); + + return; + +} + + + + diff --git a/general/pcidrv/kmdf/HW/nic_req.c b/general/pcidrv/kmdf/HW/nic_req.c new file mode 100644 index 00000000..2621ee9f --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_req.c @@ -0,0 +1,1453 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + mp_req.c + +Abstract: + This module handle NDIS OID ioctls. This module is not required + if the upper edge is not NDIS. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "nic_req.tmh" +#endif + +// +// Following status values are copied from NDIS.H +// +#define NDIS_STATUS_MEDIA_CONNECT 0x4001000BL +#define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000CL + + +PCHAR DbgGetOidName(ULONG oid); + + +VOID +NICHandleQueryOidRequest( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + WDF_REQUEST_PARAMETERS *Params + ) +/*++ + +Routine Description: + + Query an arbitrary OID value from the miniport. + +Arguments: + + Queue - Default queue handle + Request - IOCTL request handle + Params - pointer to params structure for the request. This is + equivalent to the IRP stack location pointer. + +Return Value: + + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PNDISPROT_QUERY_OID pQuery = NULL; + NDIS_OID Oid = 0; + ULONG ulInfo = 0; + ULONG64 ul64Info = 0; + PVOID pInfo = (PVOID) &ulInfo; + ULONG ulInfoLen = sizeof(ulInfo); + PVOID InformationBuffer = NULL; + ULONG InformationBufferLength = 0; + MEDIA_STATE CurrMediaState; + PVOID DataBuffer; + size_t BufferLength; + NDIS_PNP_CAPABILITIES Power_Management_Capabilities; + PFDO_DATA FdoData = NULL; + + + UNREFERENCED_PARAMETER( Params ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, + "--> HandleQueryOIDRequest \n"); + + FdoData = FdoGetData(WdfIoQueueGetDevice(Queue)); + + // + // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer & + // WdfRequestRetrieveInputBuffer return the same buffer pointer. + // So make sure you read all the information you need from + // the buffer before you write to it. + // + status = WdfRequestRetrieveOutputBuffer(Request, + sizeof(NDISPROT_QUERY_OID), + &DataBuffer, + &BufferLength); + if( !NT_SUCCESS(status) ) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, + "WdfRequestRetrieveInputBuffer failed 0x%x\n", status); + WdfRequestComplete(Request, status); + return; + } + + do { + + pQuery = (PNDISPROT_QUERY_OID)DataBuffer; + Oid = pQuery->Oid; + if(OID_GEN_LINK_SPEED != Oid) { // To avoid flood of trace messages + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "\t%s\n", + DbgGetOidName(Oid)); + } + InformationBuffer = &pQuery->Data[0]; + InformationBufferLength = (ULONG)BufferLength - + FIELD_OFFSET(NDISPROT_QUERY_OID, Data); + + switch(Oid) + { + + case OID_GEN_LINK_SPEED: + case OID_GEN_MEDIA_CONNECT_STATUS: + + if (InformationBufferLength < sizeof(ULONG)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + + WdfSpinLockAcquire(FdoData->Lock); + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) + { + status = WdfRequestForwardToIoQueue(Request, + FdoData->PendingIoctlQueue); + + WdfSpinLockRelease(FdoData->Lock); + if(NT_SUCCESS(status)) { + goto End; + } + break; + } + else + { + + WdfSpinLockRelease(FdoData->Lock); + if (Oid == OID_GEN_LINK_SPEED) + { + ulInfo = FdoData->usLinkSpeed * 10000; + } else { + + CurrMediaState = NICIndicateMediaState(FdoData); + ulInfo = CurrMediaState; + } + } + break; + + case OID_802_3_PERMANENT_ADDRESS: + + if (InformationBufferLength < ETH_LENGTH_OF_ADDRESS) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + pInfo = FdoData->PermanentAddress; + ulInfoLen = ETH_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_CURRENT_ADDRESS: + + if (InformationBufferLength < ETH_LENGTH_OF_ADDRESS) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + pInfo = FdoData->CurrentAddress; + ulInfoLen = ETH_LENGTH_OF_ADDRESS; + break; + + case OID_802_3_MAXIMUM_LIST_SIZE: + + if (InformationBufferLength < sizeof(ULONG)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + ulInfo = NIC_MAX_MCAST_LIST; + break; + + case OID_GEN_XMIT_OK: + case OID_GEN_RCV_OK: + case OID_GEN_XMIT_ERROR: + case OID_GEN_RCV_ERROR: + case OID_GEN_RCV_NO_BUFFER: + case OID_GEN_RCV_CRC_ERROR: + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + case OID_802_3_RCV_ERROR_ALIGNMENT: + case OID_802_3_XMIT_ONE_COLLISION: + case OID_802_3_XMIT_MORE_COLLISIONS: + case OID_802_3_XMIT_DEFERRED: + case OID_802_3_XMIT_MAX_COLLISIONS: + case OID_802_3_RCV_OVERRUN: + case OID_802_3_XMIT_UNDERRUN: + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + case OID_802_3_XMIT_TIMES_CRS_LOST: + case OID_802_3_XMIT_LATE_COLLISIONS: + + if (InformationBufferLength < sizeof(ULONG)) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + ulInfoLen = sizeof(ul64Info); + status = NICGetStatsCounters(FdoData, Oid, &ul64Info); + if (status == STATUS_SUCCESS) + { + ulInfoLen = min(InformationBufferLength, ulInfoLen); + pInfo = &ul64Info; + } + break; + + case OID_PNP_CAPABILITIES: + // + // This query is sent during init to get the PNP capabilities of the device. + // + NICFillPoMgmtCaps (FdoData, + &Power_Management_Capabilities, + (PNDIS_STATUS) &status, + &ulInfoLen); + if (status == STATUS_SUCCESS && + ulInfoLen <= InformationBufferLength) + { + pInfo = (PVOID) &Power_Management_Capabilities; + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + pInfo = NULL; + } + break; + + case OID_PNP_QUERY_POWER: + // + // NDIS sends the query when it receives Query-DIRP. + // As a power policy owner, NDIS generates query-DIRP when it + // receives query-SIRP from the system. + // NDIS will forward the D-IRP to lower stack only if we answer this query + // successfully. + // + status = STATUS_SUCCESS; + break; + + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + } WHILE (FALSE); + + if (status == STATUS_SUCCESS) + { + RtlMoveMemory(InformationBuffer, pInfo, ulInfoLen); + } + // + // Adjust the size to include the structure. + // + ulInfoLen += FIELD_OFFSET(NDISPROT_QUERY_OID, Data); + WdfRequestCompleteWithInformation(Request, status, ulInfoLen); + +End: + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, + "<--HandleQueryOIDRequest: Status %x\n", + status); + + return; + +} + +VOID +NICHandleSetOidRequest( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + WDF_REQUEST_PARAMETERS *Params + ) +/*++ + +Routine Description: + + This routine is called to handle set OID request sent in the ioctl buffer. + If the device is busy, we will forward the request into a queue and complete + it later in the DPC. + +Arguments: + + Queue - Default queue handle + Request - IOCTL request handle + Params - pointer to params structure for the request. This is + equivalent to the IRP stack location pointer. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PNDISPROT_SET_OID pSet; + NDIS_OID Oid; + ULONG PacketFilter; + PVOID InformationBuffer = NULL; + ULONG InformationBufferLength = 0; + PVOID DataBuffer; + size_t BufferLength; + ULONG unUsed; + WDF_POWER_DEVICE_STATE newDeviceState; + WDF_POWER_DEVICE_STATE oldDeviceState; + PFDO_DATA FdoData = NULL; + + UNREFERENCED_PARAMETER( Params ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, + "--> HandleSetOIDRequest\n"); + + FdoData = FdoGetData(WdfIoQueueGetDevice(Queue)); + + // + // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer & + // WdfRequestRetrieveInputBuffer return the same buffer pointer. + // So make sure you read all the information you need from + // the buffer before you write to it. + // + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(NDISPROT_SET_OID), + &DataBuffer, + &BufferLength); + if( !NT_SUCCESS(status) ) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, + "WdfRequestRetrieveInputBuffer failed 0x%x\n", + status); + WdfRequestComplete(Request, status); + return; + } + + Oid = 0; + + do { + + if (BufferLength < sizeof(NDISPROT_SET_OID)) + { + status = STATUS_BUFFER_OVERFLOW; + break; + } + + pSet = (PNDISPROT_SET_OID)DataBuffer; + Oid = pSet->Oid; + InformationBuffer = &pSet->Data[0]; + InformationBufferLength = + (ULONG)BufferLength - FIELD_OFFSET(NDISPROT_SET_OID, Data); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "\t%s\n", + DbgGetOidName(Oid)); + + switch(Oid) + { + + case OID_802_3_MULTICAST_LIST: + // + // Verify the length + // + if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) + { + status = STATUS_INVALID_BUFFER_SIZE; + break; + + } + + // + // Save the number of MC list size + // + FdoData->MCAddressCount = InformationBufferLength / ETH_LENGTH_OF_ADDRESS; + ASSERT(FdoData->MCAddressCount <= NIC_MAX_MCAST_LIST); + + // + // Save the MC list + // + RtlMoveMemory( + FdoData->MCList, + InformationBuffer, + InformationBufferLength); + + + WdfSpinLockAcquire(FdoData->Lock); + + WdfSpinLockAcquire(FdoData->RcvLock); + + status = NICSetMulticastList(FdoData); + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->Lock); + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + // + // Verify the Length + // + if (InformationBufferLength != sizeof(ULONG)) + { + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + + RtlMoveMemory(&PacketFilter, InformationBuffer, sizeof(ULONG)); + + // + // any bits not supported? + // + if (PacketFilter & ~NIC_SUPPORTED_FILTERS) + { + status = STATUS_NOT_SUPPORTED; + break; + } + + // + // any filtering changes? + // + if (PacketFilter == FdoData->PacketFilter) + { + break; + } + + + WdfSpinLockAcquire(FdoData->Lock); + + WdfSpinLockAcquire(FdoData->RcvLock); + + if (MP_TEST_FLAG(FdoData, fMP_ADAPTER_LINK_DETECTION)) + { + + status = WdfRequestForwardToIoQueue(Request, + FdoData->PendingIoctlQueue); + WdfSpinLockRelease(FdoData->RcvLock); + WdfSpinLockRelease(FdoData->Lock); + + if(NT_SUCCESS(status)) { + goto End; + } + + break; + } + + status = NICSetPacketFilter( + FdoData, + PacketFilter); + + + WdfSpinLockRelease(FdoData->RcvLock); + + WdfSpinLockRelease(FdoData->Lock); + + if (status == STATUS_SUCCESS) + { + FdoData->PacketFilter = PacketFilter; + } + + break; + + case OID_PNP_SET_POWER: + + // + // NDIS sends this query when it receives Set D-IRP. As a power policy + // owner, it requests a set D-IRP when it recieves a set S-IRP from the system. + // + if (InformationBufferLength != sizeof(NDIS_DEVICE_POWER_STATE )) + { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + newDeviceState = *(PDEVICE_POWER_STATE UNALIGNED)InformationBuffer; + oldDeviceState = FdoData->DevicePowerState; + FdoData->DevicePowerState = newDeviceState; + // + // Set the power state - Cannot fail this request. + // + status = NICSetPower(FdoData, newDeviceState ); + + if (status != STATUS_SUCCESS) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "SET Power: Hardware error !!!\n"); + break; + } + + status = STATUS_SUCCESS; + break; + + case OID_PNP_ADD_WAKE_UP_PATTERN: + // + // call a function that would program the adapter's wake + // up pattern, return success + // + + status = NICAddWakeUpPattern(FdoData, + InformationBuffer, + InformationBufferLength, + &unUsed, + &unUsed); + break; + + + case OID_PNP_REMOVE_WAKE_UP_PATTERN: + + // + // call a function that would remove the adapter's wake + // up pattern, return success + // + + status = NICRemoveWakeUpPattern(FdoData, + InformationBuffer, + InformationBufferLength, + &unUsed, + &unUsed); + + break; + + case OID_PNP_ENABLE_WAKE_UP: + // + // call a function that would enable wake up on the adapter + // return success + // + if (IsPoMgmtSupported(FdoData)) + { + ULONG WakeUpEnable; + RtlMoveMemory(&WakeUpEnable, InformationBuffer,sizeof(ULONG)); + // + // The WakeUpEable can only be 0, or NDIS_PNP_WAKE_UP_PATTERN_MATCH since the driver only + // supports wake up pattern match + // + if ((WakeUpEnable != 0) + && ((WakeUpEnable & NDIS_PNP_WAKE_UP_PATTERN_MATCH) != NDIS_PNP_WAKE_UP_PATTERN_MATCH )) + { + status = STATUS_NOT_SUPPORTED; + FdoData->AllowWakeArming = FALSE; + break; + } + // + // When the driver goes to low power state, it would check WakeUpEnable to decide + // which wake up methed it should use to wake up the machine. If WakeUpEnable is 0, + // no wake up method is enabled. + // + FdoData->AllowWakeArming = TRUE; + + status = STATUS_SUCCESS; + } + else + { + status = STATUS_NOT_SUPPORTED; + } + + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + } WHILE (FALSE); + + WdfRequestCompleteWithInformation(Request, status, 0); + +End: + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, + "<-- HandleSetOIDRequest %x\n", status); + + return; +} + + +VOID +NICServiceIndicateStatusIrp( + IN PFDO_DATA FdoData + ) +/*++ + +Routine Description: + + We process the IRP based on the input arguments and complete + the IRP. If the IRP was cancelled for some reason we will let + the cancel routine do the IRP completion. + +Arguments: + + Cancel - Should the IRP be cancelled right away. + +Return Value: + + None + +--*/ +{ + PNDISPROT_INDICATE_STATUS pIndicateStatus = NULL; + NTSTATUS status; + ULONG bytes = 0; + size_t bufLength; + WDFREQUEST request; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "-->ndisServiceIndicateStatusIrp\n"); + + status = NICGetIoctlRequest(FdoData->PendingIoctlQueue, + IOCTL_NDISPROT_INDICATE_STATUS, + &request); + + if(!NT_SUCCESS(status)) { + return; + } + + // + // Since the IOCTL is buffered, WdfRequestRetrieveOutputBuffer & + // WdfRequestRetrieveInputBuffer return the same buffer pointer. + // So make sure you read all the information you need from + // the buffer before you write to it. + // + status = WdfRequestRetrieveOutputBuffer(request, sizeof(NDISPROT_INDICATE_STATUS), &pIndicateStatus, &bufLength); + if( !NT_SUCCESS(status) ) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, "WdfRequestRetrieveInputBuffer failed 0x%x\n", status); + WdfRequestComplete(request, status); + return; + } + + // + // Check to see whether the buffer is large enough. + // + + + if(MP_TEST_FLAG(FdoData, fMP_ADAPTER_NO_CABLE)){ + pIndicateStatus->IndicatedStatus = NDIS_STATUS_MEDIA_DISCONNECT; + } else { + pIndicateStatus->IndicatedStatus = NDIS_STATUS_MEDIA_CONNECT; + } + + pIndicateStatus->StatusBufferLength = 0; + pIndicateStatus->StatusBufferOffset = 0; + status = STATUS_SUCCESS; + bytes = sizeof(NDISPROT_INDICATE_STATUS); + WdfRequestCompleteWithInformation(request, status, bytes); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<--ndisServiceIndicateStatusIrp\n"); + return; +} + +NTSTATUS +NICGetIoctlRequest( + IN WDFQUEUE Queue, + IN ULONG FunctionCode, + OUT WDFREQUEST* Request + ) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + WDF_REQUEST_PARAMETERS params; + WDFREQUEST tagRequest; + WDFREQUEST prevTagRequest; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICGetIoctlRequest\n"); + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + + *Request = NULL; + prevTagRequest = tagRequest = NULL; + + do { + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + status = WdfIoQueueFindRequest(Queue, + prevTagRequest, + NULL, + ¶ms, + &tagRequest); + + // + // WdfIoQueueFindRequest takes an extra reference on the returned tagRequest to + // prevent the memory from being freed. However, the tagRequest still + // in the queue and can be cancelled or removed by another thread and + // completed. + // + if(prevTagRequest) { + WdfObjectDereference(prevTagRequest); + } + + if(status == STATUS_NO_MORE_ENTRIES) { + status = STATUS_UNSUCCESSFUL; + break; + } + + if(status == STATUS_NOT_FOUND) { + // + // It seems like prevTagRequest disappeared from the + // queue for some reason - either it got cancelled, got + // dispatched to the driver. There might be other requests + // that match our criteria so let us restart the search. + // + prevTagRequest = tagRequest = NULL; + continue; + } + + if( !NT_SUCCESS(status)) { + // + // Something bad happened. + // + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, + "WdfIoQueueFindRequest failed %!STATUS!\n", status); + status = STATUS_UNSUCCESSFUL; + break; + } + + if(FunctionCode == params.Parameters.DeviceIoControl.IoControlCode){ + + status = WdfIoQueueRetrieveFoundRequest( + Queue, + tagRequest, // TagRequest + Request + ); + + WdfObjectDereference(tagRequest); + + if(status == STATUS_NOT_FOUND) { + // + // It seems like the tagrequest disappeared from the + // queue for some reason - either it got cancelled, got + // dispatched to the driver. There might be other requests + // that match our criteria so let us restart the search. + // + prevTagRequest = tagRequest = NULL; + continue; + } + + if( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, + "WdfIoQueueRetrieveNextRequest failed %!STATUS!\n", status); + status = STATUS_UNSUCCESSFUL; + break; + } + + // + // We got a request. Drop the extra reference taken by peek request before + // returning the call. + // + ASSERT(*Request == tagRequest); + status = STATUS_SUCCESS; + break; + + }else { + // + // This is not the request we need. We will drop the reference + // on the tagrequest after we looking for the next request. + // + prevTagRequest = tagRequest; + continue; + } + + } WHILE (TRUE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICGetIoctlRequest\n"); + + return status; + +} + +MEDIA_STATE +NICIndicateMediaState( + IN PFDO_DATA FdoData + ) +{ + MEDIA_STATE CurrMediaState; + + + WdfSpinLockAcquire(FdoData->Lock); + + CurrMediaState = GetMediaState(FdoData); + + if (CurrMediaState != FdoData->MediaState) + { + TraceEvents(TRACE_LEVEL_WARNING, DBG_IOCTLS, "Media state changed to %s\n", + ((CurrMediaState == Connected)? + "Connected": "Disconnected")); + + FdoData->MediaState = CurrMediaState; + + if (CurrMediaState == Connected) + { + MP_CLEAR_FLAG(FdoData, fMP_ADAPTER_NO_CABLE); + } + else + { + MP_SET_FLAG(FdoData, fMP_ADAPTER_NO_CABLE); + } + + + WdfSpinLockRelease(FdoData->Lock); + + // Indicate the media event + NICServiceIndicateStatusIrp(FdoData); + } + else + { + + WdfSpinLockRelease(FdoData->Lock); + } + + return CurrMediaState; +} + + +NTSTATUS +NICGetStatsCounters( + IN PFDO_DATA FdoData, + IN NDIS_OID Oid, + OUT PULONG64 pCounter + ) +/*++ +Routine Description: + + Get the value for a statistics OID + +Arguments: + + FdoData Pointer to our FdoData + Oid Self-explanatory + pCounter Pointer to receive the value + +Return Value: + + NT Status code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICGetStatsCounters\n"); + + *pCounter = 0; + + DumpStatsCounters(FdoData); + + switch(Oid) + { + case OID_GEN_XMIT_OK: + *pCounter = FdoData->GoodTransmits; + break; + + case OID_GEN_RCV_OK: + *pCounter = FdoData->GoodReceives; + break; + + case OID_GEN_XMIT_ERROR: + *pCounter = FdoData->TxAbortExcessCollisions + + FdoData->TxDmaUnderrun + + FdoData->TxLostCRS + + FdoData->TxLateCollisions; + break; + + case OID_GEN_RCV_ERROR: + *pCounter = FdoData->RcvCrcErrors + + FdoData->RcvAlignmentErrors + + FdoData->RcvResourceErrors + + FdoData->RcvDmaOverrunErrors + + FdoData->RcvRuntErrors; + break; + + case OID_GEN_RCV_NO_BUFFER: + *pCounter = FdoData->RcvResourceErrors; + break; + + case OID_GEN_RCV_CRC_ERROR: + *pCounter = FdoData->RcvCrcErrors; + break; + + case OID_GEN_TRANSMIT_QUEUE_LENGTH: + *pCounter = FdoData->nWaitSend; + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + *pCounter = FdoData->RcvAlignmentErrors; + break; + + case OID_802_3_XMIT_ONE_COLLISION: + *pCounter = FdoData->OneRetry; + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + *pCounter = FdoData->MoreThanOneRetry; + break; + + case OID_802_3_XMIT_DEFERRED: + *pCounter = FdoData->TxOKButDeferred; + break; + + case OID_802_3_XMIT_MAX_COLLISIONS: + *pCounter = FdoData->TxAbortExcessCollisions; + break; + + case OID_802_3_RCV_OVERRUN: + *pCounter = FdoData->RcvDmaOverrunErrors; + break; + + case OID_802_3_XMIT_UNDERRUN: + *pCounter = FdoData->TxDmaUnderrun; + break; + + case OID_802_3_XMIT_HEARTBEAT_FAILURE: + *pCounter = FdoData->TxLostCRS; + break; + + case OID_802_3_XMIT_TIMES_CRS_LOST: + *pCounter = FdoData->TxLostCRS; + break; + + case OID_802_3_XMIT_LATE_COLLISIONS: + *pCounter = FdoData->TxLateCollisions; + break; + + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICGetStatsCounters\n"); + + return(status); +} + +NTSTATUS NICSetPacketFilter( + IN PFDO_DATA FdoData, + IN ULONG PacketFilter + ) +/*++ +Routine Description: + + This routine will set up the FdoData so that it accepts packets + that match the specified packet filter. The only filter bits + that can truly be toggled are for broadcast and promiscuous + +Arguments: + + FdoData Pointer to our FdoData + PacketFilter The new packet filter + +Return Value: + + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR NewParameterField; + UINT i; + BOOLEAN bResult; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICSetPacketFilter, PacketFilter=%08x\n", PacketFilter); + + // + // Need to enable or disable broadcast and promiscuous support depending + // on the new filter + // + NewParameterField = CB_557_CFIG_DEFAULT_PARM15; + + if (PacketFilter & NDIS_PACKET_TYPE_BROADCAST) + { + NewParameterField &= ~CB_CFIG_BROADCAST_DIS; + } + else + { + NewParameterField |= CB_CFIG_BROADCAST_DIS; + } + + if (PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS) + { + NewParameterField |= CB_CFIG_PROMISCUOUS; + } + else + { + NewParameterField &= ~CB_CFIG_PROMISCUOUS; + } + + do + { + if ((FdoData->OldParameterField == NewParameterField ) && + !(PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST)) + { + break; + } + + // + // Only need to do something to the HW if the filter bits have changed. + // + FdoData->OldParameterField = NewParameterField; + ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_CONFIGURE; + ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0; + ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbLinkPointer = DRIVER_NULL; + + // + // First fill in the static (end user can't change) config bytes + // + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[0] = CB_557_CFIG_DEFAULT_PARM0; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[2] = CB_557_CFIG_DEFAULT_PARM2; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] = CB_557_CFIG_DEFAULT_PARM3; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[6] = CB_557_CFIG_DEFAULT_PARM6; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[9] = CB_557_CFIG_DEFAULT_PARM9; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[10] = CB_557_CFIG_DEFAULT_PARM10; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[11] = CB_557_CFIG_DEFAULT_PARM11; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[12] = CB_557_CFIG_DEFAULT_PARM12; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[13] = CB_557_CFIG_DEFAULT_PARM13; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[14] = CB_557_CFIG_DEFAULT_PARM14; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[16] = CB_557_CFIG_DEFAULT_PARM16; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[17] = CB_557_CFIG_DEFAULT_PARM17; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[18] = CB_557_CFIG_DEFAULT_PARM18; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[20] = CB_557_CFIG_DEFAULT_PARM20; + + // + // Set the Tx underrun retries + // + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[7] = + (UCHAR) (CB_557_CFIG_DEFAULT_PARM7 | (FdoData->AiUnderrunRetry << 1)); + + // + // Set the Tx and Rx Fifo limits + // + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[1] = + (UCHAR) ((FdoData->AiTxFifo << 4) | FdoData->AiRxFifo); + + // + // set the MWI enable bit if needed + // + if (FdoData->MWIEnable) + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[3] |= CB_CFIG_B3_MWI_ENABLE; + + // + // Set the Tx and Rx DMA maximum byte count fields. + // + if ((FdoData->AiRxDmaCount) || (FdoData->AiTxDmaCount)) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = + FdoData->AiRxDmaCount; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = + (UCHAR) (FdoData->AiTxDmaCount | CB_CFIG_DMBC_EN); + } + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[4] = + CB_557_CFIG_DEFAULT_PARM4; + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[5] = + CB_557_CFIG_DEFAULT_PARM5; + } + + // + // Setup for MII or 503 operation. The CRS+CDT bit should only be + // set when operating in 503 mode. + // + if (FdoData->PhyAddress == 32) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = + (CB_557_CFIG_DEFAULT_PARM8 & (~CB_CFIG_503_MII)); + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = + (UCHAR) (NewParameterField | CB_CFIG_CRS_OR_CDT); + } + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[8] = + (CB_557_CFIG_DEFAULT_PARM8 | CB_CFIG_503_MII); + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[15] = + (UCHAR) (NewParameterField & (~CB_CFIG_CRS_OR_CDT)); + } + + // + // Setup Full duplex stuff + // + + // + // If forced to half duplex + // + if (FdoData->AiForceDpx == 1) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + (CB_557_CFIG_DEFAULT_PARM19 & + (~(CB_CFIG_FORCE_FDX| CB_CFIG_FDX_ENABLE))); + } + // + // If forced to full duplex + // + else if (FdoData->AiForceDpx == 2) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + (CB_557_CFIG_DEFAULT_PARM19 | CB_CFIG_FORCE_FDX); + } + // + // If auto-duplex + // + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[19] = + CB_557_CFIG_DEFAULT_PARM19; + } + + // + // if multicast all is being turned on, set the bit + // + if (PacketFilter & NDIS_PACKET_TYPE_ALL_MULTICAST) + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = + (CB_557_CFIG_DEFAULT_PARM21 | CB_CFIG_MULTICAST_ALL); + } + else + { + FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[21] = + CB_557_CFIG_DEFAULT_PARM21; + } + + + // + // Wait for the SCB to clear before we check the CU status. + // + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + // + // If we have issued any transmits, then the CU will either be active, + // or in the suspended state. If the CU is active, then we wait for + // it to be suspended. + // + if (FdoData->TransmitIdle == FALSE) + { + // + // Wait for suspended state + // + MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(FdoData); + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + // + // Check the current status of the receive unit + // + if ((FdoData->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) + { + // Issue an RU abort. Since an interrupt will be issued, the + // RU will be started by the DPC. + status = D100IssueScbCommand(FdoData, SCB_RUC_ABORT, TRUE); + if (status != STATUS_SUCCESS) + { + break; + } + } + + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + break; + } + + // + // Restore the transmit software flags. After the multicast + // command is issued, the command unit will be idle, because the + // EL bit will be set in the multicast commmand block. + // + FdoData->TransmitIdle = TRUE; + FdoData->ResumeWait = TRUE; + } + + // + // Display config information + // + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Re-Issuing Configure command for filter change\n"); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Config Block at virt addr %p, phys address %x\n", + &((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus, FdoData->NonTxCmdBlockPhys); + + for (i = 0; i < CB_CFIG_BYTE_COUNT; i++) + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, " Config byte %x = %.2x\n", + i, FdoData->NonTxCmdBlock->NonTxCb.Config.ConfigBytes[i]); + + // + // Submit the configure command to the chip, and wait for it to complete. + // + FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; + status = D100SubmitCommandBlockAndWait(FdoData); + if (status != STATUS_SUCCESS) + { + status = STATUS_DEVICE_NOT_READY; + } + + } WHILE (FALSE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICSetPacketFilter, Status=%x\n", status); + + return(status); +} + +NTSTATUS +NICSetMulticastList( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + This routine will set up the FdoData for a specified multicast address list + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + +--*/ +{ + NTSTATUS status; + PUCHAR McAddress; + UINT i, j; + BOOLEAN bResult; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "--> NICSetMulticastList\n"); + + // + // Setup the command block for the multicast command. + // + for (i = 0; i < FdoData->MCAddressCount; i++) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "MC(%d) = %02x-%02x-%02x-%02x-%02x-%02x\n", + i, + FdoData->MCList[i][0], + FdoData->MCList[i][1], + FdoData->MCList[i][2], + FdoData->MCList[i][3], + FdoData->MCList[i][4], + FdoData->MCList[i][5]); + + McAddress = &FdoData->NonTxCmdBlock->NonTxCb.Multicast.McAddress[i*ETHERNET_ADDRESS_LENGTH]; + + for (j = 0; j < ETH_LENGTH_OF_ADDRESS; j++) + *(McAddress++) = FdoData->MCList[i][j]; + } + + FdoData->NonTxCmdBlock->NonTxCb.Multicast.McCount = + (USHORT)(FdoData->MCAddressCount * ETH_LENGTH_OF_ADDRESS); + ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbStatus = 0; + ((PCB_HEADER_STRUC)FdoData->NonTxCmdBlock)->CbCommand = CB_MULTICAST; + + // + // Wait for the SCB to clear before we check the CU status. + // + if (!WaitScb(FdoData)) + { + status = STATUS_DEVICE_DATA_ERROR; + goto exit; + } + + // + // If we have issued any transmits, then the CU will either be active, or + // in the suspended state. If the CU is active, then we wait for it to be + // suspended. + // + if (FdoData->TransmitIdle == FALSE) + { + // + // Wait for suspended state + // + MP_STALL_AND_WAIT((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 5000, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(FdoData); + status = STATUS_DEVICE_DATA_ERROR; + } + + // + // Restore the transmit software flags. After the multicast command is + // issued, the command unit will be idle, because the EL bit will be + // set in the multicast commmand block. + // + FdoData->TransmitIdle = TRUE; + FdoData->ResumeWait = TRUE; + } + + // + // Update the command list pointer. + // + FdoData->CSRAddress->ScbGeneralPointer = FdoData->NonTxCmdBlockPhys; + + // + // Submit the multicast command to the FdoData and wait for it to complete. + // + status = D100SubmitCommandBlockAndWait(FdoData); + if (status != STATUS_SUCCESS) + { + status = STATUS_DEVICE_NOT_READY; + } + + exit: + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "<-- NICSetMulticastList, Status=%x\n", status); + + return(status); + +} + + +VOID +NICFillPoMgmtCaps ( + IN PFDO_DATA FdoData, + IN OUT PNDIS_PNP_CAPABILITIES pPower_Management_Capabilities, + IN OUT PNDIS_STATUS pStatus, + IN OUT PULONG pulInfoLen + ) +/*++ +Routine Description: + + Fills in the Power Managment structure depending the capabilities of + the software driver and the card. + + Currently this is only supported on 82559 Version of the driver + +Arguments: + + FdoData Pointer to the FdoData structure + pPower_Management_Capabilities - Power management struct as defined in the DDK, + pStatus Status to be returned by the request, + pulInfoLen Length of the pPowerManagmentCapabilites + +Return Value: + + Success or failure depending on the type of card +--*/ + +{ + + BOOLEAN bIsPoMgmtSupported; + + bIsPoMgmtSupported = IsPoMgmtSupported(FdoData); + + if (bIsPoMgmtSupported == TRUE) + { + pPower_Management_Capabilities->Flags = NDIS_DEVICE_WAKE_UP_ENABLE; + pPower_Management_Capabilities->WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; + pPower_Management_Capabilities->WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateD3; + pPower_Management_Capabilities->WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; + *pulInfoLen = sizeof (*pPower_Management_Capabilities); + *pStatus = STATUS_SUCCESS; + } + else + { + RtlZeroMemory (pPower_Management_Capabilities, sizeof(*pPower_Management_Capabilities)); + *pStatus = STATUS_NOT_SUPPORTED; + *pulInfoLen = 0; + + } +} + +PCHAR +DbgGetOidName(ULONG oid) +{ + PCHAR oidName; + + switch (oid){ + + #undef MAKECASE + #define MAKECASE(oidx) case oidx: oidName = #oidx; break; + + MAKECASE(OID_GEN_SUPPORTED_LIST) + MAKECASE(OID_GEN_HARDWARE_STATUS) + MAKECASE(OID_GEN_MEDIA_SUPPORTED) + MAKECASE(OID_GEN_MEDIA_IN_USE) + MAKECASE(OID_GEN_MAXIMUM_LOOKAHEAD) + MAKECASE(OID_GEN_MAXIMUM_FRAME_SIZE) + MAKECASE(OID_GEN_LINK_SPEED) + MAKECASE(OID_GEN_TRANSMIT_BUFFER_SPACE) + MAKECASE(OID_GEN_RECEIVE_BUFFER_SPACE) + MAKECASE(OID_GEN_TRANSMIT_BLOCK_SIZE) + MAKECASE(OID_GEN_RECEIVE_BLOCK_SIZE) + MAKECASE(OID_GEN_VENDOR_ID) + MAKECASE(OID_GEN_VENDOR_DESCRIPTION) + MAKECASE(OID_GEN_CURRENT_PACKET_FILTER) + MAKECASE(OID_GEN_CURRENT_LOOKAHEAD) + MAKECASE(OID_GEN_DRIVER_VERSION) + MAKECASE(OID_GEN_MAXIMUM_TOTAL_SIZE) + MAKECASE(OID_GEN_PROTOCOL_OPTIONS) + MAKECASE(OID_GEN_MAC_OPTIONS) + MAKECASE(OID_GEN_MEDIA_CONNECT_STATUS) + MAKECASE(OID_GEN_MAXIMUM_SEND_PACKETS) + MAKECASE(OID_GEN_VENDOR_DRIVER_VERSION) + MAKECASE(OID_GEN_SUPPORTED_GUIDS) + MAKECASE(OID_GEN_NETWORK_LAYER_ADDRESSES) + MAKECASE(OID_GEN_TRANSPORT_HEADER_OFFSET) + MAKECASE(OID_GEN_MEDIA_CAPABILITIES) + MAKECASE(OID_GEN_PHYSICAL_MEDIUM) + MAKECASE(OID_GEN_XMIT_OK) + MAKECASE(OID_GEN_RCV_OK) + MAKECASE(OID_GEN_XMIT_ERROR) + MAKECASE(OID_GEN_RCV_ERROR) + MAKECASE(OID_GEN_RCV_NO_BUFFER) + MAKECASE(OID_GEN_DIRECTED_BYTES_XMIT) + MAKECASE(OID_GEN_DIRECTED_FRAMES_XMIT) + MAKECASE(OID_GEN_MULTICAST_BYTES_XMIT) + MAKECASE(OID_GEN_MULTICAST_FRAMES_XMIT) + MAKECASE(OID_GEN_BROADCAST_BYTES_XMIT) + MAKECASE(OID_GEN_BROADCAST_FRAMES_XMIT) + MAKECASE(OID_GEN_DIRECTED_BYTES_RCV) + MAKECASE(OID_GEN_DIRECTED_FRAMES_RCV) + MAKECASE(OID_GEN_MULTICAST_BYTES_RCV) + MAKECASE(OID_GEN_MULTICAST_FRAMES_RCV) + MAKECASE(OID_GEN_BROADCAST_BYTES_RCV) + MAKECASE(OID_GEN_BROADCAST_FRAMES_RCV) + MAKECASE(OID_GEN_RCV_CRC_ERROR) + MAKECASE(OID_GEN_TRANSMIT_QUEUE_LENGTH) + MAKECASE(OID_GEN_GET_TIME_CAPS) + MAKECASE(OID_GEN_GET_NETCARD_TIME) + MAKECASE(OID_GEN_NETCARD_LOAD) + MAKECASE(OID_GEN_DEVICE_PROFILE) + MAKECASE(OID_GEN_INIT_TIME_MS) + MAKECASE(OID_GEN_RESET_COUNTS) + MAKECASE(OID_GEN_MEDIA_SENSE_COUNTS) + MAKECASE(OID_PNP_CAPABILITIES) + MAKECASE(OID_PNP_SET_POWER) + MAKECASE(OID_PNP_QUERY_POWER) + MAKECASE(OID_PNP_ADD_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_REMOVE_WAKE_UP_PATTERN) + MAKECASE(OID_PNP_ENABLE_WAKE_UP) + MAKECASE(OID_802_3_PERMANENT_ADDRESS) + MAKECASE(OID_802_3_CURRENT_ADDRESS) + MAKECASE(OID_802_3_MULTICAST_LIST) + MAKECASE(OID_802_3_MAXIMUM_LIST_SIZE) + MAKECASE(OID_802_3_MAC_OPTIONS) + MAKECASE(OID_802_3_RCV_ERROR_ALIGNMENT) + MAKECASE(OID_802_3_XMIT_ONE_COLLISION) + MAKECASE(OID_802_3_XMIT_MORE_COLLISIONS) + MAKECASE(OID_802_3_XMIT_DEFERRED) + MAKECASE(OID_802_3_XMIT_MAX_COLLISIONS) + MAKECASE(OID_802_3_RCV_OVERRUN) + MAKECASE(OID_802_3_XMIT_UNDERRUN) + MAKECASE(OID_802_3_XMIT_HEARTBEAT_FAILURE) + MAKECASE(OID_802_3_XMIT_TIMES_CRS_LOST) + MAKECASE(OID_802_3_XMIT_LATE_COLLISIONS) + + default: + oidName = "<** UNKNOWN OID **>"; + break; + } + + return oidName; +} + + diff --git a/general/pcidrv/kmdf/HW/nic_send.c b/general/pcidrv/kmdf/HW/nic_send.c new file mode 100644 index 00000000..dafabed1 --- /dev/null +++ b/general/pcidrv/kmdf/HW/nic_send.c @@ -0,0 +1,838 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + nic_send.c + +Abstract: + This module contains routines to write packets. + +Environment: + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "nic_send.tmh" +#endif + +_IRQL_requires_same_ +_IRQL_requires_(DISPATCH_LEVEL) +_Requires_lock_held_(FdoData->SendLock) +__inline +VOID +MP_FREE_SEND_PACKET( + IN PFDO_DATA FdoData, + IN PMP_TCB pMpTcb, + IN NTSTATUS Status + ) +/*++ +Routine Description: + + Recycle a MP_TCB and complete the packet if necessary + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + pMpTcb Pointer to MP_TCB + +Return Value: + + None + +--*/ +{ + + WDFREQUEST request; + WDFDMATRANSACTION dmaTransaction; + size_t length; + + ASSERT(MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); + + dmaTransaction = pMpTcb->DmaTransaction; + pMpTcb->DmaTransaction = NULL; + + MP_CLEAR_FLAGS(pMpTcb); + + FdoData->CurrSendHead = FdoData->CurrSendHead->Next; + FdoData->nBusySend--; + + request = WdfDmaTransactionGetRequest(dmaTransaction); + length = WdfDmaTransactionGetBytesTransferred(dmaTransaction); + + WdfObjectDelete( dmaTransaction ); + + if (request) + { + WdfSpinLockRelease(FdoData->SendLock); + WdfRequestCompleteWithInformation(request, Status, length); + FdoData->BytesTransmitted += length; + + WdfSpinLockAcquire(FdoData->SendLock); + } +} + +VOID +PciDrvEvtIoWrite( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t Length + ) +/*++ + +Routine Description: + + Called by the framework as soon as it receive a write IRP. + If the device is not ready, fail the request. Otherwise + get scatter-gather list for this request and send the + packet to the hardware for DMA. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + Length - Length of the IO operation + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + +--*/ +{ + NTSTATUS status; + PFDO_DATA FdoData; + WDFDEVICE hDevice; + PMDL mdl = NULL; + + UNREFERENCED_PARAMETER(Length); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> PciDrvEvtIoWrite Request %p\n", Request); + + hDevice = WdfIoQueueGetDevice(Queue); + FdoData = FdoGetData(hDevice); + + status = WdfRequestRetrieveInputWdmMdl(Request, &mdl); + if (!NT_SUCCESS(status)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfRequestRetrieveInputWdmMdl failed %x\n", status); + WdfRequestCompleteWithInformation(Request, status, 0); + + } else { + + status = NICInitiateDmaTransfer(FdoData, Request); + if(!NT_SUCCESS(status)) { + + WdfRequestCompleteWithInformation(Request, status, 0); + } + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- PciDrvEvtIoWrite %X\n", status); + + return; +} + +NTSTATUS +NICInitiateDmaTransfer( + IN PFDO_DATA FdoData, + IN WDFREQUEST Request + ) +{ + WDFDMATRANSACTION dmaTransaction; + NTSTATUS status; + BOOLEAN bCreated = FALSE; + + do { + // + // Create a new DmaTransaction. + // + status = WdfDmaTransactionCreate( FdoData->WdfDmaEnabler, + WDF_NO_OBJECT_ATTRIBUTES, + &dmaTransaction ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionCreate failed %X\n", status); + break; + } + + bCreated = TRUE; + // + // Initialize the new DmaTransaction. + // + + status = WdfDmaTransactionInitializeUsingRequest( + dmaTransaction, + Request, + NICEvtProgramDmaFunction, + WdfDmaDirectionWriteToDevice ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionInitalizeUsingRequest failed %X\n", + status); + break; + } + + // + // Execute this DmaTransaction. + // + status = WdfDmaTransactionExecute( dmaTransaction, + dmaTransaction ); + + if(!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "WdfDmaTransactionExecute failed %X\n", status); + break; + } + + } WHILE (FALSE); + + if(!NT_SUCCESS(status)){ + + if(bCreated) { + WdfObjectDelete( dmaTransaction ); + + } + } + + return status; +} + + +BOOLEAN +NICEvtProgramDmaFunction( + IN WDFDMATRANSACTION Transaction, + IN WDFDEVICE Device, + IN PVOID Context, + IN WDF_DMA_DIRECTION Direction, + IN PSCATTER_GATHER_LIST ScatterGather + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + PFDO_DATA fdoData; + WDFREQUEST request; + NTSTATUS status; + + UNREFERENCED_PARAMETER( Context ); + UNREFERENCED_PARAMETER( Direction ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICEvtProgramDmaFunction\n"); + + fdoData = FdoGetData(Device); + request = WdfDmaTransactionGetRequest(Transaction); + + + WdfSpinLockAcquire(fdoData->SendLock); + + // + // If tcb or link is not available, queue the request + // + if (!MP_TCB_RESOURCES_AVAIABLE(fdoData) || + MP_TEST_FLAG(fdoData, fMP_ADAPTER_LINK_DETECTION)) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "Resource is not available: queue Request %p\n", request); + + // + // Must abort the transaction before deleting. + // + (VOID) WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); + ASSERT(NT_SUCCESS(status)); + WdfObjectDelete( Transaction ); + + // + // Queue the request for later processing. + // + status = WdfRequestForwardToIoQueue(request, + fdoData->PendingWriteQueue); + + if(!NT_SUCCESS(status)) { + ASSERTMSG(" WdfRequestForwardToIoQueue failed ", FALSE); + WdfSpinLockRelease(fdoData->SendLock); + WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); + return FALSE; + } + fdoData->nWaitSend++; + + } else { + + status = NICWritePacket(fdoData, Transaction, ScatterGather); + + if(!NT_SUCCESS(status)){ + + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "<-- NICEvtProgramDmaFunction returning %!STATUS!\n", + status); + // + // Must abort the transaction before deleting. + // + (VOID )WdfDmaTransactionDmaCompletedFinal(Transaction, 0, &status); + ASSERT(NT_SUCCESS(status)); + WdfObjectDelete( Transaction ); + + WdfSpinLockRelease(fdoData->SendLock); + WdfRequestCompleteWithInformation(request, STATUS_UNSUCCESSFUL, 0); + return FALSE; + } + } + + + WdfSpinLockRelease(fdoData->SendLock); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- NICEvtProgramDmaFunction\n"); + + return TRUE; +} + + +NTSTATUS +NICWritePacket( + IN PFDO_DATA FdoData, + IN WDFDMATRANSACTION DmaTransaction, + IN PSCATTER_GATHER_LIST SGList + ) +/*++ +Routine Description: + + Do the work to send a packet + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + +--*/ +{ + PMP_TCB pMpTcb = NULL; + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICWritePacket: SGList %p\n", SGList); + + // + // Initialize the Transfer Control Block. + // + pMpTcb = FdoData->CurrSendTail; + ASSERT(!MP_TEST_FLAG(pMpTcb, fMP_TCB_IN_USE)); + + pMpTcb->DmaTransaction = DmaTransaction; + + MP_SET_FLAG(pMpTcb, fMP_TCB_IN_USE); + + // + // Call the send handler, it only needs to deal with the ScatterGather list + // + status = NICSendPacket(FdoData, pMpTcb, SGList); + if(!NT_SUCCESS(status)){ + MP_CLEAR_FLAG(pMpTcb, fMP_TCB_IN_USE); + return status; + } + + FdoData->nBusySend++; + ASSERT(FdoData->nBusySend <= FdoData->NumTcb); + + FdoData->CurrSendTail = FdoData->CurrSendTail->Next; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICWritePacket\n"); + + return status; +} + +NTSTATUS +NICSendPacket( + IN PFDO_DATA FdoData, + IN PMP_TCB pMpTcb, + IN PSCATTER_GATHER_LIST ScatterGather + ) +/*++ +Routine Description: + + NIC specific send handler + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + pMpTcb Pointer to MP_TCB + ScatterGather The pointer to the frag list to be filled + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + ULONG index; + UCHAR TbdCount = 0; + + PHW_TCB pHwTcb = pMpTcb->HwTcb; + PTBD_STRUC pHwTbd = pMpTcb->HwTbd; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICSendPacket\n"); + + for (index = 0; index < ScatterGather->NumberOfElements; index++) + { + if (ScatterGather->Elements[index].Length) + { + pHwTbd->TbdBufferAddress = + ScatterGather->Elements[index].Address.LowPart; + + pHwTbd->TbdCount = ScatterGather->Elements[index].Length; + + pHwTbd++; + TbdCount++; + } + } + + pHwTcb->TxCbHeader.CbStatus = 0; + pHwTcb->TxCbHeader.CbCommand = CB_S_BIT | CB_TRANSMIT | CB_TX_SF_BIT; + + pHwTcb->TxCbTbdPointer = pMpTcb->HwTbdPhys; + pHwTcb->TxCbTbdNumber = TbdCount; + pHwTcb->TxCbCount = 0; + pHwTcb->TxCbThreshold = (UCHAR) FdoData->AiThreshold; + + + status = NICStartSend(FdoData, pMpTcb); + + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "NICStartSend returned error %x\n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICSendPacket\n"); + + return status; +} + +NTSTATUS +NICStartSend( + IN PFDO_DATA FdoData, + IN PMP_TCB pMpTcb + ) +/*++ +Routine Description: + + Issue a send command to the NIC + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + pMpTcb Pointer to MP_TCB + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "--> NICStartSend\n"); + + // + // If the transmit unit is idle (very first transmit) then we must + // setup the general pointer and issue a full CU-start + // + if (FdoData->TransmitIdle) + { + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "CU is idle -- First TCB added to Active List\n"); + + // + // Wait for the SCB to clear before we set the general pointer + // + if (!WaitScb(FdoData)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "NICStartSend -- WaitScb returned error\n"); + status = STATUS_DEVICE_DATA_ERROR; + goto exit; + } + + // + // Don't try to start the transmitter if the command unit is not + // idle ((not idle) == (Cu-Suspended or Cu-Active)). + // + if ((FdoData->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_IDLE) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "FdoData = %p, CU Not IDLE\n", FdoData); + MP_SET_HARDWARE_ERROR(FdoData); + KeStallExecutionProcessor(25); + } + + FdoData->CSRAddress->ScbGeneralPointer = pMpTcb->HwTcbPhys; + + status = D100IssueScbCommand(FdoData, SCB_CUC_START, FALSE); + + FdoData->TransmitIdle = FALSE; + FdoData->ResumeWait = TRUE; + } + else + { + // + // If the command unit has already been started, then append this + // TCB onto the end of the transmit chain, and issue a CU-Resume. + // + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "adding TCB to Active chain\n"); + + // + // Clear the suspend bit on the previous packet. + // + pMpTcb->PrevHwTcb->TxCbHeader.CbCommand &= ~CB_S_BIT; + + // + // Issue a CU-Resume command to the device. We only need to do a + // WaitScb if the last command was NOT a RESUME. + // + status = D100IssueScbCommand(FdoData, + SCB_CUC_RESUME, + FdoData->ResumeWait); + } + + exit: + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, "<-- NICStartSend\n"); + + return status; +} + +_Requires_lock_held_(FdoData->SendLock) +NTSTATUS +NICHandleSendInterrupt( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Interrupt handler for sending processing. Re-claim the send resources, + complete sends and get more to send from the send wait queue. + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + NTSTATUS code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PMP_TCB pMpTcb; + +#if DBG + ULONG i; +#endif + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICHandleSendInterrupt\n"); + + // + // Any packets being sent? Any packet waiting in the send queue? + // + if (FdoData->nBusySend == 0) + { + ASSERT(FdoData->CurrSendHead == FdoData->CurrSendTail); + return status; + } + + // + // Check the first TCB on the send list + // + while (FdoData->nBusySend > 0) + { + +#if DBG + pMpTcb = FdoData->CurrSendHead; + for (i = 0; i < FdoData->nBusySend; i++) + { + pMpTcb = pMpTcb->Next; + } + + if (pMpTcb != FdoData->CurrSendTail) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "nBusySend= %d\n", FdoData->nBusySend); + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "CurrSendhead= %p\n", FdoData->CurrSendHead); + TraceEvents(TRACE_LEVEL_ERROR, DBG_WRITE, + "CurrSendTail= %p\n", FdoData->CurrSendTail); + ASSERT(FALSE); + } +#endif + + pMpTcb = FdoData->CurrSendHead; + + // + // Is this TCB completed? + // + if (pMpTcb->HwTcb->TxCbHeader.CbStatus & CB_STATUS_COMPLETE) + { + // + // Check if this is a multicast hw workaround packet + // + if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST) + { + BOOLEAN transactionComplete; + + ASSERT(pMpTcb->DmaTransaction); + + // + // Indicate this DMA operation has completed: + // This may drive the transfer on the next packet if + // there is still data to be transfered in the DmaTransaction. + // + transactionComplete = + WdfDmaTransactionDmaCompleted( pMpTcb->DmaTransaction, + &status ); + + if(transactionComplete == TRUE) { + + ASSERT(status == STATUS_SUCCESS); + MP_FREE_SEND_PACKET(FdoData, pMpTcb, status); + + } else { + // + // NOTE: For this ethernet driver this should never + // be returned as the packets are <= 1514 bytes. + // It is included to show the complete DmaTransaction + // coding pattern. + // + ASSERT(!"STATUS_MORE_PROCESSING_REQUIRED"); + } + + } + else + { + + // Multicast workaround would be here (???) + + } + } + else + { + break; + } + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- NICHandleSendInterrupt\n"); + return status; +} + +VOID +NICCheckForQueuedSends( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + +--*/ +{ + WDFREQUEST request; + WDFDMATRANSACTION dmaTransaction; + NTSTATUS status; + + UNREFERENCED_PARAMETER( dmaTransaction ); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICCheckForQueuedSends\n"); + + // + // If we queued any transmits because we didn't have any TCBs earlier, + // dequeue and send those packets now, as long as we have free TCBs. + // + while (MP_TCB_RESOURCES_AVAIABLE(FdoData)) + { + status = WdfIoQueueRetrieveNextRequest( + FdoData->PendingWriteQueue, + &request + ); + + if(!NT_SUCCESS(status) ) { + if(STATUS_NO_MORE_ENTRIES != status) { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "WdfIoQueueRetrieveNextRequest failed %X\n", status); + } + break; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "\t processing Request %p \n", request); + + status = NICInitiateDmaTransfer(FdoData, request); + if(!NT_SUCCESS(status)) { + WdfRequestCompleteWithInformation(request, status, 0); + } + + FdoData->nWaitSend--; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- NICCheckForQueuedSends\n"); +} + +_Requires_lock_held_(FdoData->SendLock) +VOID +NICFreeBusySendPackets( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Free and complete the stopped active sends + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + PMP_TCB pMpTcb; + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICFreeBusySendPackets\n"); + + // + // Any packets being sent? Check the first TCB on the send list + // + while (FdoData->nBusySend > 0) + { + pMpTcb = FdoData->CurrSendHead; + + // + // Is this TCB completed? + // + if ((pMpTcb->HwTcb->TxCbHeader.CbCommand & CB_CMD_MASK) != CB_MULTICAST) + { + MP_FREE_SEND_PACKET(FdoData, pMpTcb, STATUS_SUCCESS); + } + else + { + break; + } + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- NICFreeBusySendPackets\n"); +} + + +_IRQL_requires_same_ +_IRQL_requires_(DISPATCH_LEVEL) +_Requires_lock_held_(FdoData->SendLock) +VOID +NICFreeQueuedSendPackets( + IN PFDO_DATA FdoData + ) +/*++ +Routine Description: + + Free and complete the pended sends on SendQueueHead + + Assumption: This function is called with the Send SPINLOCK held. + +Arguments: + + FdoData Pointer to our FdoData + +Return Value: + + None + +--*/ +{ + WDFREQUEST request; + NTSTATUS status = MP_GET_STATUS_FROM_FLAGS(FdoData); + + if (STATUS_UNSUCCESSFUL == status) { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "MP_GET_STATUS_FROM_FLAGS failed %x\n", status); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "--> NICFreeQueuedSendPackets\n"); + + do { + status = WdfIoQueueRetrieveNextRequest( + FdoData->PendingWriteQueue, + &request + ); + + if(!NT_SUCCESS(status) ) { + if(STATUS_NO_MORE_ENTRIES != status){ + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "WdfIoQueueRetrieveNextRequest failed %x\n", status); + } + break; + } + + FdoData->nWaitSend--; + + WdfSpinLockRelease(FdoData->SendLock); + + WdfRequestCompleteWithInformation(request, status, 0); + + WdfSpinLockAcquire(FdoData->SendLock); + + } WHILE (TRUE); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_WRITE, + "<-- NICFreeQueuedSendPackets\n"); + +} + + diff --git a/general/pcidrv/kmdf/HW/nuiouser.h b/general/pcidrv/kmdf/HW/nuiouser.h new file mode 100644 index 00000000..c33861ae --- /dev/null +++ b/general/pcidrv/kmdf/HW/nuiouser.h @@ -0,0 +1,105 @@ +/*++ + +Copyright (c) 2000 Microsoft Corporation + +Module Name: + + nuiouser.h + +Abstract: + + Constants and types to access the NDISPROT driver. + Users must also include ntddndis.h + +Environment: + + User/Kernel mode. + +--*/ + +#ifndef __NUIOUSER__H +#define __NUIOUSER__H + + +#define FSCTL_NDISPROT_BASE FILE_DEVICE_NETWORK + +#define _NDISPROT_CTL_CODE(_Function, _Method, _Access) \ + CTL_CODE(FSCTL_NDISPROT_BASE, _Function, _Method, _Access) + +#define IOCTL_NDISPROT_OPEN_DEVICE \ + _NDISPROT_CTL_CODE(0x200, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISPROT_QUERY_OID_VALUE \ + _NDISPROT_CTL_CODE(0x201, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISPROT_SET_OID_VALUE \ + _NDISPROT_CTL_CODE(0x205, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISPROT_QUERY_BINDING \ + _NDISPROT_CTL_CODE(0x203, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISPROT_BIND_WAIT \ + _NDISPROT_CTL_CODE(0x204, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_NDISPROT_INDICATE_STATUS \ + _NDISPROT_CTL_CODE(0x206, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + + + +// +// Structure to go with IOCTL_NDISPROT_QUERY_OID_VALUE. +// The Data part is of variable length, determined by +// the input buffer length passed to DeviceIoControl. +// +typedef struct _NDISPROT_QUERY_OID +{ + NDIS_OID Oid; + UCHAR Data[sizeof(ULONG)]; + +} NDISPROT_QUERY_OID, *PNDISPROT_QUERY_OID; + +// +// Structure to go with IOCTL_NDISPROT_SET_OID_VALUE. +// The Data part is of variable length, determined +// by the input buffer length passed to DeviceIoControl. +// +typedef struct _NDISPROT_SET_OID +{ + NDIS_OID Oid; + UCHAR Data[sizeof(ULONG)]; + +} NDISPROT_SET_OID, *PNDISPROT_SET_OID; + + +// +// Structure to go with IOCTL_NDISPROT_QUERY_BINDING. +// The input parameter is BindingIndex, which is the +// index into the list of bindings active at the driver. +// On successful completion, we get back a device name +// and a device descriptor (friendly name). +// +typedef struct _NDISPROT_QUERY_BINDING +{ + ULONG BindingIndex; // 0-based binding number + ULONG DeviceNameOffset; // from start of this struct + ULONG DeviceNameLength; // in bytes + ULONG DeviceDescrOffset; // from start of this struct + ULONG DeviceDescrLength; // in bytes + +} NDISPROT_QUERY_BINDING, *PNDISPROT_QUERY_BINDING; + +// +// Structure to go with IOCTL_NDISPROT_INDICATE_STATUS. +// NDISPROT copies the status indicated by the NIC and +// also the data indicated in the StatusBuffer. +// +typedef struct _NDISPROT_INDICATE_STATUS +{ + ULONG IndicatedStatus; // NDIS_STATUS + ULONG StatusBufferOffset; // from start of this struct + ULONG StatusBufferLength; // in bytes +} NDISPROT_INDICATE_STATUS, *PNDISPROT_INDICATE_STATUS; + +#endif // __NUIOUSER__H + + diff --git a/general/pcidrv/kmdf/HW/physet.c b/general/pcidrv/kmdf/HW/physet.c new file mode 100644 index 00000000..94132fec --- /dev/null +++ b/general/pcidrv/kmdf/HW/physet.c @@ -0,0 +1,1001 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + physet.c + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +//#pragma TRACE_LEVEL_WARNING (disable: 4514) + +//----------------------------------------------------------------------------- +// Procedure: PhyDetect +// +// Description: This routine will detect what phy we are using, set the line +// speed, FDX or HDX, and configure the phy if necessary. +// +// The following combinations are supported: +// - TX or T4 PHY alone at PHY address 1 +// - T4 or TX PHY at address 1 and MII PHY at address 0 +// - 82503 alone (10Base-T mode, no full duplex support) +// - 82503 and MII PHY (TX or T4) at address 0 +// +// The sequence / priority of detection is as follows: +// If there is a PHY Address override use that address. +// else scan based on the 'Connector' setting. +// Switch Connector +// 0 = AutoScan +// 1 = Onboard TPE only +// 2 = MII connector only +// +// Each of the above cases is explained below. +// +// AutoScan means: +// Look for link on addresses 1, 0, 2..31 (in that order). Use the first +// address found that has link. +// If link is not found then use the first valid PHY found in the same scan +// order 1,0,2..31. NOTE: this means that NO LINK or Multi-link cases will +// default to the onboard PHY (address 1). +// +// Onboard TPE only: +// Phy address is set to 1 (No Scanning). +// +// MII connector only means: +// Look for link on addresses 0, 2..31 (again in that order, Note address 1 is +// NOT scanned). Use the first address found that has link. +// If link is not found then use the first valid Phy found in the same scan +// order 0, 2..31. +// In the AutoScan case above we should always find a valid PHY at address 1, +// there is no such guarantee here, so, If NO Phy is found then the driver +// should default to address 0 and continue to load. Note: External +// transceivers should be at address 0 but our early Nitro3 testing found +// transceivers at several non-zero addresses (6,10,14). +// +// +// NWAY +// Additionally auto-negotiation capable (NWAY) and parallel +// detection PHYs are supported. The flow-chart is described in +// the 82557 software writer's manual. +// +// NOTE: 1. All PHY MDI registers are read in polled mode. +// 2. The routines assume that the 82557 has been RESET and we have +// obtained the virtual memory address of the CSR. +// 3. PhyDetect will not RESET the PHY. +// 4. If FORCEFDX is set, SPEED should also be set. The driver will +// check the values for inconsistency with the detected PHY +// technology. +// 5. PHY 1 (the PHY on the adapter) MUST be at address 1. +// 6. Driver ignores FORCEFDX and SPEED overrides if a 503 interface +// is detected. +// +// +// Arguments: +// FdoData - ptr to FdoData object instance +// +// Result: +// Returns: +// STATUS_SUCCESS +// NDIS_STATUS_FAILURE +//----------------------------------------------------------------------------- + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "physet.tmh" +#endif + +NTSTATUS PhyDetect( + IN PFDO_DATA FdoData + ) +{ +#if DBG + USHORT MdiControlReg; + USHORT MdiStatusReg; +#endif + + // + // Check for a phy address over-ride of 32 which indicates a 503 + // + if (FdoData->PhyAddress == 32) + { + // + // 503 interface over-ride + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " 503 serial component over-ride\n"); + + FdoData->PhyAddress = 32; + + // + // Record the current speed and duplex. We will be in half duplex + // mode unless the user used the force full duplex over-ride. + // + FdoData->usLinkSpeed = 10; + FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx; + if (!FdoData->usDuplexMode) + { + FdoData->usDuplexMode = 1; + } + + return(STATUS_SUCCESS); + } + + // + // Check for other phy address over-rides. + // If the Phy Address is between 0-31 then there is an over-ride. + // Or the connector was set to 1 + // + if ((FdoData->PhyAddress < 32) || (FdoData->Connector == CONNECTOR_TPE)) + { + + // + // User Override nothing to do but setup Phy and leave + // + if ((FdoData->PhyAddress > 32) && (FdoData->Connector == CONNECTOR_TPE)) + { + FdoData->PhyAddress = 1; // Connector was forced + + // Isolate all other PHYs and unisolate this one + SelectPhy(FdoData, FdoData->PhyAddress, FALSE); + + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, + " Phy address Override to address %d\n", FdoData->PhyAddress); + +#if DBG + // + // Read the MDI control register at override address. + // + MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg); + + // + // Read the status register at override address. + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + // + // Read the status register again because of sticky bits + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // check if we found a valid phy + // + if (!((MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0)))) + { + // + // we have a valid phy1 + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Over-ride address %d has a valid Phy.\n", FdoData->PhyAddress); + + // + // Read the status register again + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // If there is a valid link then use this Phy. + // + if (MdiStatusReg & MDI_SR_LINK_STATUS) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Phy at address %d has link\n", FdoData->PhyAddress); + } + + } + else + { + // + // no PHY at over-ride address + // + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Over-ride address %d has no Phy!!!!\n", FdoData->PhyAddress); + } +#endif + return(SetupPhy(FdoData)); + } + else // Need to scan - No address over-ride and Connector is AUTO or MII + { + FdoData->CurrentScanPhyIndex = 0; + FdoData->LinkDetectionWaitCount = 0; + FdoData->FoundPhyAt = 0xff; + FdoData->bLookForLink = TRUE; + + return(ScanAndSetupPhy(FdoData)); + + } // End else scan + + +} + +NTSTATUS ScanAndSetupPhy( + IN PFDO_DATA FdoData + ) +{ + USHORT MdiControlReg = 0; + USHORT MdiStatusReg = 0; + + if (FdoData->bLinkDetectionWait) + { + goto NEGOTIATION_WAIT; + } + + SCAN_PHY_START: + + // + // For each PhyAddress 0 - 31 + // + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Index=%d, bLookForLink=%d\n", + FdoData->CurrentScanPhyIndex, FdoData->bLookForLink); + + if (FdoData->bLookForLink) + { + // + // Phy Addresses must be tested in the order 1,0,2..31. + // + switch(FdoData->CurrentScanPhyIndex) + { + case 0: + FdoData->PhyAddress = 1; + break; + + case 1: + FdoData->PhyAddress = 0; + break; + + default: + FdoData->PhyAddress = FdoData->CurrentScanPhyIndex; + break; + } + + // + // Skip OnBoard for MII only case + // + if ((FdoData->PhyAddress == 1)&&(FdoData->Connector == CONNECTOR_MII)) + { + goto SCAN_PHY_NEXT; + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Scanning Phy address %d for link\n", FdoData->PhyAddress); + + // + // Read the MDI control register + // + MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg); + + // + // Read the status register + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + // Sticky Bits + } + else + { + // + // Not looking for link + // + if (FdoData->FoundPhyAt < 32) + { + FdoData->PhyAddress = FdoData->FoundPhyAt; + } + else if (FdoData->Connector == CONNECTOR_MII) + { + // + // No valid PHYs were found last time so just default + // + FdoData->PhyAddress = 0; // Default for MII + } + else + { + // + // assume a 503 interface + // + FdoData->PhyAddress = 32; + + // + // Record the current speed and duplex. We will be in half duplex + // mode unless the user used the force full duplex over-ride. + // + FdoData->usLinkSpeed = 10; + FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx; + if (!FdoData->usDuplexMode) + { + FdoData->usDuplexMode = 1; + } + + return(STATUS_SUCCESS); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " No Links Found!!\n"); + } + + // + // check if we found a valid phy or on !LookForLink pass + // + if (!( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0))) + || (!FdoData->bLookForLink)) + { + + // + // Valid phy or Not looking for Link + // + +#if DBG + if (!( (MdiControlReg == 0xffff) || ((MdiStatusReg == 0) && (MdiControlReg == 0)))) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Found a Phy at address %d\n", FdoData->PhyAddress); + } +#endif + // + // Store highest priority phy found for NO link case + // + if (FdoData->CurrentScanPhyIndex < FdoData->FoundPhyAt && FdoData->FoundPhyAt != 1) + { + // this phy is higher priority + FdoData->FoundPhyAt = (UCHAR) FdoData->PhyAddress; + } + + // + // Select Phy before checking link status + // NOTE: may take up to 3.5 Sec if LookForLink == TRUE + //SelectPhy(FdoData, FdoData->PhyAddress, (BOOLEAN)LookForLink); + // + SelectPhy(FdoData, FdoData->PhyAddress, FALSE); + + NEGOTIATION_WAIT: + + // + // wait for auto-negotiation to complete (up to 3.5 seconds) + // + if (FdoData->LinkDetectionWaitCount++ < RENEGOTIATE_TIME) + { + // Read the status register twice because of sticky bits + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + if (!(MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) + { + return STATUS_PENDING; + } + } + else + { + FdoData->LinkDetectionWaitCount = 0; + } + + // + // Read the MDI control register + // + MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg); + + // + // Read the status register + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // If there is a valid link or we alreadry tried once then use this Phy. + // + if ((MdiStatusReg & MDI_SR_LINK_STATUS) || (!FdoData->bLookForLink)) + { +#if DBG + if (MdiStatusReg & MDI_SR_LINK_STATUS) + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Using Phy at address %d with link\n", FdoData->PhyAddress); + } + else + { + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Using Phy at address %d WITHOUT link!!!\n", FdoData->PhyAddress); + } +#endif + + return(SetupPhy(FdoData)); // Exit with Link Path + } + } // End if valid PHY + + SCAN_PHY_NEXT: + + FdoData->CurrentScanPhyIndex++; + if (FdoData->CurrentScanPhyIndex >= 32) + { + FdoData->bLookForLink = FALSE; + } + + goto SCAN_PHY_START; +} + + +//*************************************************************************** +// +// Name: SelectPhy +// +// Description: This routine will Isolate all Phy addresses on the MII +// Bus except for the one address to be 'selected'. This +// Phy address will be un-isolated and auto-negotiation will +// be enabled, started, and completed. The Phy will NOT be +// reset and the speed will NOT be set to any value (that is +// done in SetupPhy). +// +// Arguments: SelectPhyAddress - PhyAddress to select +// WaitAutoNeg - Flag TRUE = Wait for Auto Negociation to complete. +// FALSE = don't wait. Good for 'No Link' case. +// +// Returns: Nothing +// +// Modification log: +// Date Who Description +// -------- --- -------------------------------------------------------- +//*************************************************************************** +VOID SelectPhy( + IN PFDO_DATA FdoData, + IN UINT SelectPhyAddress, + IN BOOLEAN WaitAutoNeg + ) +{ + UCHAR i; + USHORT MdiControlReg = 0; + USHORT MdiStatusReg = 0; + + // + // Isolate all other phys and unisolate the one to query + // + for (i = 0; i < 32; i++) + { + if (i != SelectPhyAddress) + { + // isolate this phy + MdiWrite(FdoData, MDI_CONTROL_REG, i, MDI_CR_ISOLATE); + // wait 100 microseconds for the phy to isolate. + KeStallExecutionProcessor(100); + } + } + + // unisolate the phy to query + + // + // Read the MDI control register + // + MdiRead(FdoData, MDI_CONTROL_REG, SelectPhyAddress, FALSE, &MdiControlReg); + + // + // Set/Clear bit unisolate this phy + // + MdiControlReg &= ~MDI_CR_ISOLATE; // Clear the Isolate Bit + + // + // issue the command to unisolate this Phy + // + MdiWrite(FdoData, MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg); + + // + // sticky bits on link + // + MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg); + + // + // if we have link, don't mess with the phy + // + if (MdiStatusReg & MDI_SR_LINK_STATUS) + return; + + // + // Read the MDI control register + // + MdiRead(FdoData, MDI_CONTROL_REG, SelectPhyAddress, FALSE, &MdiControlReg); + + // + // set Restart auto-negotiation + // + MdiControlReg |= MDI_CR_AUTO_SELECT; // Set Auto Neg Enable + MdiControlReg |= MDI_CR_RESTART_AUTO_NEG; // Restart Auto Neg + + // + // restart the auto-negotion process + // + MdiWrite(FdoData, MDI_CONTROL_REG, SelectPhyAddress, MdiControlReg); + + // + // wait 200 microseconds for the phy to unisolate. + // + KeStallExecutionProcessor(200); + + if (WaitAutoNeg) + { + // + // wait for auto-negotiation to complete (up to 3.5 seconds) + // + for (i = RENEGOTIATE_TIME; i != 0; i--) + { + // Read the status register twice because of sticky bits + MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, SelectPhyAddress, FALSE, &MdiStatusReg); + + if (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE) + break; + + MP_STALL_EXECUTION(100); + } + } +} + +//----------------------------------------------------------------------------- +// Procedure: SetupPhy +// +// Description: This routine will setup phy 1 or phy 0 so that it is configured +// to match a speed and duplex over-ride option. If speed or +// duplex mode is not explicitly specified in the registry, the +// driver will skip the speed and duplex over-ride code, and +// assume the FdoData is automatically setting the line speed, and +// the duplex mode. At the end of this routine, any truly Phy +// specific code will be executed (each Phy has its own quirks, +// and some require that certain special bits are set). +// +// NOTE: The driver assumes that SPEED and FORCEFDX are specified at the +// same time. If FORCEDPX is set without speed being set, the driver +// will encouter a fatal error and log a message into the event viewer. +// +// Arguments: +// FdoData - ptr to FdoData object instance +// +// Result: +// Returns: +// STATUS_SUCCESS +// NDIS_STATUS_FAILURE +//----------------------------------------------------------------------------- + +NTSTATUS SetupPhy( + IN PFDO_DATA FdoData) +{ + USHORT MdiControlReg = 0; + USHORT MdiStatusReg = 0; + USHORT MdiIdLowReg = 0; + USHORT MdiIdHighReg = 0; + USHORT MdiMiscReg = 0; + UINT PhyId; + BOOLEAN ForcePhySetting = FALSE; + + // + // If we are NOT forcing a setting for line speed or full duplex, then + // we won't force a link setting, and we'll jump down to the phy + // specific code. + // + if (((FdoData->AiTempSpeed) || (FdoData->AiForceDpx))) + { + + // + // Find out what kind of technology this Phy is capable of. + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // Read the MDI control register at our phy + // + MdiRead(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiControlReg); + + // + // Now check the validity of our forced option. If the force option is + // valid, then force the setting. If the force option is not valid, + // we'll set a flag indicating that we should error out. + // + + // + // If speed is forced to 10mb + // + if (FdoData->AiTempSpeed == 10) + { + // If half duplex is forced + if (FdoData->AiForceDpx == 1) + { + if (MdiStatusReg & MDI_SR_10T_HALF_DPX) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb 1/2 duplex\n"); + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + } + } + + // If full duplex is forced + else if (FdoData->AiForceDpx == 2) + { + if (MdiStatusReg & MDI_SR_10T_FULL_DPX) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb full duplex\n"); + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT); + MdiControlReg |= MDI_CR_FULL_HALF; + ForcePhySetting = TRUE; + } + } + + // If auto duplex (we actually set phy to 1/2) + else + { + if (MdiStatusReg & (MDI_SR_10T_FULL_DPX | MDI_SR_10T_HALF_DPX)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 10mb auto duplex\n"); + MdiControlReg &= ~(MDI_CR_10_100 | MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + FdoData->AiForceDpx = 1; + } + } + } + + // + // If speed is forced to 100mb + // + else if (FdoData->AiTempSpeed == 100) + { + // If half duplex is forced + if (FdoData->AiForceDpx == 1) + { + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb half duplex\n"); + MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + MdiControlReg |= MDI_CR_10_100; + ForcePhySetting = TRUE; + } + } + + // If full duplex is forced + else if (FdoData->AiForceDpx == 2) + { + if (MdiStatusReg & MDI_SR_TX_FULL_DPX) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb full duplex\n"); + MdiControlReg &= ~MDI_CR_AUTO_SELECT; + MdiControlReg |= (MDI_CR_10_100 | MDI_CR_FULL_HALF); + ForcePhySetting = TRUE; + } + } + + // If auto duplex (we set phy to 1/2) + else + { + if (MdiStatusReg & (MDI_SR_TX_HALF_DPX | MDI_SR_T4_CAPABLE)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Forcing 100mb auto duplex\n"); + MdiControlReg &= ~(MDI_CR_AUTO_SELECT | MDI_CR_FULL_HALF); + MdiControlReg |= MDI_CR_10_100; + ForcePhySetting = TRUE; + FdoData->AiForceDpx = 1; + } + } + } + + if (ForcePhySetting == FALSE) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Can't force speed=%d, duplex=%d\n",FdoData->AiTempSpeed, FdoData->AiForceDpx); + + return(STATUS_UNSUCCESSFUL); + } + + // + // Write the MDI control register with our new Phy configuration + // + MdiWrite(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, MdiControlReg); + + // + // wait 100 milliseconds for auto-negotiation to complete + // + MP_STALL_EXECUTION(100); + + } + + // + // Find out specifically what Phy this is. We do this because for certain + // phys there are specific bits that must be set so that the phy and the + // 82557 work together properly. + // + MdiRead(FdoData, PHY_ID_REG_1, FdoData->PhyAddress, FALSE, &MdiIdLowReg); + MdiRead(FdoData, PHY_ID_REG_2, FdoData->PhyAddress, FALSE, &MdiIdHighReg); + + PhyId = ((UINT) MdiIdLowReg | ((UINT) MdiIdHighReg << 16)); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, " Phy ID is %x\n", PhyId); + + // + // And out the revsion field of the Phy ID so that we'll be able to detect + // future revs of the same Phy. + // + PhyId &= PHY_MODEL_REV_ID_MASK; + + // + // Handle the National TX + // + if (PhyId == PHY_NSC_TX) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Found a NSC TX Phy\n"); + + MdiRead(FdoData, NSC_CONG_CONTROL_REG, FdoData->PhyAddress, FALSE, &MdiMiscReg); + + MdiMiscReg |= (NSC_TX_CONG_TXREADY | NSC_TX_CONG_F_CONNECT); + + // + // If we are configured to do congestion control, then enable the + // congestion control bit in the National Phy + // + if (FdoData->Congest) + MdiMiscReg |= NSC_TX_CONG_ENABLE; + else + MdiMiscReg &= ~NSC_TX_CONG_ENABLE; + + MdiWrite(FdoData, NSC_CONG_CONTROL_REG, FdoData->PhyAddress, MdiMiscReg); + } + + FindPhySpeedAndDpx(FdoData, PhyId); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Current Speed=%d, Current Duplex=%d\n",FdoData->usLinkSpeed, FdoData->usDuplexMode); + + return(STATUS_SUCCESS); +} + + +//----------------------------------------------------------------------------- +// Procedure: FindPhySpeedAndDpx +// +// Description: This routine will figure out what line speed and duplex mode +// the PHY is currently using. +// +// Arguments: +// FdoData - ptr to FdoData object instance +// PhyId - The ID of the PHY in question. +// +// Returns: +// NOTHING +//----------------------------------------------------------------------------- + +VOID FindPhySpeedAndDpx( + IN PFDO_DATA FdoData, + IN UINT PhyId + ) +{ + USHORT MdiStatusReg = 0; + USHORT MdiMiscReg = 0; + USHORT MdiOwnAdReg = 0; + USHORT MdiLinkPartnerAdReg = 0; + + // + // If there was a speed and/or duplex override, then set our current + // value accordingly + // + FdoData->usLinkSpeed = FdoData->AiTempSpeed; + FdoData->usDuplexMode = (USHORT) FdoData->AiForceDpx; + + // + // If speed and duplex were forced, then we know our current settings, so + // we'll just return. Otherwise, we'll need to figure out what NWAY set + // us to. + // + if (FdoData->usLinkSpeed && FdoData->usDuplexMode) + { + return; + } + + // + // If we didn't have a valid link, then we'll assume that our current + // speed is 10mb half-duplex. + // + + // + // Read the status register twice because of sticky bits + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // If there wasn't a valid link then use default speed & duplex + // + if (!(MdiStatusReg & MDI_SR_LINK_STATUS)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Link Not found for speed detection!!! Using defaults.\n"); + + FdoData->usLinkSpeed = 10; + FdoData->usDuplexMode = 1; + + return; + } + + // + // If this is an Intel PHY (a T4 PHY_100 or a TX PHY_TX), then read bits + // 1 and 0 of extended register 0, to get the current speed and duplex + // settings. + // + if ((PhyId == PHY_100_A) || (PhyId == PHY_100_C) || (PhyId == PHY_TX_ID)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx for an Intel PHY\n"); + + // + // Read extended register 0 + // + MdiRead(FdoData, EXTENDED_REG_0, FdoData->PhyAddress, FALSE, &MdiMiscReg); + + // + // Get current speed setting + // + if (MdiMiscReg & PHY_100_ER0_SPEED_INDIC) + { + FdoData->usLinkSpeed = 100; + } + else + { + FdoData->usLinkSpeed = 10; + } + + // + // + // Get current duplex setting -- if bit is set then FDX is enabled + // + if (MdiMiscReg & PHY_100_ER0_FDX_INDIC) + { + FdoData->usDuplexMode = 2; + } + else + { + FdoData->usDuplexMode = 1; + } + + return; + } + + // + // Read our link partner's advertisement register + // + MdiRead(FdoData, + AUTO_NEG_LINK_PARTNER_REG, + FdoData->PhyAddress, + FALSE, + &MdiLinkPartnerAdReg); + // + // See if Auto-Negotiation was complete (bit 5, reg 1) + // + MdiRead(FdoData, MDI_STATUS_REG, FdoData->PhyAddress, FALSE, &MdiStatusReg); + + // + // If a True NWAY connection was made, then we can detect speed/duplex by + // ANDing our FdoData's advertised abilities with our link partner's + // advertised ablilities, and then assuming that the highest common + // denominator was chosed by NWAY. + // + if ((MdiLinkPartnerAdReg & NWAY_LP_ABILITY) && + (MdiStatusReg & MDI_SR_AUTO_NEG_COMPLETE)) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx from NWAY connection\n"); + + // + // Read our advertisement register + // + MdiRead(FdoData, AUTO_NEG_ADVERTISE_REG, FdoData->PhyAddress, FALSE, &MdiOwnAdReg); + + // + // AND the two advertisement registers together, and get rid of any + // extraneous bits. + // + MdiOwnAdReg &= (MdiLinkPartnerAdReg & NWAY_LP_ABILITY); + + // + // Get speed setting + // + if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX | NWAY_AD_TX_FULL_DPX | NWAY_AD_T4_CAPABLE)) + { + FdoData->usLinkSpeed = 100; + } + else + { + FdoData->usLinkSpeed = 10; + } + + // + // Get duplex setting -- use priority resolution algorithm + // + if (MdiOwnAdReg & (NWAY_AD_T4_CAPABLE)) + { + FdoData->usDuplexMode = 1; + return; + } + else if (MdiOwnAdReg & (NWAY_AD_TX_FULL_DPX)) + { + FdoData->usDuplexMode = 2; + return; + } + else if (MdiOwnAdReg & (NWAY_AD_TX_HALF_DPX)) + { + FdoData->usDuplexMode = 1; + return; + } + else if (MdiOwnAdReg & (NWAY_AD_10T_FULL_DPX)) + { + FdoData->usDuplexMode = 2; + return; + } + else + { + FdoData->usDuplexMode = 1; + return; + } + } + + // + // If we are connected to a non-NWAY repeater or hub, and the line + // speed was determined automatically by parallel detection, then we have + // no way of knowing exactly what speed the PHY is set to unless that PHY + // has a propietary register which indicates speed in this situation. The + // NSC TX PHY does have such a register. Also, since NWAY didn't establish + // the connection, the duplex setting should HALF duplex. + // + FdoData->usDuplexMode = 1; + + if (PhyId == PHY_NSC_TX) + { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS, " Detecting Speed/Dpx from non-NWAY NSC connection\n"); + + // + // Read register 25 to get the SPEED_10 bit + // + MdiRead(FdoData, NSC_SPEED_IND_REG, FdoData->PhyAddress, FALSE, &MdiMiscReg); + + // + // If bit 6 was set then we're at 10mb + // + if (MdiMiscReg & NSC_TX_SPD_INDC_SPEED) + { + FdoData->usLinkSpeed = 10; + } + else + { + FdoData->usLinkSpeed = 100; + } + } + // + // If we don't know what line speed we are set at, then we'll default to + // 10mbs + // + else + { + FdoData->usLinkSpeed = 10; + } +} + + +//----------------------------------------------------------------------------- +// Procedure: ResetPhy +// +// Description: This routine will reset the PHY that the FdoData is currently +// configured to use. +// +// Arguments: +// FdoData - ptr to FdoData object instance +// +// Returns: +// NOTHING +//----------------------------------------------------------------------------- + +VOID ResetPhy( + IN PFDO_DATA FdoData + ) +{ + USHORT MdiControlReg; + + // + // Reset the Phy, enable auto-negotiation, and restart auto-negotiation. + // + MdiControlReg = (MDI_CR_AUTO_SELECT | MDI_CR_RESTART_AUTO_NEG | MDI_CR_RESET); + + // + // Write the MDI control register with our new Phy configuration + // + MdiWrite(FdoData, MDI_CONTROL_REG, FdoData->PhyAddress, MdiControlReg); +} + diff --git a/general/pcidrv/kmdf/HW/precomp.h b/general/pcidrv/kmdf/HW/precomp.h new file mode 100644 index 00000000..851ce1f1 --- /dev/null +++ b/general/pcidrv/kmdf/HW/precomp.h @@ -0,0 +1,45 @@ +// +// precomp.h for pcidrv driver +// +#define WIN9X_COMPAT_SPINLOCK +#include <ntddk.h> +#include <wdf.h> + +typedef unsigned int UINT; +typedef unsigned int *PUINT; + +#include <initguid.h> // required for GUID definitions +#include <wdmguid.h> // required for WMILIB_CONTEXT +#include <wmistr.h> +#include <wmilib.h> +#include <ntintsafe.h> + + +// +// Disable warnings that prevent our driver from compiling with /W4 MSC_WARNING_LEVEL +// +// 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 +// +#pragma warning(disable:4214) +#pragma warning(disable:4201) +#pragma warning(disable:4115) + +#include "ntddndis.h" // for OIDs + +#pragma warning(default:4214) +#pragma warning(default:4201) +#pragma warning(default:4115) + +#include "nuiouser.h" // for ioctls recevied from ndisedge +#include "public.h" + +#include "e100_equ.h" +#include "e100_557.h" +#include "trace.h" +#include "nic_def.h" +#include "pcidrv.h" +#include "macros.h" + + diff --git a/general/pcidrv/kmdf/HW/precompsrc.c b/general/pcidrv/kmdf/HW/precompsrc.c new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/general/pcidrv/kmdf/HW/precompsrc.c @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/general/pcidrv/kmdf/HW/routines.c b/general/pcidrv/kmdf/HW/routines.c new file mode 100644 index 00000000..d6908ea5 --- /dev/null +++ b/general/pcidrv/kmdf/HW/routines.c @@ -0,0 +1,479 @@ +/**************************************************************************** +** COPYRIGHT (C) 1994-1997 INTEL CORPORATION ** +** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON ** +** HTTP://WWW.INTEL.COM/ ** +** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND ** +** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER ** +****************************************************************************/ + +/**************************************************************************** +Module Name: + routines.c + +This driver runs on the following hardware: + - 82558 based PCI 10/100Mb ethernet adapters + (aka Intel EtherExpress(TM) PRO Adapters) + +Environment: + Kernel Mode - Or whatever is the equivalent on WinNT + +*****************************************************************************/ + +//#pragma TRACE_LEVEL_WARNING (disable: 4514 4706) + +//----------------------------------------------------------------------------- +// Procedure: MdiWrite +// +// Description: This routine will write a value to the specified MII register +// of an external MDI compliant device (e.g. PHY 100). The +// command will execute in polled mode. +// +// Arguments: +// Adapter - ptr to Adapter object instance +// RegAddress - The MII register that we are writing to +// PhyAddress - The MDI address of the Phy component. +// DataValue - The value that we are writing to the MII register. +// +// Returns: +// NOTHING +//----------------------------------------------------------------------------- + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "routines.tmh" +#endif + +//----------------------------------------------------------------------------- +// Procedure: WaitScb +// +// Description: This routine checks to see if the D100 has accepted a command. +// It does so by checking the command field in the SCB, which will +// be zeroed by the D100 upon accepting a command. The loop waits +// for up to 600 milliseconds for command acceptance. +// +// Arguments: +// Adapter - ptr to Adapter object instance +// +// Returns: +// TRUE if the SCB cleared within 600 milliseconds. +// FALSE if it didn't clear within 600 milliseconds +//----------------------------------------------------------------------------- +__inline BOOLEAN +WaitScb( + IN PFDO_DATA FdoData + ) +{ + BOOLEAN bResult; + + HW_CSR volatile *pCSRAddress = FdoData->CSRAddress; + + MP_STALL_AND_WAIT(pCSRAddress->ScbCommandLow == 0, 600, bResult); + if(!bResult) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "WaitScb failed, ScbCommandLow=%x\n", pCSRAddress->ScbCommandLow); + if(pCSRAddress->ScbCommandLow != 0x80) + { + //ASSERT(FALSE); + } + MP_SET_HARDWARE_ERROR(FdoData); + } + + return bResult; +} + + +VOID +MdiWrite( + IN PFDO_DATA Adapter, + IN ULONG RegAddress, + IN ULONG PhyAddress, + IN USHORT DataValue + ) +{ + BOOLEAN bResult; + + // Issue the write command to the MDI control register. + Adapter->CSRAddress->MDIControl = (((ULONG) DataValue) | + (RegAddress << 16) | + (PhyAddress << 21) | + (MDI_WRITE << 26)); + + // wait 20usec before checking status + KeStallExecutionProcessor (20); + + // wait 2 seconds for the mdi write to complete + MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult); + + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + } +} + + +//----------------------------------------------------------------------------- +// Procedure: MdiRead +// +// Description: This routine will read a value from the specified MII register +// of an external MDI compliant device (e.g. PHY 100), and return +// it to the calling routine. The command will execute in polled +// mode. +// +// Arguments: +// Adapter - ptr to Adapter object instance +// RegAddress - The MII register that we are reading from +// PhyAddress - The MDI address of the Phy component. +// Recoverable - Whether the hardware TRACE_LEVEL_ERROR(if any)if recoverable or not +// +// Results: +// DataValue - The value that we read from the MII register. +// +// Returns: +// None +//----------------------------------------------------------------------------- +BOOLEAN +MdiRead( + IN PFDO_DATA Adapter, + IN ULONG RegAddress, + IN ULONG PhyAddress, + IN BOOLEAN Recoverable, + IN OUT PUSHORT DataValue + ) +{ + BOOLEAN bResult; + + // Issue the read command to the MDI control register. + Adapter->CSRAddress->MDIControl = ((RegAddress << 16) | + (PhyAddress << 21) | + (MDI_READ << 26)); + + // wait 20usec before checking status + KeStallExecutionProcessor (20); + + // Wait up to 2 seconds for the mdi read to complete + MP_STALL_AND_WAIT(Adapter->CSRAddress->MDIControl & MDI_PHY_READY, 2000, bResult); + if (!bResult) + { + if (!Recoverable) + { + MP_SET_NON_RECOVER_ERROR(Adapter); + } + MP_SET_HARDWARE_ERROR(Adapter); + return bResult; + } + + *DataValue = (USHORT) Adapter->CSRAddress->MDIControl; + return bResult; + +} + + +//----------------------------------------------------------------------------- +// Procedure: DumpStatsCounters +// +// Description: This routine will dump and reset the 82557's internal +// Statistics counters. The current stats dump values will be +// added to the "Adapter's" overall statistics. +// Arguments: +// Adapter - ptr to Adapter object instance +// +// Returns: +// NOTHING +//----------------------------------------------------------------------------- +VOID +DumpStatsCounters( + IN PFDO_DATA Adapter + ) +{ + BOOLEAN bResult; + //KIRQL oldIrql; + + // The query is for a driver statistic, so we need to first + // update our statistics in software. + + // clear the dump counters complete DWORD + Adapter->StatsCounters->CommandComplete = 0; + + + WdfSpinLockAcquire(Adapter->Lock); + + // Dump and reset the hardware's statistic counters + D100IssueScbCommand(Adapter, SCB_CUC_DUMP_RST_STAT, TRUE); + + // Restore the resume transmit software flag. After the dump counters + // command is issued, we should do a WaitSCB before issuing the next send. + Adapter->ResumeWait = TRUE; + + + WdfSpinLockRelease(Adapter->Lock); + + // wait up to 2 seconds for the dump/reset to complete + MP_STALL_AND_WAIT(Adapter->StatsCounters->CommandComplete == 0xA007, 2000, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + return; + } + + // Output the debug counters to the debug terminal. + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Good Transmits %d\n", Adapter->StatsCounters->XmtGoodFrames); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Good Receives %d\n", Adapter->StatsCounters->RcvGoodFrames); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Max Collisions %d\n", Adapter->StatsCounters->XmtMaxCollisions); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Late Collisions %d\n", Adapter->StatsCounters->XmtLateCollisions); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmit Underruns %d\n", Adapter->StatsCounters->XmtUnderruns); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmit Lost CRS %d\n", Adapter->StatsCounters->XmtLostCRS); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Transmits Deferred %d\n", Adapter->StatsCounters->XmtDeferred); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "One Collision xmits %d\n", Adapter->StatsCounters->XmtSingleCollision); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Mult Collision xmits %d\n", Adapter->StatsCounters->XmtMultCollisions); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Total Collisions %d\n", Adapter->StatsCounters->XmtTotalCollisions); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive CRC errors %d\n", Adapter->StatsCounters->RcvCrcErrors); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive Alignment errors %d\n", Adapter->StatsCounters->RcvAlignmentErrors); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive no resources %d\n", Adapter->StatsCounters->RcvResourceErrors); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive overrun errors %d\n", Adapter->StatsCounters->RcvOverrunErrors); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive CDT errors %d\n", Adapter->StatsCounters->RcvCdtErrors); + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, "Receive short frames %d\n", Adapter->StatsCounters->RcvShortFrames); + + // update packet counts + Adapter->GoodTransmits += Adapter->StatsCounters->XmtGoodFrames; + Adapter->GoodReceives += Adapter->StatsCounters->RcvGoodFrames; + + // update transmit TRACE_LEVEL_ERROR counts + Adapter->TxAbortExcessCollisions += Adapter->StatsCounters->XmtMaxCollisions; + Adapter->TxLateCollisions += Adapter->StatsCounters->XmtLateCollisions; + Adapter->TxDmaUnderrun += Adapter->StatsCounters->XmtUnderruns; + Adapter->TxLostCRS += Adapter->StatsCounters->XmtLostCRS; + Adapter->TxOKButDeferred += Adapter->StatsCounters->XmtDeferred; + Adapter->OneRetry += Adapter->StatsCounters->XmtSingleCollision; + Adapter->MoreThanOneRetry += Adapter->StatsCounters->XmtMultCollisions; + Adapter->TotalRetries += Adapter->StatsCounters->XmtTotalCollisions; + + // update receive TRACE_LEVEL_ERROR counts + Adapter->RcvCrcErrors += Adapter->StatsCounters->RcvCrcErrors; + Adapter->RcvAlignmentErrors += Adapter->StatsCounters->RcvAlignmentErrors; + Adapter->RcvResourceErrors += Adapter->StatsCounters->RcvResourceErrors; + Adapter->RcvDmaOverrunErrors += Adapter->StatsCounters->RcvOverrunErrors; + Adapter->RcvCdtFrames += Adapter->StatsCounters->RcvCdtErrors; + Adapter->RcvRuntErrors += Adapter->StatsCounters->RcvShortFrames; +} + + +//----------------------------------------------------------------------------- +// Procedure: NICIssueSelectiveReset +// +// Description: This routine will issue a selective reset, forcing the adapter +// the CU and RU back into their idle states. The receive unit +// will then be re-enabled if it was previously enabled, because +// an RNR interrupt will be generated when we abort the RU. +// +// Arguments: +// Adapter - ptr to Adapter object instance +// +// Returns: +// NOTHING +//----------------------------------------------------------------------------- + +VOID +NICIssueSelectiveReset( + PFDO_DATA Adapter + ) +{ + NTSTATUS status; + BOOLEAN bResult; + + // Wait for the SCB to clear before we check the CU status. + if (!MP_TEST_FLAG(Adapter, fMP_ADAPTER_HARDWARE_ERROR)) + { + WaitScb(Adapter); + } + + // If we have issued any transmits, then the CU will either be active, or + // in the suspended state. If the CU is active, then we wait for it to be + // suspended. If the the CU is suspended, then we need to put the CU back + // into the idle state by issuing a selective reset. + if (Adapter->TransmitIdle == FALSE) + { + // Wait up to 2 seconds for suspended state + MP_STALL_AND_WAIT((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) != SCB_CUS_ACTIVE, 2000, bResult) + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + } + + // Check the current status of the receive unit + if ((Adapter->CSRAddress->ScbStatus & SCB_RUS_MASK) != SCB_RUS_IDLE) + { + // Issue an RU abort. Since an interrupt will be issued, the + // RU will be started by the DPC. + status = D100IssueScbCommand(Adapter, SCB_RUC_ABORT, TRUE); + } + + // Issue a selective reset. + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_HW_ACCESS, "CU suspended. ScbStatus=%04x Issue selective reset\n", Adapter->CSRAddress->ScbStatus); + Adapter->CSRAddress->Port = PORT_SELECTIVE_RESET; + + // Wait after a port sel-reset command + KeStallExecutionProcessor (NIC_DELAY_POST_RESET); + + // wait up to 2 ms for port command to complete + MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult) + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + } + + // disable interrupts after issuing reset, because the int + // line gets raised when reset completes. + NICDisableInterrupt(Adapter); + + // Restore the transmit software flags. + Adapter->TransmitIdle = TRUE; + Adapter->ResumeWait = TRUE; + } +} + +VOID +NICIssueFullReset( + PFDO_DATA Adapter + ) +{ + BOOLEAN bResult; + + NICIssueSelectiveReset(Adapter); + + Adapter->CSRAddress->Port = PORT_SOFTWARE_RESET; + + // wait up to 2 ms for port command to complete + MP_STALL_AND_WAIT(Adapter->CSRAddress->Port == 0, 2, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + return; + } + + NICDisableInterrupt(Adapter); +} + + +//----------------------------------------------------------------------------- +// Procedure: D100SubmitCommandBlockAndWait +// +// Description: This routine will submit a command block to be executed, and +// then it will wait for that command block to be executed. Since +// board ints will be disabled, we will ack the interrupt in +// this routine. +// +// Arguments: +// Adapter - ptr to Adapter object instance +// +// Returns: +// NDIS_STATUS_SUCCESS +// STATUS_DEVICE_DATA_ERROR +//----------------------------------------------------------------------------- + +NTSTATUS +D100SubmitCommandBlockAndWait( + IN PFDO_DATA Adapter + ) +{ + NTSTATUS status; + BOOLEAN bResult; + + // Points to the Non Tx Command Block. + NON_TRANSMIT_CB volatile *CommandBlock = Adapter->NonTxCmdBlock; + + // Set the Command Block to be the last command block + CommandBlock->NonTxCb.Config.ConfigCBHeader.CbCommand |= CB_EL_BIT; + + // Clear the status of the command block + CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus = 0; + +#if DBG + // Don't try to start the CU if the command unit is active. + if ((Adapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_ACTIVE) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Scb %p ScbStatus %04x\n", Adapter->CSRAddress, Adapter->CSRAddress->ScbStatus); + ASSERT(FALSE); + MP_SET_HARDWARE_ERROR(Adapter); + return(STATUS_DEVICE_DATA_ERROR); + } +#endif + + // Start the command unit. + D100IssueScbCommand(Adapter, SCB_CUC_START, FALSE); + + // Wait for the SCB to clear, indicating the completion of the command. + if (!WaitScb(Adapter)) + { + return(STATUS_DEVICE_DATA_ERROR); + } + + // Wait for some status, timeout value 3 secs + MP_STALL_AND_WAIT(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_COMPLETE, 3000, bResult); + if (!bResult) + { + MP_SET_HARDWARE_ERROR(Adapter); + return(STATUS_DEVICE_DATA_ERROR); + } + + // Ack any interrupts + if (Adapter->CSRAddress->ScbStatus & SCB_ACK_MASK) + { + // Ack all pending interrupts now + Adapter->CSRAddress->ScbStatus &= SCB_ACK_MASK; + } + + // Check the status of the command, and if the command failed return FALSE, + // otherwise return TRUE. + if (!(CommandBlock->NonTxCb.Config.ConfigCBHeader.CbStatus & CB_STATUS_OK)) + { + TraceEvents(TRACE_LEVEL_ERROR, DBG_HW_ACCESS, "Command failed\n"); + MP_SET_HARDWARE_ERROR(Adapter); + status = STATUS_DEVICE_DATA_ERROR; + } + else + status = STATUS_SUCCESS; + + return(status); +} + +//----------------------------------------------------------------------------- +// Procedure: GetConnectionStatus +// +// Description: This function returns the connection status that is +// a required indication for PC 97 specification from MS +// the value we are looking for is if there is link to the +// wire or not. +// +// Arguments: IN Adapter structure pointer +// +// Returns: NdisMediaStateConnected +// NdisMediaStateDisconnected +//----------------------------------------------------------------------------- +MEDIA_STATE +GetMediaState( + IN PFDO_DATA Adapter + ) +{ + USHORT MdiStatusReg = 0; + BOOLEAN bResult1; + BOOLEAN bResult2; + + + // Read the status register at phy 1 + bResult1 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg); + bResult2 = MdiRead(Adapter, MDI_STATUS_REG, Adapter->PhyAddress, TRUE, &MdiStatusReg); + + // if there is hardware failure, or let the state remains the same + if (!bResult1 || !bResult2) + { + return Adapter->MediaState; + } + if (MdiStatusReg & MDI_SR_LINK_STATUS) + return(Connected); + else + return(Disconnected); + +} + diff --git a/general/pcidrv/kmdf/PCIDRV.C b/general/pcidrv/kmdf/PCIDRV.C new file mode 100644 index 00000000..41a71b3c --- /dev/null +++ b/general/pcidrv/kmdf/PCIDRV.C @@ -0,0 +1,1792 @@ + +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + PciDrv.c + +Abstract: + + This is a generic WDM sample driver for Intel 82557/82558 + based PCI Ethernet Adapter (10/100) and Intel compatibles. + The WDM interface in this sample is based on the Toaster function + driver, and all the code to access the hardware is taken from + the E100BEX NDIS miniport sample from the DDK and converted to + use WDM interfaces instead of NDIS functions. + + This driver can be installed as a standalone driver (genpci.inf) + for the Intel PCI device. Please read the PCIDRV.HTM file for + more information. + +Environment: + + Kernel mode + +--*/ + +#include "precomp.h" + +#if defined(EVENT_TRACING) +// +// The trace message header (.tmh) file must be included in a source file +// before any WPP macro calls and after defining a WPP_CONTROL_GUIDS +// macro (defined in toaster.h). During the compilation, WPP scans the source +// files for DoTraceMessage() calls and builds a .tmh file which stores a unique +// data GUID for each message, the text resource string for each message, +// and the data types of the variables passed in for each message. This file +// is automatically generated and used during post-processing. +// +#include "pcidrv.tmh" +#endif + +// +// Global debug error level +// +#if !defined(EVENT_TRACING) +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0x2f;//0x46;//0x4FF; //0x00000006; +#else +ULONG DebugLevel; // wouldn't be used to control the TRACE_LEVEL_VERBOSE +ULONG DebugFlag; +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, PciDrvEvtDeviceAdd) +#pragma alloc_text (PAGE, PciDrvEvtDeviceContextCleanup) +#pragma alloc_text (PAGE, PciDrvEvtDevicePrepareHardware) +#pragma alloc_text (PAGE, PciDrvEvtDeviceReleaseHardware) +#pragma alloc_text (PAGE, PciDrvReadRegistryValue) +#pragma alloc_text (PAGE, PciDrvWriteRegistryValue) +#pragma alloc_text (PAGE, PciDrvEvtDriverContextCleanup) +#pragma alloc_text (PAGE, PciDrvEvtDeviceSelfManagedIoCleanup) +#pragma alloc_text (PAGE, PciDrvEvtDeviceSelfManagedIoSuspend) +#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeArmS0) +#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeTriggeredS0) +#pragma alloc_text (PAGE, PciDrvEvtDeviceWakeArmSx) +#pragma alloc_text (PAGE, PciDrvSetPowerPolicy) +#pragma alloc_text (PAGE, PciDrvReadFdoRegistryKeyValue) +#endif + + +#define PARAMATER_NAME_LEN 80 + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + WDF_OBJECT_ATTRIBUTES attrib; + WDFDRIVER driver; + PDRIVER_CONTEXT driverContext; + + // + // Initialize WPP Tracing + // + WPP_INIT_TRACING( DriverObject, RegistryPath ); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "PCIDRV Sample - Driver Framework Edition \n"); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, DRIVER_CONTEXT); + + // + // Register a cleanup callback so that we can call WPP_CLEANUP when + // the framework driver object is deleted during driver unload. + // + attrib.EvtCleanupCallback = PciDrvEvtDriverContextCleanup; + + // + // Initialize the Driver Config structure.. + // + WDF_DRIVER_CONFIG_INIT(&config, PciDrvEvtDeviceAdd); + + // + // Create a WDFDRIVER object. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + &attrib, + &config, + &driver); + + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "WdfDriverCreate failed with status %!STATUS!\n", status); + // + // Cleanup tracing here because DriverContextCleanup will not be called + // as we have failed to create WDFDRIVER object itself. + // Please note that if your return failure from DriverEntry after the + // WDFDRIVER object is created successfully, you don't have to + // call WPP cleanup because in those cases DriverContextCleanup + // will be executed when the framework deletes the DriverObject. + // + WPP_CLEANUP(DriverObject); + return status; + } + + driverContext = GetDriverContext(driver); + + // + // Create a driver wide lookside list used for allocating memory for the + // MP_RFD structure for all device instances (if there are multiple present). + // + status = WdfLookasideListCreate(WDF_NO_OBJECT_ATTRIBUTES, // LookAsideAttributes + sizeof(MP_RFD), + NonPagedPool, + WDF_NO_OBJECT_ATTRIBUTES, // MemoryAttributes + PCIDRV_POOL_TAG, + &driverContext->RecvLookaside + ); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_INIT, + "Couldn't allocate lookaside list status %!STATUS!\n", status); + return status; + } + + return status; + +} + +NTSTATUS +PciDrvEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; + WDF_OBJECT_ATTRIBUTES fdoAttributes; + WDFDEVICE device; + PFDO_DATA fdoData = NULL; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "-->PciDrvEvtDeviceAdd routine. Driver: 0x%p\n", Driver); + + // + // I/O type is Buffered by default. If required to use something else, + // call WdfDeviceInitSetIoType with the appropriate type. + // + WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect); + + // + // Zero out the PnpPowerCallbacks structure. + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Set Callbacks for any of the functions we are interested in. + // If no callback is set, Framework will take the default action + // by itself. This sample provides many of the possible callbacks, + // mostly because it's a fairly complex sample that drives full-featured + // hardware. Drivers derived from this sample will often be able to + // provide only some of these. + // + + // + // These callback is invoked to tear down all the driver-managed state + // that is set up in this function. Many times, this callback won't do + // much of anything, since many of the things that are set up here will + // have their lifetimes automatically managed by the Framework. + // + + + // + // These two callbacks set up and tear down hardware state, + // specifically that which only has to be done once. + // + + pnpPowerCallbacks.EvtDevicePrepareHardware = PciDrvEvtDevicePrepareHardware; + pnpPowerCallbacks.EvtDeviceReleaseHardware = PciDrvEvtDeviceReleaseHardware; + + // + // These two callbacks set up and tear down hardware state that must be + // done every time the device moves in and out of the D0-working state. + // + + pnpPowerCallbacks.EvtDeviceD0Entry = PciDrvEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = PciDrvEvtDeviceD0Exit; + + // + // These next two callbacks are for doing work at PASSIVE_LEVEL (low IRQL) + // after all the interrupts are connected and before they are disconnected. + // + // Some drivers need to do device initialization and tear-down while the + // interrupt is connected. (This is a problem for these devices, since + // it opens them up to taking interrupts before they are actually ready + // to handle them, or to taking them after they have torn down too much + // to be able to handle them.) While this hardware design pattern is to + // be discouraged, it is possible to handle it by doing device init and + // tear down in these routines rather than in EvtDeviceD0Entry and + // EvtDeviceD0Exit. + // + // In this sample these callbacks don't do anything. + // + + pnpPowerCallbacks.EvtDeviceD0EntryPostInterruptsEnabled = NICEvtDeviceD0EntryPostInterruptsEnabled; + pnpPowerCallbacks.EvtDeviceD0ExitPreInterruptsDisabled = NICEvtDeviceD0ExitPreInterruptsDisabled; + + // + // This next group of five callbacks allow a driver to become involved in + // starting and stopping operations within a driver as the driver moves + // through various PnP/Power states. These functions are not necessary + // if the Framework is managing all the device's queues and there is no + // activity going on that isn't queue-based. This sample provides these + // callbacks because it uses watchdog timer to monitor whether the device + // is working or not and it needs to start and stop the timer when the device + // is started or removed. It cannot start and stop the timers in the D0Entry + // and D0Exit callbacks because if the device is surprise-removed, D0Exit + // will not be called. + // + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = PciDrvEvtDeviceSelfManagedIoInit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoCleanup = PciDrvEvtDeviceSelfManagedIoCleanup; + pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = PciDrvEvtDeviceSelfManagedIoSuspend; + pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = PciDrvEvtDeviceSelfManagedIoRestart; + + // + // Register the PnP and power callbacks. Power policy related callbacks will be registered + // later. + // + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Init the power policy callbacks + // + WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks); + + // + // This group of three callbacks allows this sample driver to manage + // arming the device for wake from the S0 state. Networking devices can + // optionally be put into a low-power state when there is no networking + // cable plugged into them. This sample implements this feature. + // + powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = PciDrvEvtDeviceWakeArmS0; + powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = PciDrvEvtDeviceWakeDisarmS0; + powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = PciDrvEvtDeviceWakeTriggeredS0; + + // + // This group of three callbacks allows the device to be armed for wake + // from Sx (S1, S2, S3 or S4.) Networking devices can optionally be put + // into a state where a packet sent to them will cause the device's wake + // signal to be triggered, which causes the machine to wake, moving back + // into the S0 state. + // + + powerPolicyCallbacks.EvtDeviceArmWakeFromSx = PciDrvEvtDeviceWakeArmSx; + powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = PciDrvEvtDeviceWakeDisarmSx; + powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = PciDrvEvtDeviceWakeTriggeredSx; + + // + // Register the power policy callbacks. + // + WdfDeviceInitSetPowerPolicyEventCallbacks(DeviceInit, &powerPolicyCallbacks); + + // Since we are the function driver, we are now the power policy owner + // for the device according to the default framework rule. We will register + // our power policy callbacks after finding the wakeup capability of the device. + + // + // Specify the context type and size for the device we are about to create. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); + + // + // ContextCleanup will be called by the framework when it deletes the device. + // So you can defer freeing any resources allocated to Cleanup callback in the + // event AddDevice returns any error after the device is created. + // + fdoAttributes.EvtCleanupCallback = PciDrvEvtDeviceContextCleanup; + + status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); + + if ( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceInitialize failed %!STATUS!\n", status); + return status; + } + + // + // Device creation is complete. + // Get the DeviceExtension and initialize it. + // + fdoData = FdoGetData(device); + fdoData->WdfDevice = device; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "PDO(0x%p) FDO(0x%p), Lower(0x%p) DevExt (0x%p)\n", + WdfDeviceWdmGetPhysicalDevice (device), + WdfDeviceWdmGetDeviceObject (device), + WdfDeviceWdmGetAttachedDevice(device), + fdoData); + + // + // Initialize the device extension and allocate all the software resources + // + status = NICAllocateSoftwareResources(fdoData); + if (!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "NICAllocateSoftwareResources failed: %!STATUS!\n", + status); + return status; + } + + // + // If our device supports wait-wake then we will set our power-policy and + // update S0-Idle policy. + // + if (IsPoMgmtSupported(fdoData)) { + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "Device has wait-wake capability\n"); + status = PciDrvSetPowerPolicy(fdoData); + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "PciDrvSetPowerPolicy failed %!STATUS!\n", status); + return status; + } + } + + // + // Tell the Framework that this device will need an interface so that + // application can interact with it. + // + status = WdfDeviceCreateDeviceInterface( + device, + (LPGUID) &GUID_DEVINTERFACE_PCIDRV, + NULL + ); + + if (!NT_SUCCESS (status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceCreateDeviceInterface failed %!STATUS!\n", status); + return status; + } + + status = PciDrvWmiRegistration(device); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PciDrvEvtDeviceAdd \n"); + + return status; +} + +VOID +PciDrvEvtDeviceContextCleanup ( + WDFOBJECT Device + ) +/*++ + +Routine Description: + + EvtDeviceContextCleanup event callback cleans up anything done in + EvtDeviceAdd, except those things that are automatically cleaned + up by the Framework. + + In the case of this sample, everything is automatically handled. In a + driver derived from this sample, it's quite likely that this function could + be deleted. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + VOID + +--*/ +{ + PFDO_DATA fdoData = NULL; + + PAGED_CODE(); + + fdoData = FdoGetData((WDFDEVICE)Device); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceContextCleanup\n"); + + NICFreeSoftwareResources(fdoData); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceContextCleanup\n"); + +} + +NTSTATUS +PciDrvEvtDevicePrepareHardware ( + WDFDEVICE Device, + WDFCMRESLIST Resources, + WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDeviceStart event callback performs operations that are necessary + to make the driver's device operational. The framework calls the driver's + EvtDeviceStart callback when the PnP manager sends an IRP_MN_START_DEVICE + request to the driver stack. + +Arguments: + + Device - Handle to a framework device object. + + Resources - Handle to a collection of framework resource objects. + This collection identifies the raw (bus-relative) hardware + resources that have been assigned to the device. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + WDF status code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PFDO_DATA fdoData = NULL; + + UNREFERENCED_PARAMETER(Resources); + UNREFERENCED_PARAMETER(ResourcesTranslated); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDevicePrepareHardware\n"); + + fdoData = FdoGetData(Device); + + status = NICMapHWResources(fdoData, Resources, ResourcesTranslated); + if (!NT_SUCCESS (status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "NICMapHWResources failed: %!STATUS!\n", status); + return status; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDevicePrepareHardware\n"); + + return status; + +} + +NTSTATUS +PciDrvEvtDeviceReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDeviceReleaseHardware is called by the framework whenever the PnP manager + is revoking ownership of our resources. This may be in response to either + IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before + passing down the IRP to the lower driver. + + In this callback, do anything necessary to free those resources. + +Arguments: + + Device - Handle to a framework device object. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + NTSTATUS - Failures will be logged, but not acted on. + +--*/ +{ + PFDO_DATA fdoData = NULL; + + UNREFERENCED_PARAMETER(ResourcesTranslated); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceReleaseHardware\n"); + + fdoData = FdoGetData(Device); + + // + // Unmap any I/O ports. Disconnecting from the interrupt will be done + // automatically by the framework. + // + NICUnmapHWResources(fdoData); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceReleaseHardware\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS +PciDrvEvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PreviousState + ) +/*++ + +Routine Description: + + EvtDeviceD0Entry event callback must perform any operations that are + necessary before the specified device is used. It will be called every + time the hardware needs to be (re-)initialized. This includes after + IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, + IRP_MN_SET_POWER-D0. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + + This function runs at PASSIVE_LEVEL, even though it is not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE + is set. Even if DO_POWER_PAGABLE isn't set, this function still runs + at PASSIVE_LEVEL. In this case, though, the function absolutely must + not do anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + PreviousState - Device power state which the device was in most recently. + If the device is being newly started, this will be + PowerDeviceUnspecified. + +Return Value: + + NTSTATUS + +--*/ +{ + PFDO_DATA fdoData; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->PciDrvEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(PreviousState)); + + fdoData = FdoGetData(Device); + + ASSERT(PowerDeviceD0 != PreviousState); + + fdoData->DevicePowerState = PowerDeviceD0; + + if(IsPoMgmtSupported(fdoData)){ + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, + "Entering fully on state\n"); + MPSetPowerD0 (fdoData); + } + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--PciDrvEvtDeviceD0Entry\n"); + + return STATUS_SUCCESS; +} + + +NTSTATUS +PciDrvEvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE TargetState + ) +/*++ + +Routine Description: + + This routine undoes anything done in EvtDeviceD0Entry. It is called + whenever the device leaves the D0 state, which happens when the device is + stopped, when it is removed, and when it is powered off. + + The device is still in D0 when this callback is invoked, which means that + the driver can still touch hardware in this routine. + + Note that interrupts have already been disabled by the time that this + callback is invoked. + + EvtDeviceD0Exit event callback must perform any operations that are + necessary before the specified device is moved out of the D0 state. If the + driver needs to save hardware state before the device is powered down, then + that should be done here. + + This function runs at PASSIVE_LEVEL, though it is generally not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE is set. + + Even if DO_POWER_PAGABLE isn't set, this function still runs at + PASSIVE_LEVEL. In this case, though, the function absolutely must not do + anything that will cause a page fault. + +Arguments: + + Device - Handle to a framework device object. + + TargetState - Device power state which the device will be put in once this + callback is complete. + +Return Value: + + Success implies that the device can be used. Failure will result in the + device stack being torn down. + +--*/ +{ + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(Device); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, + "-->PciDrvEvtDeviceD0Exit - moving to %s\n", + DbgDevicePowerString(TargetState)); + + fdoData = FdoGetData(Device); + + fdoData->DevicePowerState = TargetState; + + switch (TargetState) { + case WdfPowerDeviceD1: + case WdfPowerDeviceD2: + case WdfPowerDeviceD3: + + if(IsPoMgmtSupported(fdoData)){ + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_POWER, + "Entering a deeper sleep state\n"); + MPSetPowerLow (fdoData, TargetState); + } + break; + + case WdfPowerDevicePrepareForHibernation: + + // + // Fill in any code to save hardware state here. Do not put in any + // code to shut the device off. If this device cannot support being + // in the paging path (or being a parent or grandparent of a paging + // path device) then this whole case can be deleted. + // + ASSERT(FALSE); // This driver shouldn't get this. + break; + + case WdfPowerDeviceD3Final: + // + // Reset and put the device into a known initial state we're shutting + // down for the last time. + // + NICShutdown(fdoData); + break; + + default: + break; + } + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_POWER, "<--PciDrvEvtDeviceD0Exit\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS +PciDrvEvtDeviceSelfManagedIoInit( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + PciDrvEvtDeviceSelfManagedIoInit is called by the Framework when the device + enters the D0 state. Its job is to start any I/O-related actions that the + Framework isn't managing. This might include releasing queues that are not + power-managed, that is, the Framework is not automatically holding and releasing + them across PnP/Power transitions. (The default behavior for WDFQUEUE is + auto-managed, so most queues don't need to be dealt with here.) This might + also include setting up non-queue-based actions. + + If you allow the Framework to manage most or all of your queues, then when + you build a driver from this sample, you can probably delete this function. + + In this driver, the SelfManagedIo callbacks are used to implement a watchdog timer. + + This function is not marked pagable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + PFDO_DATA fdoData = NULL; + WDF_TIMER_CONFIG wdfTimerConfig; + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES timerAttributes; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceSelfManagedIoInit\n"); + + fdoData = FdoGetData(Device); + // + // To minimize init-time, create a timer DPC to do link detection. + // This DPC will also be used to check for hardware hang. + // + WDF_TIMER_CONFIG_INIT(&wdfTimerConfig, NICWatchDogEvtTimerFunc); + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + timerAttributes.ParentObject = fdoData->WdfDevice; + + status = WdfTimerCreate( + &wdfTimerConfig, + &timerAttributes, + &fdoData->WatchDogTimer + ); + + if(!NT_SUCCESS(status) ) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "Error: WdfTimerCreate create failed 0x%x\n", status); + return status; + } + + NICStartWatchDogTimer(fdoData); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceSelfManagedIoInit\n"); + + return status; +} + +NTSTATUS +PciDrvEvtDeviceSelfManagedIoSuspend( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceSelfManagedIoSuspend is called by the Framework before the device + leaves the D0 state. Its job is to stop any I/O-related actions that the + Framework isn't managing, and which cannot be handled when the device + hardware isn't available. In general, this means reversing anything that + was done in EvtDeviceSelfManagedIoStart. + + If you allow the Framework to manage most or all of your queues, then when + you build a driver from this sample, you can probably delete this function. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + PFDO_DATA fdoData = NULL; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceSelfManagedIoSuspend\n"); + + fdoData = FdoGetData(Device); + + // + // Stop the watchdog timer and wait for DPC to run to completion if + // it's already fired. + // + WdfTimerStop(fdoData->WatchDogTimer, TRUE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceSelfManagedIoSuspend\n"); + + return STATUS_SUCCESS; +} + +NTSTATUS +PciDrvEvtDeviceSelfManagedIoRestart( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceSelfManagedIoRestart is called by the Framework before the device + is restarted for one of the following reasons: + a) the PnP resources were rebalanced (framework received + query-stop and stop IRPS ) + b) the device resumed from a low power state to D0. + + This function is not marked pagable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failure will cause the device stack to be torn down. + +--*/ +{ + PFDO_DATA fdoData; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceSelfManagedIoRestart\n"); + + fdoData = FdoGetData(Device); + + // + // Restart the watchdog timer. + // + NICStartWatchDogTimer(fdoData); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceSelfManagedIoRestart\n"); + + return STATUS_SUCCESS; +} + +VOID +PciDrvEvtDeviceSelfManagedIoCleanup( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceSelfManagedIoCleanup is called by the Framework when the device is + being torn down, either in response to the WDM IRP_MN_REMOVE_DEVICE + It will be called only once. Its job is to stop all outstanding I/O in the driver + that the Framework is not managing. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + PFDO_DATA fdoData = NULL; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceSelfManagedIoCleanup\n"); + + fdoData = FdoGetData(Device); + + if(fdoData->WatchDogTimer) { + WdfObjectDelete(fdoData->WatchDogTimer); + } + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceSelfManagedIoCleanup\n"); +} + + +VOID +PciDrvEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. +Return Value: + + VOID + +--*/ +{ + NTSTATUS status= STATUS_SUCCESS; + PFDO_DATA fdoData = NULL; + WDFDEVICE hDevice; + WDF_REQUEST_PARAMETERS params; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_IOCTLS, + "PciDrvEvtIoDeviceControl called %p\n", Request); + + hDevice = WdfIoQueueGetDevice(Queue); + fdoData = FdoGetData(hDevice); + + WDF_REQUEST_PARAMETERS_INIT(¶ms); + + WdfRequestGetParameters( + Request, + ¶ms + ); + + switch (IoControlCode) + { + case IOCTL_NDISPROT_QUERY_OID_VALUE: + + ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); + + NICHandleQueryOidRequest( + Queue, + Request, + ¶ms + ); + break; + + case IOCTL_NDISPROT_SET_OID_VALUE: + + ASSERT((IoControlCode & 0x3) == METHOD_BUFFERED); + + NICHandleSetOidRequest( + Queue, + Request, + ¶ms + ); + + break; + + case IOCTL_NDISPROT_INDICATE_STATUS: + + status = WdfRequestForwardToIoQueue(Request, + fdoData->PendingIoctlQueue); + if(!NT_SUCCESS(status)){ + TraceEvents(TRACE_LEVEL_ERROR, DBG_IOCTLS, + "WdfRequestForwardToIoQueue failed 0x%x\n", status); + WdfRequestComplete(Request, status); + break; + } + + break; + + default: + ASSERTMSG(FALSE, "Invalid IOCTL request\n"); + WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST); + break; + } + + return; +} + +NTSTATUS +PciDrvEvtDeviceWakeArmS0( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeArmS0 is called when the Framework arms the device for + wake in the S0 state. If there is any device-specific initialization + that needs to be done to arm internal wake signals, or to route internal + interrupt signals to the wake logic, it should be done here. The device + will be moved out of the D0 state soon after this callback is invoked. + + In this sample, wake from S0 involves waking on packet arrival, as does + wake from Sx. A more common NIC implementation might wake on cable + insertion. + + This function is pageable and it will run at PASSIVE_LEVEL. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + NTSTATUS - Failure will result in the device remaining in the D0 state. + +--*/ +{ + NTSTATUS status; + PFDO_DATA fdoData; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeArmS0\n"); + + fdoData = FdoGetData(Device); + + // + // Add pattern before sending wait-wake + // + status = NICConfigureForWakeUp(fdoData, TRUE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeArmS0 %x\n", status); + + return status; +} + +NTSTATUS +PciDrvEvtDeviceWakeArmSx( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeArmSx is called when the Framework arms the device for + wake from the S1, S2, S3 or S4 states. If there is any device-specific + initialization that needs to be done to arm internal wake signals, or to + route internal interrupt signals to the wake logic, it should be done here. + The device will be moved out of the D0 state soon after this callback is + invoked. + + In this sample, wake from Sx involves arming for wake on packet arrival. + Cable insertion should not be enabled, as nobody would want their machine + to wake up simply because they plugged the cable in. + + This function runs at PASSIVE_LEVEL. Whether it is pageable or not depends + on whether the device has set DO_POWER_PAGABLE. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + NTSTATUS - Failure will result in the device not being armed for wake + while the system is in Sx. + +--*/ +{ + NTSTATUS status; + PFDO_DATA fdoData; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeArmSx\n"); + + fdoData = FdoGetData(Device); + // + // Add pattern before sending wait-wake + // + status = NICConfigureForWakeUp(fdoData, TRUE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeArmSx %x\n", status); + + return status; +} + +VOID +PciDrvEvtDeviceWakeDisarmS0( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeDisarmS0 reverses anything done in EvtDeviceWakeArmS0. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID. + +--*/ +{ + NTSTATUS status; + PFDO_DATA fdoData; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeDisarmS0\n"); + + fdoData = FdoGetData(Device); + status = NICConfigureForWakeUp(fdoData, FALSE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeDisarmS0 %x\n", status); + + return ; +} + +VOID +PciDrvEvtDeviceWakeDisarmSx( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeDisarmSx reverses anything done in EvtDeviceWakeArmSx. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + + This function runs at PASSIVE_LEVEL, even though it is not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE + is set. Even if DO_POWER_PAGABLE isn't set, this function still runs + at PASSIVE_LEVEL. In this case, though, the function absolutely must + not do anything that will cause a page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(Device); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeDisarmSx\n"); + + fdoData = FdoGetData(Device); + status = NICConfigureForWakeUp(fdoData, FALSE); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeDisarmSx %x\n", status); + + return; +} + +VOID +PciDrvEvtDeviceWakeTriggeredS0( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeTriggeredS0 will be called whenever the device triggers its + wake signal after being armed for wake from S0. + + This function is pageable and runs at PASSIVE_LEVEL. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeTriggeredS0\n"); + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeTriggeredS0\n"); +} + +VOID +PciDrvEvtDeviceWakeTriggeredSx( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeTriggeredSx will be called whenever the device triggers its + wake signal after being armed for wake from Sx. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + + This function runs at PASSIVE_LEVEL, even though it is not paged. A + driver can optionally make this function pageable if DO_POWER_PAGABLE + is set. Even if DO_POWER_PAGABLE isn't set, this function still runs + at PASSIVE_LEVEL. In this case, though, the function absolutely must + not do anything that will cause a page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvEvtDeviceWakeTriggeredSx"); + + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvEvtDeviceWakeTriggeredSx"); + + return; +} + + +NTSTATUS +PciDrvQueuePassiveLevelCallback( + IN PFDO_DATA FdoData, + IN PFN_WDF_WORKITEM CallbackFunction, + IN PVOID Context1, + IN PVOID Context2 + ) +/*++ + Routine Description: + + This routine is used to queue workitems so that the callback + functions can be executed at PASSIVE_LEVEL in the conext of + a system thread. + +Arguments: + + FdoData - pointer to a device extenion. + + CallbackFunction - Function to invoke when at PASSIVE_LEVEL. + + Context1 & 2 - Meaning of the context values depends on the + callback function. + +Return Value: + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PWORKER_ITEM_CONTEXT context; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_WORKITEM_CONFIG workitemConfig; + WDFWORKITEM hWorkItem; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, WORKER_ITEM_CONTEXT); + + attributes.ParentObject = FdoData->WdfDevice; + + WDF_WORKITEM_CONFIG_INIT(&workitemConfig, CallbackFunction); + + status = WdfWorkItemCreate( &workitemConfig, + &attributes, + &hWorkItem); + + if (!NT_SUCCESS(status)) { + return status; + } + + context = GetWorkItemContext(hWorkItem); + + context->FdoData = FdoData; + context->Argument1 = Context1; + context->Argument2 = Context2; + + // + // Execute this work item. + // + WdfWorkItemEnqueue(hWorkItem); + + return STATUS_SUCCESS; +} + + +BOOLEAN +PciDrvReadRegistryValue( + _In_ PFDO_DATA FdoData, + _In_ PWSTR Name, + _Out_ PULONG Value + ) +/*++ + +Routine Description: + + Can be used to read any REG_DWORD registry value stored + under Device Parameter. + +Arguments: + + FdoData - pointer to the device extension + Name - Name of the registry value + Value - + + +Return Value: + + TRUE if successful + FALSE if not present/error in reading registry + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + BOOLEAN retValue = FALSE; + UNICODE_STRING valueName; + + + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "-->PciDrvReadRegistryValue \n"); + + *Value = 0; + + status = WdfDeviceOpenRegistryKey(FdoData->WdfDevice, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (NT_SUCCESS (status)) { + + RtlInitUnicodeString(&valueName,Name); + + status = WdfRegistryQueryULong( hKey, + &valueName, + Value ); + + if (NT_SUCCESS (status)) { + retValue = TRUE; + } + + WdfRegistryClose(hKey); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "<--PciDrvReadRegistryValue %ws %d \n", Name, *Value); + + return retValue; +} + +BOOLEAN +PciDrvWriteRegistryValue( + _In_ PFDO_DATA FdoData, + _In_ PWSTR Name, + _In_ ULONG Value + ) +/*++ + +Routine Description: + + Can be used to write any REG_DWORD registry value stored + under Device Parameter. + +Arguments: + + +Return Value: + + TRUE - if write is successful + FALSE - otherwise + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + BOOLEAN retValue = FALSE; + UNICODE_STRING valueName; + + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, + "Entered PciDrvWriteRegistryValue\n"); + + // + // write the value out to the registry + // + status = WdfDeviceOpenRegistryKey(FdoData->WdfDevice, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (NT_SUCCESS (status)) { + + RtlInitUnicodeString(&valueName,Name); + + status = WdfRegistryAssignULong (hKey, + &valueName, + Value ); + + if (NT_SUCCESS (status)) { + retValue = TRUE; + } + + WdfRegistryClose(hKey); + } + + return retValue; + +} + +#define PARAMATER_NAME_LEN 80 + +BOOLEAN +PciDrvReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWSTR Name, + _Out_ PULONG Value + ) +/*++ + +Routine Description: + + Can be used to read any REG_DWORD registry value stored + under Device Parameter. + +Arguments: + + FdoData - pointer to the device extension + Name - Name of the registry value + Value - + + +Return Value: + + TRUE if successful + FALSE if not present/error in reading registry + +--*/ +{ + WDFKEY hKey = NULL; + NTSTATUS status; + BOOLEAN retValue = FALSE; + UNICODE_STRING valueName; + + PAGED_CODE(); + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, + "-->PciDrvReadFdoRegistryKeyValue\n"); + + *Value = 0; + + status = WdfFdoInitOpenRegistryKey(DeviceInit, + PLUGPLAY_REGKEY_DEVICE, + STANDARD_RIGHTS_ALL, + WDF_NO_OBJECT_ATTRIBUTES, + &hKey); + + if (NT_SUCCESS (status)) { + + RtlInitUnicodeString(&valueName,Name); + + status = WdfRegistryQueryULong (hKey, + &valueName, + Value); + + if (NT_SUCCESS (status)) { + retValue = TRUE; + } + + WdfRegistryClose(hKey); + } + + TraceEvents(TRACE_LEVEL_VERBOSE, DBG_PNP, + "<--PciDrvReadFdoRegistryKeyValue %ws %d \n", + Name, *Value); + + return retValue; +} + +VOID +PciDrvEvtDriverContextCleanup( + IN WDFOBJECT Driver + ) +/*++ +Routine Description: + + Free all the resources allocated in DriverEntry. + +Arguments: + + Driver - handle to a WDF Driver object. + +Return Value: + + VOID. + +--*/ +{ + PDRIVER_CONTEXT driverContext; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, + "--> PciDrvEvtDriverContextCleanup\n"); + PAGED_CODE (); + + driverContext = GetDriverContext((WDFDRIVER)Driver); + + if (driverContext->RecvLookaside) { + WdfObjectDelete(driverContext->RecvLookaside); + } + // + // Stop WPP Tracing + // + WPP_CLEANUP( WdfDriverWdmGetDriverObject( (WDFDRIVER)Driver ) ); + +} + +NTSTATUS +PciDrvSetPowerPolicy( + IN PFDO_DATA FdoData + ) +{ + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + NTSTATUS status = STATUS_SUCCESS; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "--> PciDrvSetPowerPolicy\n"); + + PAGED_CODE(); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCanWakeFromS0); + idleSettings.IdleTimeout = 10000; // 10-sec + + status = WdfDeviceAssignS0IdleSettings(FdoData->WdfDevice, &idleSettings); + if ( !NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceSetPowerPolicyS0IdlePolicy failed %x\n", status); + return status; + } + + // + // Init wait-wake policy structure. + // + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + + status = WdfDeviceAssignSxWakeSettings(FdoData->WdfDevice, &wakeSettings); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignSxWakeSettings failed %x\n", status); + return status; + } + + + // + // Functions that program wakeup patterns on the device + // check this variable to see whether the NDIS edge has enabled + // wakeup on this device. If there is no ndis edge, this variable and all + // the checks can be removed because framework as a power policy owner + // it knows when to call the driver to arm/disarm for wakeup. + // + FdoData->AllowWakeArming = TRUE; + + TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, + "<-- PciDrvSetPowerPolicy\n"); + + return status; +} + +PCHAR +DbgDevicePowerString( + IN WDF_POWER_DEVICE_STATE Type + ) +/*++ + +Updated Routine Description: + DbgDevicePowerString does not change in this stage of the function driver. + +--*/ +{ + switch (Type) + { + case WdfPowerDeviceInvalid: + return "WdfPowerDeviceInvalid"; + case WdfPowerDeviceD0: + return "WdfPowerDeviceD0"; + case WdfPowerDeviceD1: + return "WdfPowerDeviceD1"; + case WdfPowerDeviceD2: + return "WdfPowerDeviceD2"; + case WdfPowerDeviceD3: + return "WdfPowerDeviceD3"; + case WdfPowerDeviceD3Final: + return "WdfPowerDeviceD3Final"; + case WdfPowerDevicePrepareForHibernation: + return "WdfPowerDevicePrepareForHibernation"; + case WdfPowerDeviceMaximum: + return "WdfPowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + + +#if !defined(EVENT_TRACING) + +VOID +TraceEvents ( + IN ULONG TraceEventsLevel, + IN ULONG TraceEventsFlag, + IN PCCHAR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Debug print for the sample driver. + +Arguments: + + TraceEventsLevel - print level between 0 and 3, with 3 the most verbose + +Return Value: + + None. + + --*/ + { +#if DBG +#define TEMP_BUFFER_SIZE 512 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint (_DRIVER_NAME_": RtlStringCbVPrintfA failed %x\n", + status); + return; + } + if (TraceEventsLevel <= TRACE_LEVEL_INFORMATION || + (TraceEventsLevel <= DebugLevel && + ((TraceEventsFlag & DebugFlag) == TraceEventsFlag))) { + DbgPrint(debugMessageBuffer); + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(TraceEventsLevel); + UNREFERENCED_PARAMETER(TraceEventsFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif + diff --git a/general/pcidrv/kmdf/PCIDRV.H b/general/pcidrv/kmdf/PCIDRV.H new file mode 100644 index 00000000..db42bd39 --- /dev/null +++ b/general/pcidrv/kmdf/PCIDRV.H @@ -0,0 +1,401 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + PciDrv.h + +Abstract: + + Header file for the PCIDRV driver modules. + +Environment: + + Kernel mode + +--*/ + + +#if !defined(_PCIDRV_H_) +#define _PCIDRV_H_ + +// +// Let us use newly introduced (.NET DDK) safe string function to avoid +// security issues related buffer overrun. +// The advantages of the RtlStrsafe functions include: +// 1) The size of the destination buffer is always provided to the +// function to ensure that the function does not write past the end of +// the buffer. +// 2) Buffers are guaranteed to be null-terminated, even if the +// operation truncates the intended result. +// + +// +// In this driver we are using a safe version vsnprintf, which is +// RtlStringCbVPrintfA. To use strsafe function on 9x, ME, and Win2K Oses, we +// have to define NTSTRSAFE_LIB before including this header file and explicitly +// link to ntstrsafe.lib. If your driver is just target for XP and above, there is +// no define NTSTRSAFE_LIB and link to the lib. +// +#define NTSTRSAFE_LIB +#include <ntstrsafe.h> + +//----------------------------------------------------------------------------- +// 4127 -- Conditional Expression is Constant warning +//----------------------------------------------------------------------------- +#define WHILE(constant) \ +__pragma(warning(suppress: 4127)) while(constant) + +#define _DRIVER_NAME_ "PCIDRV" + +#define PCIDRV_POOL_TAG (ULONG) 'DICP' +#define PCIDRV_FDO_INSTANCE_SIGNATURE (ULONG) 'odFT' + +#define MILLISECONDS_TO_100NS (10000) +#define SECOND_TO_MILLISEC (1000) +#define SECOND_TO_100NS (SECOND_TO_MILLISEC * MILLISECONDS_TO_100NS) + +// +// Bit Flag Macros +// + +#define SET_FLAG(Flags, Bit) ((Flags) |= (Bit)) +#define CLEAR_FLAG(Flags, Bit) ((Flags) &= ~(Bit)) +#define TEST_FLAG(Flags, Bit) (((Flags) & (Bit)) != 0) + +// +// The driver context contains global data to the whole driver. +// +typedef struct _DRIVER_CONTEXT { + // + // The assumption here is that there is nothing device specific in the lookaside list + // and hence the same list can be used to do allocations for multiple devices. + // + WDFLOOKASIDE RecvLookaside; + +} DRIVER_CONTEXT, * PDRIVER_CONTEXT; +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DRIVER_CONTEXT, GetDriverContext) + + + +// +// Connector Types +// + +typedef struct _PCIDRV_WMI_STD_DATA { + + // + // Current Mac Address of the NIC + // + + UINT64 MacAddress; + +} PCIDRV_WMI_STD_DATA, * PPCIDRV_WMI_STD_DATA; + + +// +// General purpose workitem context used in dispatching work to +// system worker thread to be executed at PASSIVE_LEVEL. +// +typedef struct _WORKER_ITEM_CONTEXT { + PFDO_DATA FdoData; + PVOID Argument1; + PVOID Argument2; +} WORKER_ITEM_CONTEXT, *PWORKER_ITEM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKER_ITEM_CONTEXT, GetWorkItemContext) + +// +// The device extension for the device object +// +typedef struct _FDO_DATA +{ + ULONG Signature; // must be PCIDRV_FDO_INSTANCE_SIGNATURE + // beneath this device object. + WDFDEVICE WdfDevice; + + // Power Management + MP_POWER_MGMT PoMgmt; + WDF_POWER_DEVICE_STATE DevicePowerState; // Current power state of the device(D0 - D3) + + // Wait-Wake + BOOLEAN AllowWakeArming; + + // Idle Detection + //BOOLEAN IdleDetectionEnabled; + PCIDRV_WMI_STD_DATA StdDeviceData; + + // Following fields are specific to the hardware + // Configuration + ULONG Flags; + UCHAR PermanentAddress[ETH_LENGTH_OF_ADDRESS]; + UCHAR CurrentAddress[ETH_LENGTH_OF_ADDRESS]; + BOOLEAN bOverrideAddress; + USHORT AiTxFifo; // TX FIFO Threshold + USHORT AiRxFifo; // RX FIFO Threshold + UCHAR AiTxDmaCount; // Tx dma count + UCHAR AiRxDmaCount; // Rx dma count + UCHAR AiUnderrunRetry; // The underrun retry mechanism + UCHAR AiForceDpx; // duplex setting + USHORT AiTempSpeed; // 'Speed', user over-ride of line speed + USHORT AiThreshold; // 'Threshold', Transmit Threshold + BOOLEAN MWIEnable; // Memory Write Invalidate bit in the PCI command word + UCHAR Congest; // Enables congestion control + ULONG SpeedDuplex; // New reg value for speed/duplex + + + // IDs + UCHAR RevsionID; + USHORT SubVendorID; + USHORT SubSystemID; + + // HW Resources + ULONG CacheFillSize; + PULONG IoBaseAddress; + ULONG IoRange; + PHYSICAL_ADDRESS MemPhysAddress; + + WDFINTERRUPT WdfInterrupt; + + BOOLEAN MappedPorts; + PHW_CSR CSRAddress; + BUS_INTERFACE_STANDARD BusInterface; + PREAD_PORT ReadPort; + PWRITE_PORT WritePort; + WDFDMAENABLER WdfDmaEnabler; + + // Media Link State + UCHAR CurrentScanPhyIndex; + UCHAR LinkDetectionWaitCount; + UCHAR FoundPhyAt; + USHORT EepromAddressSize; + MEDIA_STATE MediaState; + + // SEND + PMP_TCB CurrSendHead; + PMP_TCB CurrSendTail; + ULONG nBusySend; + LONG nWaitSend; + LONG nCancelSend; + WDFQUEUE WriteQueue; + WDFQUEUE PendingWriteQueue; + SINGLE_LIST_ENTRY SendBufList; + WDFSPINLOCK SendLock; + + ULONG NumTcb; // Total number of TCBs + LONG RegNumTcb; // 'NumTcb' + ULONG NumBuffers; + + + _Field_size_(MpTcbMemSize) PUCHAR MpTcbMem; + ULONG MpTcbMemSize; + + WDFCOMMONBUFFER WdfSendCommonBuffer; + + _Field_size_(HwSendMemAllocSize) PUCHAR HwSendMemAllocVa; + ULONG HwSendMemAllocSize; + PHYSICAL_ADDRESS HwSendMemAllocLa; // Logical Address + + // command unit status flags + BOOLEAN TransmitIdle; + BOOLEAN ResumeWait; + + // RECV + LIST_ENTRY RecvList; + ULONG nReadyRecv; + LONG RefCount; + + ULONG NumRfd; + ULONG CurrNumRfd; + ULONG MaxNumRfd; + ULONG HwRfdSize; + LONG RfdShrinkCount; + + WDFQUEUE PendingReadQueue; + WDFSPINLOCK RcvLock; + + BOOLEAN AllocNewRfd; + + // spin locks for protecting misc variables + WDFSPINLOCK Lock; + + // Packet Filter and look ahead size. + ULONG PacketFilter; + ULONG OldPacketFilter; + ULONG ulLookAhead; + USHORT usLinkSpeed; + USHORT usDuplexMode; + + // multicast list + UINT MCAddressCount; + UCHAR MCList[NIC_MAX_MCAST_LIST][ETH_LENGTH_OF_ADDRESS]; + + WDFCOMMONBUFFER WdfMiscCommonBuffer; + _Field_size_(HwMiscMemAllocSize) PUCHAR HwMiscMemAllocVa; + ULONG HwMiscMemAllocSize; + PHYSICAL_ADDRESS HwMiscMemAllocLa; // Logical Address + + PSELF_TEST_STRUC SelfTest; // 82558 SelfTest + ULONG SelfTestPhys; + BOOLEAN SelfTested; + + PNON_TRANSMIT_CB NonTxCmdBlock; // 82558 (non transmit) Command Block + ULONG NonTxCmdBlockPhys; + + PDUMP_AREA_STRUC DumpSpace; // 82558 dump buffer area + ULONG DumpSpacePhys; + + PERR_COUNT_STRUC StatsCounters; + ULONG StatsCounterPhys; + + UINT PhyAddress; // Address of the phy component + UCHAR Connector; // 0=Auto, 1=TPE, 2=MII + + UCHAR OldParameterField; + + ULONG HwErrCount; + + // WatchDog timer related fields + WDFTIMER WatchDogTimer; + BOOLEAN bLinkDetectionWait; + BOOLEAN bLookForLink; + BOOLEAN CheckForHang; + + // For handling IOCTLs - required if the upper edge is NDIS + WDFQUEUE IoctlQueue; + WDFQUEUE PendingIoctlQueue; + + // Packet counts + ULONG64 GoodTransmits; + ULONG64 GoodReceives; + ULONG NumTxSinceLastAdjust; + + // Count of transmit errors + ULONG TxAbortExcessCollisions; + ULONG TxLateCollisions; + ULONG TxDmaUnderrun; + ULONG TxLostCRS; + ULONG TxOKButDeferred; + ULONG OneRetry; + ULONG MoreThanOneRetry; + ULONG TotalRetries; + + // Count of receive errors + ULONG RcvCrcErrors; + ULONG RcvAlignmentErrors; + ULONG RcvResourceErrors; + ULONG RcvDmaOverrunErrors; + ULONG RcvCdtFrames; + ULONG RcvRuntErrors; + + // Count of bytes received & transmitted + ULONG64 BytesReceived; + ULONG64 BytesTransmitted; +} FDO_DATA, *PFDO_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, FdoGetData) + +#define CLRMASK(x, mask) ((x) &= ~(mask)); +#define SETMASK(x, mask) ((x) |= (mask)); + + +// +// Function prototypes +// +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD PciDrvEvtDeviceAdd; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP PciDrvEvtDriverContextCleanup; +EVT_WDF_DEVICE_CONTEXT_CLEANUP PciDrvEvtDeviceContextCleanup; + +EVT_WDF_DEVICE_D0_ENTRY PciDrvEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT PciDrvEvtDeviceD0Exit; +EVT_WDF_DEVICE_PREPARE_HARDWARE PciDrvEvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE PciDrvEvtDeviceReleaseHardware; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP PciDrvEvtDeviceSelfManagedIoCleanup; +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT PciDrvEvtDeviceSelfManagedIoInit; +EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND PciDrvEvtDeviceSelfManagedIoSuspend; +EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART PciDrvEvtDeviceSelfManagedIoRestart; + +EVT_WDF_DEVICE_ARM_WAKE_FROM_S0 PciDrvEvtDeviceWakeArmS0; +EVT_WDF_DEVICE_ARM_WAKE_FROM_SX PciDrvEvtDeviceWakeArmSx; +EVT_WDF_DEVICE_DISARM_WAKE_FROM_S0 PciDrvEvtDeviceWakeDisarmS0; +EVT_WDF_DEVICE_DISARM_WAKE_FROM_SX PciDrvEvtDeviceWakeDisarmSx; +EVT_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED PciDrvEvtDeviceWakeTriggeredS0; +EVT_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED PciDrvEvtDeviceWakeTriggeredSx; + +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL PciDrvEvtIoDeviceControl; + +NTSTATUS +PciDrvReturnResources ( + IN OUT PFDO_DATA FdoData + ); + +NTSTATUS +PciDrvSetPowerPolicy( + IN PFDO_DATA FdoData + ); + +NTSTATUS +PciDrvQueuePassiveLevelCallback( + IN PFDO_DATA FdoData, + IN PFN_WDF_WORKITEM CallbackFunction, + IN PVOID Context1, + IN PVOID Context2 + ); + +BOOLEAN +PciDrvReadRegistryValue( + _In_ PFDO_DATA FdoData, + _In_ PWSTR Name, + _Out_ PULONG Value + ); + +BOOLEAN +PciDrvWriteRegistryValue( + _In_ PFDO_DATA FdoData, + _In_ PWSTR Name, + _In_ ULONG Value + ); + + +NTSTATUS +PciDrvWmiRegistration( + WDFDEVICE hDevice +); + +PCHAR +DbgDevicePowerString( + IN WDF_POWER_DEVICE_STATE Type + ); + + +BOOLEAN +PciDrvReadFdoRegistryKeyValue( + _In_ PWDFDEVICE_INIT DeviceInit, + _In_ PWSTR Name, + _Out_ PULONG Value + ); + +#if defined(WIN2K) + +NTKERNELAPI +VOID +ExFreePoolWithTag( + _In_ PVOID P, + _In_ ULONG Tag + ); + +#endif + +#endif // _PCIDRV_H_ + + diff --git a/general/pcidrv/kmdf/PCIDRV.RC b/general/pcidrv/kmdf/PCIDRV.RC new file mode 100644 index 00000000..dd01a93c --- /dev/null +++ b/general/pcidrv/kmdf/PCIDRV.RC @@ -0,0 +1,33 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "WDM Driver for Intel 8255x Ethernet Adapters" +#define VER_INTERNALNAME_STR "PCIDRV.sys" +#define VER_ORIGINALFILENAME_STR "PCIDRV.sys" + +#define VER_FILEVERSION 1,00,00,0000 +#define VER_FILEVERSION_STR "1.00.00.0000" + +#undef VER_PRODUCTVERSION +#define VER_PRODUCTVERSION VER_FILEVERSION + +#undef VER_PRODUCTVERSION_STR +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR + +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) 2003 Microsoft Corporation" +#ifdef VER_COMPANYNAME_STR + +#undef VER_COMPANYNAME_STR +#define VER_COMPANYNAME_STR "Microsoft Corporation" +#endif + +#undef VER_PRODUCTNAME_STR +#define VER_PRODUCTNAME_STR "Microsoft Sample Driver for PCI Device" + +#include "common.ver" + + + diff --git a/general/pcidrv/kmdf/PCIDRV.mof b/general/pcidrv/kmdf/PCIDRV.mof new file mode 100644 index 00000000..283b6fb7 --- /dev/null +++ b/general/pcidrv/kmdf/PCIDRV.mof @@ -0,0 +1,19 @@ +#PRAGMA AUTORECOVER + +[Dynamic, Provider("WMIProv"), + WMI, + Description("PCIDRV Device Information"), + guid("{20E35E40-7179-4f89-A28C-12ED5A3CAAA5}"), + locale("MS\\0x409")] +class PciDeviceInformation +{ + [key, read] + string InstanceName; + [read] boolean Active; + + [WmiDataId(1), + read, + write, + Description("Current Mac Address of the NIC.")] + uint64 MacAddress; +};
\ No newline at end of file diff --git a/general/pcidrv/kmdf/genpci.inx b/general/pcidrv/kmdf/genpci.inx new file mode 100644 index 00000000..b1f30a6c --- /dev/null +++ b/general/pcidrv/kmdf/genpci.inx @@ -0,0 +1,127 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; +; GenPCI.INF +; +;Abstract: +; INF file for a generic PCI device. +; +;--*/ + +[Version] +Signature = "$WINDOWS NT$" +Class = Sample +ClassGuid = {78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider = %MSFT% +DriverVer = 03/20/2003,5.00.3788 +CatalogFile = KmdfSamples.cat + +[DestinationDirs] +DefaultDestDir = 12 + +;------------------------------------------------------------------------- +; Class Section +;------------------------------------------------------------------------- +[ClassInstall32] +Addreg = SampleClassReg + +[SampleClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 +HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. + +;------------------------------------------------------------------------- +; Device Install Section +;------------------------------------------------------------------------- +[ControlFlags] +ExcludeFromSelect = * + +[Manufacturer] +%MSFT%=MSFT,NT$ARCH$ + +[SourceDisksFiles] +pcidrv.sys = 1 + +[SourceDisksNames] +1=%DISK_NAME%, + +; For Win2K +[MSFT] +; DisplayName Section DeviceId +; ----------- ------- -------- +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1229 +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_103D +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1031 +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1038 + +; For XP and later +[MSFT.NT$ARCH$] +; DisplayName Section DeviceId +; ----------- ------- -------- +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1229 +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_103D +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1031 +%GenPCI.DRVDESC%=GenPCI_Inst, PCI\VEN_8086&DEV_1038 + +[GenPCI_Inst.NT] +CopyFiles = GenPCI.CopyFiles + + +[GenPCI.CopyFiles] +pcidrv.sys + + +[GenPCI_Inst.NT.Services] +AddService = GenPCI,0x00000002,GenPCI_Service + +[GenPCI_Service] +DisplayName = %GenPCI.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\pcidrv.sys + +;------------------------------------------------------------------------- +; WDF Coinstaller installation +;------------------------------------------------------------------------- +[DestinationDirs] +CoInstaller_CopyFiles = 11 + +[GenPCI_Inst.NT.CoInstallers] +AddReg = CoInstaller_AddReg +CopyFiles = CoInstaller_CopyFiles + +[CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1 ; make sure the number matches with SourceDisksNames + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[GenPCI_Inst.NT.Wdf] +KmdfService = GenPCI, GenPCI_wdfsect + +[GenPCI_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ + +[Strings] +MSFT = "Microsoft" +ClassName = "Sample Device" +GenPCI.SVCDESC = "Sample WDF PCI Driver Service for Intel 8255x Ethernet Controller" +GenPCI.DRVDESC = "Sample WDF PCI Driver for Intel 8255x Ethernet Controller" +DISK_NAME = "GenPCI Sample Install Disk" diff --git a/general/pcidrv/kmdf/public.h b/general/pcidrv/kmdf/public.h new file mode 100644 index 00000000..70a2087f --- /dev/null +++ b/general/pcidrv/kmdf/public.h @@ -0,0 +1,48 @@ +/*++ + Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + +Environment: + + user and kernel + +--*/ + +// +// Define an Interface Guid for toaster device class. +// This GUID is used to register (IoRegisterDeviceInterface) +// an instance of an interface so that user application +// can control the toaster device. +// + +DEFINE_GUID (GUID_DEVINTERFACE_PCIDRV, + 0xb74cfec2, 0x9366, 0x454a, 0xba, 0x71, 0x7c, 0x27, 0xb5, 0x14, 0x70, 0xa4); +// {B74CFEC2-9366-454a-BA71-7C27B51470A4} + +// +// Define a WMI GUID to get toaster device info. +// + +DEFINE_GUID (PCIDRV_WMI_STD_DATA_GUID, + 0x20e35e40, 0x7179, 0x4f89, 0xa2, 0x8c, 0x12, 0xed, 0x5a, 0x3c, 0xaa, 0xa5); + +// {20E35E40-7179-4f89-A28C-12ED5A3CAAA5} + +// +// GUID definition are required to be outside of header inclusion pragma to avoid +// error during precompiled headers. +// + diff --git a/general/pcidrv/kmdf/trace.h b/general/pcidrv/kmdf/trace.h new file mode 100644 index 00000000..2c041319 --- /dev/null +++ b/general/pcidrv/kmdf/trace.h @@ -0,0 +1,140 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TRACE.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + HEXDUMP is not defined by default. So we have to provide a localwpp.ini file + that defines type. + +Environment: + + Kernel mode + +--*/ + +#include <evntrace.h> // For TRACE_LEVEL definitions + +#if !defined(EVENT_TRACING) + +// +// TODO: These defines are missing in evntrace.h +// in some DDK build environments (XP). +// +#if !defined(TRACE_LEVEL_NONE) + #define TRACE_LEVEL_NONE 0 + #define TRACE_LEVEL_CRITICAL 1 + #define TRACE_LEVEL_FATAL 1 + #define TRACE_LEVEL_ERROR 2 + #define TRACE_LEVEL_WARNING 3 + #define TRACE_LEVEL_INFORMATION 4 + #define TRACE_LEVEL_VERBOSE 5 + #define TRACE_LEVEL_RESERVED6 6 + #define TRACE_LEVEL_RESERVED7 7 + #define TRACE_LEVEL_RESERVED8 8 + #define TRACE_LEVEL_RESERVED9 9 +#endif + + +// +// Define Debug Flags +// +#define DBG_INIT 0x00000001 +#define DBG_PNP 0x00000002 +#define DBG_POWER 0x00000004 +#define DBG_WMI 0x00000008 +#define DBG_CREATE_CLOSE 0x00000010 +#define DBG_IOCTLS 0x00000020 +#define DBG_WRITE 0x00000040 +#define DBG_READ 0x00000080 +#define DBG_DPC 0x00000100 +#define DBG_INTERRUPT 0x00000200 +#define DBG_LOCKS 0x00000400 +#define DBG_QUEUEING 0x00000800 +#define DBG_HW_ACCESS 0x00001000 + +VOID +TraceEvents ( + IN ULONG DebugPrintLevel, + IN ULONG DebugPrintFlag, + IN PCCHAR DebugMessage, + ... + ); + +#define Hexdump(x) // Used for HEXDUMP in case tracing is enabled +#define WPP_INIT_TRACING(DriverObject, RegistryPath) +#define WPP_CLEANUP(DriverObject) + +#else +// +// If software tracing is defined in the sources file.. +// WPP_DEFINE_CONTROL_GUID specifies the GUID used for this driver. +// *** REPLACE THE GUID WITH YOUR OWN UNIQUE ID *** +// WPP_DEFINE_BIT allows setting debug bit masks to selectively print. +// The names defined in the WPP_DEFINE_BIT call define the actual names +// that are used to control the level of tracing for the control guid +// specified. +// +// Name of the logger is PciDrv and the guid is +// {BC6C9364-FC67-42c5-ACF7-ABED3B12ECC6} +// (0xbc6c9364, 0xfc67, 0x42c5, 0xac, 0xf7, 0xab, 0xed, 0x3b, 0x12, 0xec, 0xc6); +// + +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(PciDrvTraceGuid,(bc6c9364,fc67,42c5,acf7,abed3b12ecc6), \ + WPP_DEFINE_BIT(DBG_INIT) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(DBG_PNP) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(DBG_POWER) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(DBG_WMI) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(DBG_CREATE_CLOSE) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(DBG_IOCTLS) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(DBG_WRITE) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(DBG_READ) /* bit 7 = 0x00000080 */ \ + WPP_DEFINE_BIT(DBG_DPC) /* bit 8 = 0x00000100 */ \ + WPP_DEFINE_BIT(DBG_INTERRUPT) /* bit 9 = 0x00000200 */ \ + WPP_DEFINE_BIT(DBG_LOCKS) /* bit 10 = 0x00000400 */ \ + WPP_DEFINE_BIT(DBG_QUEUEING) /* bit 11 = 0x00000800 */ \ + WPP_DEFINE_BIT(DBG_HW_ACCESS) /* bit 12 = 0x00001000 */ \ + /* You can have up to 32 defines. If you want more than that,\ + you have to provide another trace control GUID */\ + ) + + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +#pragma warning(disable:4204) // C4204 nonstandard extension used : non-constant aggregate initializer + +// +// Define the 'xstr' structure for logging buffer and length pairs +// and the 'log_xstr' function which returns it to create one in-place. +// this enables logging of complex data types. +// +typedef struct xstr { char * _buf; short _len; } xstr_t; +__inline xstr_t log_xstr(void * p, short l) { xstr_t xs = {(char*)p,l}; return xs; } + +#pragma warning(default:4204) + +// +// Define the macro required for a hexdump use as: +// +// DebugTraceEx((LEVEL, FLAG,"%!HEXDUMP!\n", log_xstr(buffersize,(char *)buffer) )); +// +// +#define WPP_LOGHEXDUMP(x) WPP_LOGPAIR(2, &((x)._len)) WPP_LOGPAIR((x)._len, (x)._buf) + +#endif + + diff --git a/general/pcidrv/kmdf/wmi.c b/general/pcidrv/kmdf/wmi.c new file mode 100644 index 00000000..a0c5eba5 --- /dev/null +++ b/general/pcidrv/kmdf/wmi.c @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + WMI.C + +Abstract: + + This module handle all the WMI Irps. + +Environment: + + Kernel mode + +--*/ + + +#include "precomp.h" + +#if defined(EVENT_TRACING) +#include "wmi.tmh" +#endif + + +#define MOFRESOURCENAME L"PciDrvWMI" + +EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiDeviceInfoQueryInstance; + +EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiDeviceInfoSetInstance; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, PciDrvWmiRegistration) +#pragma alloc_text(PAGE, EvtWmiDeviceInfoQueryInstance) +#pragma alloc_text(PAGE, EvtWmiDeviceInfoSetInstance) +#endif + +NTSTATUS +PciDrvWmiRegistration( + WDFDEVICE Device + ) +/*++ +Routine Description + + Registers with WMI as a data provider for this + instance of the device + +--*/ +{ + WDF_WMI_PROVIDER_CONFIG providerConfig; + WDF_WMI_INSTANCE_CONFIG instanceConfig; + NTSTATUS status; + DECLARE_CONST_UNICODE_STRING(mofRsrcName, MOFRESOURCENAME); + + PAGED_CODE(); + + status = WdfDeviceAssignMofResourceName(Device, &mofRsrcName); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfDeviceAssignMofResourceName failed 0x%x", status); + return status; + } + + WDF_WMI_PROVIDER_CONFIG_INIT(&providerConfig, &PCIDRV_WMI_STD_DATA_GUID); + providerConfig.MinInstanceBufferSize = sizeof(PCIDRV_WMI_STD_DATA); + + WDF_WMI_INSTANCE_CONFIG_INIT_PROVIDER_CONFIG(&instanceConfig, &providerConfig); + instanceConfig.Register = TRUE; + instanceConfig.EvtWmiInstanceQueryInstance = EvtWmiDeviceInfoQueryInstance; + instanceConfig.EvtWmiInstanceSetInstance = EvtWmiDeviceInfoSetInstance; + + // + // No need to get the newly creawted handle because we just reference data + // from our device extension directly. + // + status = WdfWmiInstanceCreate(Device, + &instanceConfig, + WDF_NO_OBJECT_ATTRIBUTES, + WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP, + "WdfWmiInstanceCreate failed 0x%x", status); + return status; + } + + return status; +} + +NTSTATUS +EvtWmiDeviceInfoQueryInstance( + _In_ WDFWMIINSTANCE WmiInstance, + _In_ ULONG OutBufferSize, + _Out_writes_bytes_to_(OutBufferSize, *BufferUsed) PVOID OutBuffer, + _Out_ PULONG BufferUsed + ) +{ + PFDO_DATA fdoData; + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + *BufferUsed = sizeof(fdoData->CurrentAddress); + + if (OutBufferSize < sizeof(fdoData->CurrentAddress)) { + return STATUS_BUFFER_TOO_SMALL; + } + + RtlZeroMemory(OutBuffer, OutBufferSize); + RtlCopyMemory(OutBuffer, fdoData->CurrentAddress, sizeof(fdoData->CurrentAddress)); + + return STATUS_SUCCESS; +} + +NTSTATUS +EvtWmiDeviceInfoSetInstance( + _In_ WDFWMIINSTANCE WmiInstance, + _In_ ULONG InBufferSize, + _In_reads_bytes_(InBufferSize) PVOID InBuffer + ) +{ + PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(InBufferSize); + + PAGED_CODE(); + + fdoData = FdoGetData(WdfWmiInstanceGetDevice(WmiInstance)); + + if (InBufferSize < sizeof(fdoData->CurrentAddress)) { + return STATUS_WMI_SET_FAILURE; + } + + RtlCopyMemory(fdoData->CurrentAddress, InBuffer, sizeof(fdoData->CurrentAddress)); + + return STATUS_SUCCESS; +} + diff --git a/general/pcidrv/pcidrv.sln b/general/pcidrv/pcidrv.sln new file mode 100644 index 00000000..e6607b8a --- /dev/null +++ b/general/pcidrv/pcidrv.sln @@ -0,0 +1,49 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{EFA400EA-F405-4FB2-AC59-22D52ED1C479}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HW", "HW", "{8CBB3334-12D6-42CE-BD7A-A6F00E08FE45}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Kmdf", "Kmdf", "{A8847B95-FC0F-4553-9D94-354FE3C0A56E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "myping", "test\myping.vcxproj", "{AAB2FA59-187D-45F7-A84F-09C7089848B3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PCIDRV", "kmdf\HW\PCIDRV.vcxproj", "{2221261F-E1E2-4562-A15D-2EF8BF7D878E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.ActiveCfg = Debug|Win32 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|Win32.Build.0 = Debug|Win32 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.ActiveCfg = Release|Win32 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|Win32.Build.0 = Release|Win32 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.ActiveCfg = Debug|x64 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Debug|x64.Build.0 = Debug|x64 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.ActiveCfg = Release|x64 + {AAB2FA59-187D-45F7-A84F-09C7089848B3}.Release|x64.Build.0 = Release|x64 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.ActiveCfg = Debug|Win32 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|Win32.Build.0 = Debug|Win32 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.ActiveCfg = Release|Win32 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|Win32.Build.0 = Release|Win32 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.ActiveCfg = Debug|x64 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Debug|x64.Build.0 = Debug|x64 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.ActiveCfg = Release|x64 + {2221261F-E1E2-4562-A15D-2EF8BF7D878E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {AAB2FA59-187D-45F7-A84F-09C7089848B3} = {EFA400EA-F405-4FB2-AC59-22D52ED1C479} + {2221261F-E1E2-4562-A15D-2EF8BF7D878E} = {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45} + {8CBB3334-12D6-42CE-BD7A-A6F00E08FE45} = {A8847B95-FC0F-4553-9D94-354FE3C0A56E} + EndGlobalSection +EndGlobal diff --git a/general/pcidrv/test/myping.c b/general/pcidrv/test/myping.c new file mode 100644 index 00000000..b0c2d22c --- /dev/null +++ b/general/pcidrv/test/myping.c @@ -0,0 +1,1054 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + MYPING.C + +Abstract: + + + +Environment: + + usermode console application + +--*/ +#define _WINSOCK_DEPRECATED_NO_WARNINGS + +#include "testapp.h" +#include "nuiouser.h" +#include <intsafe.h> + +#define MAX_HEADER_SIZE (sizeof(ETH_HEADER) + sizeof(IpHeader) + sizeof(IcmpHeader)) +#define MAX_ECHO_PAY_LOAD (ETH_MAX_PACKET_SIZE - MAX_HEADER_SIZE) + + +#define ETH_HEADER_SIZE 14 +#define ETH_MAX_DATA_SIZE 1500 +#define ETH_MAX_PACKET_SIZE ETH_HEADER_SIZE + ETH_MAX_DATA_SIZE +#define ETH_MIN_PACKET_SIZE 60 + +#define ARP_ETYPE_ARP 0x806 +#define IP_PROT_TYPE 0x800 +#define ARP_REQUEST 1 +#define ARP_RESPONSE 2 +#define ARP_HW_ENET 1 + +#define PROTOCOL_ICMP 1 + +// ICMP types and codes +#define ICMPV4_ECHO_REQUEST_TYPE 8 +#define ICMPV4_ECHO_REQUEST_CODE 0 +#define ICMPV4_ECHO_REPLY_TYPE 0 +#define ICMPV4_ECHO_REPLY_CODE 0 +#define ICMPV4_MINIMUM_HEADER 8 + +#define DEFAULT_DATA_SIZE 32 // default data size + +#define DEFAULT_SEND_COUNT 32767 // number of ICMP requests to send + +#define DEFAULT_RECV_TIMEOUT 6000 // six second + +#define DEFAULT_TTL 128 + +#define IP_ADDR_LEN 4 + +#include <pshpack1.h> + +// ======================================================================== +// The IP header +// + +typedef struct iphdr { + unsigned char verlen; + unsigned char tos; // Type of service + unsigned short total_len; // total length of the packet + unsigned short ident; // unique identifier + unsigned short frag_and_flags; // flags + unsigned char ttl; // time to live + unsigned char proto; // protocol (TCP, UDP etc) + unsigned char checksumHigh; + unsigned char checksumLow; + unsigned int sourceIP; // source ip address + unsigned int destIP; // destination ip address + +} IpHeader; + +// ======================================================================== +// ICMP header +// + +typedef struct _ihdr { + BYTE i_type; + BYTE i_code; /* type sub code */ + USHORT i_cksum; + USHORT i_id; + USHORT i_seq; + ULONG timestamp; /* non standard, reserve space for time */ +} IcmpHeader; + +typedef struct _ETH_HEADER +{ + UCHAR DstAddr[MAC_ADDR_LEN]; + UCHAR SrcAddr[MAC_ADDR_LEN]; + USHORT EthType; +} ETH_HEADER, *PETH_HEADER; + +// Structure of an ARP header. +typedef struct _ARP_BODY { + USHORT hw; // Hardware address space. = 00 01 + USHORT pro; // Protocol address space. = 08 00 + UCHAR hlen; // Hardware address length. = 06 + UCHAR plen; // Protocol address length. = 04 + USHORT opcode; // Opcode. + UCHAR SenderHwAddr[MAC_ADDR_LEN]; // Source HW address. + UINT SenderIpAddr; // Source protocol address. + UCHAR DestHwAddr[MAC_ADDR_LEN]; // Destination HW address. + UINT DestIPAddr; // Destination protocol address. +} _ARP_BODY, *PARP_BODY; + +#include <poppack.h> + +// +// For Read operation. +// +typedef struct _RCB { + OVERLAPPED Overlapped; + char Buffer[ETH_MAX_PACKET_SIZE]; + PDEVICE_INFO DeviceInfo; +}RCB, *PRCB; + +// +// For Write operation. +// +typedef struct _TCB { + OVERLAPPED Overlapped; + char *Buffer; // packet length is user specified. + ULONG BufferLength; + PDEVICE_INFO DeviceInfo; + +}TCB, *PTCB; + +unsigned short PacketId; + +VOID +PostNextRead( + RCB *pRCB + ); + + +// +// Function: SetIcmpSequence +// +// Description: +// This routine sets the sequence number of the ICMP request packet. +// +VOID +SetIcmpSequence( + _At_((IcmpHeader*)buf, _Out_writes_bytes_all_(bufSize)) char *buf, + _In_ _In_range_(==, sizeof(IcmpHeader)) ULONG bufSize + ) +{ + ULONG sequence=0; + IcmpHeader *icmpv4=NULL; + + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above") + sequence = GetTickCount(); + + icmpv4 = (IcmpHeader *)buf; + + icmpv4->i_seq = (USHORT)sequence; +} + +// +// Using _Inexpressible_ to suppress prefast warning 2014 : "Potential overflow +// using expression at icmp_hdr->i_code" +// +VOID +InitIcmpHeader( + _Out_writes_bytes_(_Inexpressible_(bufSize + datasize)) char *buf, + ULONG bufSize, + int datasize) +{ + IcmpHeader *icmp_hdr=NULL; + char *datapart=NULL; + + icmp_hdr = (IcmpHeader *)buf; + icmp_hdr->i_type = ICMPV4_ECHO_REQUEST_TYPE; // request an ICMP echo + icmp_hdr->i_code = ICMPV4_ECHO_REQUEST_CODE; + icmp_hdr->i_id = htons((USHORT)PacketId++); + icmp_hdr->i_cksum = 0; + icmp_hdr->i_seq = 0; + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above") + icmp_hdr->timestamp= htonl(GetTickCount()); + + datapart = buf + sizeof(IcmpHeader); + // + // Place some junk in the buffer. + // + memset(datapart, 'X', datasize); +} + +VOID +ComputeIPChecksum ( + IpHeader *pIPHeader + ) +////////////////////////////////////////////////////////////////////////////// +{ + ULONG Checksum; + PUCHAR NextChar; + + pIPHeader->checksumHigh = pIPHeader->checksumLow = 0; + Checksum = 0; + for ( NextChar = (PUCHAR) pIPHeader + ; (NextChar - (PUCHAR) pIPHeader) <= (sizeof(IpHeader) - 2) + ; NextChar += 2) + { + Checksum += ((ULONG) (NextChar[0]) << 8) + (ULONG) (NextChar[1]); + } + + Checksum = (Checksum >> 16) + (Checksum & 0xffff); + Checksum += (Checksum >> 16); + Checksum = ~Checksum; + + pIPHeader->checksumHigh = (UCHAR) ((Checksum >> 8) & 0xff); + pIPHeader->checksumLow = (UCHAR) (Checksum & 0xff); +} + +// +// Function: checksum +// +// Description: +// This function calculates the 16-bit one's complement sum +// of the supplied buffer (ICMP) header. +// +USHORT +checksum( + USHORT *buffer, + int size + ) +{ + unsigned long cksum=0; + + while (size > 1) + { + cksum += *buffer++; + size -= sizeof(USHORT); + } + if (size) + { + cksum += *(UCHAR*)buffer; + } + cksum = (cksum >> 16) + (cksum & 0xffff); + cksum += (cksum >>16); + return (USHORT)(~cksum); +} + + +VOID +ComputeIcmpChecksum( + _At_((IcmpHeader*) buf, _Inout_updates_bytes_all_(bufSize)) char *buf, + _In_ _In_range_(==, sizeof(IcmpHeader)) ULONG bufSize, + int packetlen + ) +{ + IcmpHeader *icmpv4; + + icmpv4 = (IcmpHeader *)buf; + icmpv4->i_cksum = 0; + icmpv4->i_cksum = checksum((USHORT *)buf, packetlen); +} + +void +InitEtherHeader( + PDEVICE_INFO DeviceInfo, + PETH_HEADER pEthHeader + ) +{ + + pEthHeader->EthType = htons(IP_PROT_TYPE); + memcpy(pEthHeader->DstAddr, DeviceInfo->TargetMacAddr, MAC_ADDR_LEN); + memcpy(pEthHeader->SrcAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN); + + +} + +BOOL +InitIpHeader( + PDEVICE_INFO DeviceInfo, + IpHeader *pIpHeader, + unsigned short IpLength) +{ + pIpHeader->verlen = 0x45; + pIpHeader->tos = 0; //Normal service + pIpHeader->total_len = htons(IpLength); + pIpHeader->ident = htons(0xABBA); + pIpHeader->frag_and_flags = 0; + pIpHeader->ttl = DEFAULT_TTL; + pIpHeader->proto = PROTOCOL_ICMP; + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + pIpHeader->sourceIP = inet_addr(DeviceInfo->SourceIp); + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + pIpHeader->destIP = inet_addr(DeviceInfo->DestIp); + + return TRUE; +} +VOID WriteComplete(DWORD dwError, DWORD dwBytesTransferred, LPOVERLAPPED pOvl) +{ + TCB* pTCB = (TCB *)pOvl; + + if (dwError) { + if(dwError == ERROR_DEVICE_NOT_CONNECTED) { + Display(TEXT("WriteComplete: Device not connected")); + } + else { + Display(TEXT("WriteComplete: Error %x"), dwError); + + } + } + + DisplayV(TEXT("Write Complete: %x"), dwBytesTransferred); + HeapFree (GetProcessHeap(), 0, pTCB->Buffer); + HeapFree (GetProcessHeap(), 0, pTCB); +} + +VOID WriteCompleteArp(DWORD dwError, DWORD dwBytesTransferred, LPOVERLAPPED pOvl) +{ + if (dwError) { + if(dwError == ERROR_DEVICE_NOT_CONNECTED) { + Display(TEXT("WriteCompleteArp: Device not connected")); + } + else { + Display(TEXT("WriteCompleteArp: Error %x"), dwError); + + } + } + + DisplayV(TEXT("Write Complete ARP: %x"), dwBytesTransferred); +} + +VOID +ReadMacAddrComplete( + DWORD dwError, + DWORD dwBytesTransferred, + LPOVERLAPPED pOvl + ) +{ + if (ERROR_OPERATION_ABORTED != dwError) + { + RCB* pRCB = (RCB *)pOvl; + + char *Buffer = pRCB->Buffer; + PETH_HEADER ethHeader = (PETH_HEADER) Buffer; + PARP_BODY pBody; + + PDEVICE_INFO deviceInfo = pRCB->DeviceInfo; + WCHAR unicodeIpAddr[MAX_LEN]; + char *ipAddr; + + DisplayV(TEXT("ReadMacAddrComplete: %x"), dwBytesTransferred); + + if(ntohs(ethHeader->EthType) == ARP_ETYPE_ARP){ + + pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER)); + + if(ntohs(pBody->opcode) == ARP_RESPONSE){ + #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6") + struct in_addr IPAddr = {0}; + + memcpy(&IPAddr, &pBody->SenderIpAddr, IP_ADDR_LEN); + + if(memcmp(pBody->DestHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN) == 0){ + + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + ipAddr = inet_ntoa(IPAddr); + + if (!MultiByteToWideChar ( + CP_ACP, + 0, + ipAddr, + -1, // string is null terminated + unicodeIpAddr, + sizeof(unicodeIpAddr)/sizeof(WCHAR) + )) { + Display(TEXT("AnsitoUnicode conversion failed")); + + } + + DisplayV(TEXT("Target IP Address: %ws"), unicodeIpAddr); + + DisplayV(TEXT("Target Mac Address: %02X-%02X-%02X-%02X-%02X-%02X-"), + pBody->SenderHwAddr[0], + pBody->SenderHwAddr[1], + pBody->SenderHwAddr[2], + pBody->SenderHwAddr[3], + pBody->SenderHwAddr[4], + pBody->SenderHwAddr[5] + ); + memcpy(deviceInfo->TargetMacAddr, pBody->SenderHwAddr, MAC_ADDR_LEN); + + SetEvent(deviceInfo->PingEvent); + return; + } + } + } + + if(!ReadFileEx(pRCB->DeviceInfo->hDevice, pRCB->Buffer, sizeof(pRCB->Buffer), + &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadMacAddrComplete)){ + Display(TEXT("ReadMacAddrComplete: ReadFileEx failed %x"), GetLastError()); + } + + } +} + +BOOL +GetTargetMac( + PDEVICE_INFO DeviceInfo, + PRCB pRCB + ) +{ + char *Buffer = NULL; + PETH_HEADER ethHeader = NULL; + PARP_BODY pBody = NULL; + unsigned int retries =0; + DWORD status; + HANDLE hDevice = pRCB->DeviceInfo->hDevice; + PTCB pTCB = NULL; + + if(!ReadFileEx(hDevice, pRCB->Buffer, sizeof(pRCB->Buffer), + &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadMacAddrComplete)) + { + Display(TEXT("GetTargetMac: Error in ReadFile %x"), GetLastError()); + return FALSE; + } + + // + // We will try asking for mac address ten times. If we don't get valid response, + // we will bail out. + // + while(retries < 10){ + + // + // Allocate memory for the TCB and it's buffer. Writes are overlapped. + // We don't wait for the write requests to complete before posting + // another one. + // + pTCB = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCB)); + if(!pTCB){ + Display(TEXT("Ping: HeapAlloc Failed")); + return FALSE; + } + + pTCB->Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ETH_MAX_PACKET_SIZE); + if(!pTCB->Buffer){ + Display(TEXT("Ping: HeapAlloc Failed")); + HeapFree (GetProcessHeap(), 0, pTCB); + return FALSE; + } + + pTCB->BufferLength = ETH_MAX_PACKET_SIZE; + memset(&pTCB->Overlapped, 0, sizeof(OVERLAPPED)); + pTCB->DeviceInfo = DeviceInfo; + + Buffer = pTCB->Buffer; + memset(Buffer, 0, ETH_MIN_PACKET_SIZE); + + ethHeader = (PETH_HEADER) Buffer; + + + memcpy(ethHeader->SrcAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN); + memset(ethHeader->DstAddr, 0xff, MAC_ADDR_LEN); + ethHeader->EthType = htons(ARP_ETYPE_ARP); //Network byte order + + pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER)); + pBody->hw = htons(ARP_REQUEST); //Network byte order + pBody->pro = htons(IP_PROT_TYPE); //Network byte order + pBody->hlen = MAC_ADDR_LEN; + pBody->plen = IP_ADDR_LEN; + pBody->opcode = 0x0100; + + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + pBody->SenderIpAddr = inet_addr(DeviceInfo->SourceIp); + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + pBody->DestIPAddr = inet_addr(DeviceInfo->DestIp); + + memcpy(pBody->SenderHwAddr, DeviceInfo->SrcMacAddr, MAC_ADDR_LEN); + + if(!WriteFileEx(hDevice, pTCB->Buffer, ETH_MIN_PACKET_SIZE, &pTCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteComplete)) + { + Display(TEXT("GetTargetMac WriteFile failed %x"), GetLastError()); + HeapFree (GetProcessHeap(), 0, pTCB->Buffer); + HeapFree (GetProcessHeap(), 0, pTCB); + return FALSE; + } + + retries++; + // + // Wait for the PingEvent to be signalled. This even is signalled when the + // ReadMacAddrComplete received a valid packet + // +wait: + status = WaitForSingleObjectEx(DeviceInfo->PingEvent, 1000, TRUE ); + + if ( status == WAIT_OBJECT_0 ) { // event fired, not timeout + // + // Got a valid response. Hurray! + // + return TRUE; + } + + if ( status == WAIT_IO_COMPLETION ) { + // Either Read/Write completed. Go back to waiting until the completion rotuine + // processes the response and sigals the event. + goto wait; + } + if (status != WAIT_TIMEOUT){ + // + // It has to be timeout at this point. Or else something fatal, break out. + Display(TEXT("WaitForSingleObjectEx returned error %d"), status); + return FALSE; + } + } + + return FALSE; +} + +BOOL +GetSrcMac( + HANDLE Handle, + PUCHAR pSrcMacAddr + ) +{ + DWORD BytesReturned; + BOOLEAN bSuccess; + UCHAR QueryBuffer[sizeof(NDISPROT_QUERY_OID) + MAC_ADDR_LEN]; + PNDISPROT_QUERY_OID pQueryOid; + + + DisplayV(TEXT("Trying to get src mac address"), NULL); + + pQueryOid = (PNDISPROT_QUERY_OID)&QueryBuffer[0]; + pQueryOid->Oid = OID_802_3_CURRENT_ADDRESS; + + bSuccess = (BOOLEAN)DeviceIoControl( + Handle, + IOCTL_NDISPROT_QUERY_OID_VALUE, + (LPVOID)&QueryBuffer[0], + sizeof(QueryBuffer), + (LPVOID)&QueryBuffer[0], + sizeof(QueryBuffer), + &BytesReturned, + NULL); + + if (bSuccess) + { + DisplayV(TEXT("GetSrcMac: IoControl success")); + memcpy(pSrcMacAddr, &pQueryOid->Data[0], MAC_ADDR_LEN); + + + } + else + { + Display(TEXT("GetSrcMac: IoControl failed %x\n"), GetLastError()); + } + + return (bSuccess); +} + +VOID +PrintIpHeader( + IpHeader *pIpHeader + ) +{ + #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6") + struct in_addr IPAddr = {0}; + + DisplayV(TEXT("Ip Proto %x"), pIpHeader->proto); + DisplayV(TEXT("Ip VerLen %x"), pIpHeader->verlen); + DisplayV(TEXT("Ip Total Len %d"), pIpHeader->total_len); + DisplayV(TEXT("Ip Ident %d"), pIpHeader->ident); + DisplayV(TEXT("Ip tos %x"), pIpHeader->tos); + + memcpy(&IPAddr, &pIpHeader->sourceIP, IP_ADDR_LEN); + + // Display(TEXT("Source IP %s"), inet_ntoa(IPAddr)); + + memcpy(&IPAddr, &pIpHeader->destIP, IP_ADDR_LEN); + + // Display(TEXT("Dest IP %s"), inet_ntoa(IPAddr)); + +} + + +BOOL +SetPacketFilter( + HANDLE Handle, + ULONG PacketFilter + ) +{ + DWORD BytesReturned; + BOOLEAN bSuccess; + NDISPROT_SET_OID SetOid; + + + DisplayV(TEXT("Trying to SetPacketFilter"), NULL); + + SetOid.Oid = OID_GEN_CURRENT_PACKET_FILTER; + + memcpy(&SetOid.Data[0], &PacketFilter, sizeof(ULONG)); + + bSuccess = (BOOLEAN)DeviceIoControl( + Handle, + IOCTL_NDISPROT_SET_OID_VALUE, + (LPVOID)&SetOid, + sizeof(NDISPROT_SET_OID), + NULL, + 0, + &BytesReturned, + NULL); + + if (!bSuccess) + { + Display(TEXT("SetPacketFilter: IoControl failed: %d"), GetLastError()); + } + + return (bSuccess); +} + + +VOID +ProcessReadBuffer( + PRCB pRCB, + ULONG BufferLength + ) +{ + char *Buffer = pRCB->Buffer; + PETH_HEADER ethHeader = (PETH_HEADER) Buffer; + PARP_BODY pBody = (PARP_BODY)(Buffer + sizeof(ETH_HEADER)); + char ArpResponse[ETH_MIN_PACKET_SIZE] = {0}; + PETH_HEADER pResEthHeader = (PETH_HEADER)ArpResponse; + PARP_BODY pRespBody = (PARP_BODY)(ArpResponse + sizeof(ETH_HEADER)); + OVERLAPPED ov = {0}; + PDEVICE_INFO deviceInfo = pRCB->DeviceInfo; + HANDLE hDevice = deviceInfo->hDevice; + + // Check whether its a broadcast ARP request + if (ethHeader->DstAddr[0] == 0xff && + ethHeader->DstAddr[1] == 0xff ) + { + + if(ntohs(ethHeader->EthType) != ARP_ETYPE_ARP){ + deviceInfo->Sleep = FALSE; + DisplayV(TEXT("Non an arp eth request")); + goto End; + } + + if (IP_PROT_TYPE != ntohs(pBody->pro) || + MAC_ADDR_LEN != pBody->hlen || + IP_ADDR_LEN != pBody->plen ) + { + // + // these are just sanity checks + // + deviceInfo->Sleep = FALSE; + DisplayV(TEXT("Non an arp packet")); + goto End; + } + + DisplayV(TEXT("This is an arp request")); + + memcpy(pResEthHeader->DstAddr, ethHeader->SrcAddr, MAC_ADDR_LEN); + memcpy(pResEthHeader->SrcAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); + pResEthHeader->EthType = ethHeader->EthType; + + pRespBody->hw = pBody->hw; // Hardware address space. = 00 01 + + pRespBody->pro = pBody->pro; // Protocol address space. = 08 00 + + pRespBody->hlen = MAC_ADDR_LEN; // 6 + + pRespBody->plen = IP_ADDR_LEN; // 4 + + pRespBody->opcode = htons(ARP_RESPONSE); // Opcode. + + memcpy(pRespBody->SenderHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); // Destination HW address. + + pRespBody->SenderIpAddr = pBody->DestIPAddr ; // Source protocol address. + + memcpy(pRespBody->DestHwAddr, pBody->SenderHwAddr, MAC_ADDR_LEN); // Destination HW address. + + pRespBody->DestIPAddr = pBody->SenderIpAddr; + + PostNextRead(pRCB); + + DisplayV(TEXT("Writing Arp response\n")); + if(!WriteFileEx(hDevice, ArpResponse, sizeof(ArpResponse), &ov, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteCompleteArp)) + { + Display(TEXT("Couldn't write arp response %d"), GetLastError()); + return ; + } + } + // Check whether its an unicast ARP request + else if (ethHeader->DstAddr[0] == deviceInfo->SrcMacAddr[0] && + ethHeader->DstAddr[1] == deviceInfo->SrcMacAddr[1] && + ethHeader->DstAddr[2] == deviceInfo->SrcMacAddr[2] && + ethHeader->DstAddr[3] == deviceInfo->SrcMacAddr[3] && + ethHeader->DstAddr[4] == deviceInfo->SrcMacAddr[4] && + ethHeader->DstAddr[5] == deviceInfo->SrcMacAddr[5] && + ntohs(ethHeader->EthType) == ARP_ETYPE_ARP && + IP_PROT_TYPE == ntohs(pBody->pro) && + MAC_ADDR_LEN == pBody->hlen && + IP_ADDR_LEN == pBody->plen) { + + // If it passed all these checks, its an ARP request + memcpy(pResEthHeader->DstAddr, ethHeader->SrcAddr, MAC_ADDR_LEN); + memcpy(pResEthHeader->SrcAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); + pResEthHeader->EthType = ethHeader->EthType; + + pRespBody->hw = pBody->hw; // Hardware address space. = 00 01 + + pRespBody->pro = pBody->pro; // Protocol address space. = 08 00 + + pRespBody->hlen = MAC_ADDR_LEN; // 6 + + pRespBody->plen = IP_ADDR_LEN; // 4 + + pRespBody->opcode = htons(ARP_RESPONSE); // Opcode. + + memcpy(pRespBody->SenderHwAddr, deviceInfo->SrcMacAddr, MAC_ADDR_LEN); // Destination HW address. + + pRespBody->SenderIpAddr = pBody->DestIPAddr ; // Source protocol address. + + memcpy(pRespBody->DestHwAddr, pBody->SenderHwAddr, MAC_ADDR_LEN); // Destination HW address. + + pRespBody->DestIPAddr = pBody->SenderIpAddr; + + PostNextRead(pRCB); + + DisplayV(TEXT("Writing Arp response\n")); + if(!WriteFileEx(hDevice, ArpResponse, sizeof(ArpResponse), &ov, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteCompleteArp)) + { + Display(TEXT("Couldn't write arp response %d"), GetLastError()); + return ; + } + } + else { + + IpHeader *pIpHeader = (IpHeader *)(Buffer + sizeof(ETH_HEADER)); + IcmpHeader *pIcmpHeader = (IcmpHeader *)(Buffer + sizeof(ETH_HEADER)+sizeof(IpHeader));//TODO: Find the iP len from the packet + ULONG datalen = BufferLength - sizeof(ETH_HEADER) - sizeof(IpHeader) - sizeof(IcmpHeader); + #pragma prefast(suppress:__WARNING_IPV6_ADDRESS_STRUCTURE_IPV4_SPECIFIC, "This test app doesn't support IPv6") + struct in_addr IPAddr = {0}; + char *ipAddr; + WCHAR unicodeIpAddr[MAX_LEN]; + + PrintIpHeader(pIpHeader); + + if(pIpHeader->proto == PROTOCOL_ICMP && pIcmpHeader->i_type == ICMPV4_ECHO_REPLY_TYPE && + pIcmpHeader->i_type == ICMPV4_ECHO_REPLY_CODE){ + + memcpy(&IPAddr, &pIpHeader->sourceIP, IP_ADDR_LEN); + + #pragma prefast(suppress:__WARNING_IPV6_NAME_RESOLUTION_IPV4_SPECIFIC, "This test app doesn't support IPv6") + ipAddr = inet_ntoa(IPAddr); + + if (!MultiByteToWideChar ( + CP_ACP, + 0, + ipAddr, + -1, + unicodeIpAddr, + sizeof(unicodeIpAddr)/sizeof(unicodeIpAddr[0]) + )) { + Display(TEXT("AnsitoUnicode conversion failed")); + + } + + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "The recommended function GeTickCount64 is available only on Windows Vista/Server 2008 and above") + Display(TEXT("Reply %d from %ws: bytes=%d time<%dms TTL=%d"), + ntohs(pIcmpHeader->i_id), + unicodeIpAddr, + datalen, + (GetTickCount()-ntohl(pIcmpHeader->timestamp)), + pIpHeader->ttl); + + deviceInfo->NumberOfRequestSent++; + deviceInfo->Sleep = TRUE; + + } + + } + +End: + PostNextRead(pRCB); + SetEvent(deviceInfo->PingEvent); + +} +VOID +ReadComplete( + DWORD dwError, + DWORD dwBytesTransferred, + LPOVERLAPPED pOvl + ) +{ + if (ERROR_OPERATION_ABORTED != dwError) + { + RCB* pRCB = (RCB *)pOvl; + DisplayV(TEXT("ReadComplete: %d"), dwBytesTransferred); + ProcessReadBuffer(pRCB, dwBytesTransferred); + } +} + +VOID +PostNextRead( + RCB *pRCB + ) +{ + + if(!ReadFileEx(pRCB->DeviceInfo->hDevice, pRCB->Buffer, sizeof(pRCB->Buffer), + &pRCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) ReadComplete)) + { + Display(TEXT("Error in ReadFile: %x"), GetLastError()); + } + +} + + +BOOLEAN +Ping( + PDEVICE_INFO DeviceInfo + ) +{ + HANDLE hDevice = DeviceInfo->hDevice; + char *icmpbuf; + char *ipHeader; + char *etherHeader; + unsigned int icmpbuflen, packetlen; + PTCB pTCB = NULL; + + packetlen = sizeof(IcmpHeader) + sizeof(IpHeader) + sizeof(ETH_HEADER); + + // Add in the data size + if(FAILED(UIntAdd(packetlen, DeviceInfo->PacketSize, &packetlen))) { + Display(TEXT("Ping: UIntAdd Failed")); + goto Error; + } + + pTCB = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TCB)); + if(!pTCB){ + Display(TEXT("Ping: HeapAlloc Failed")); + goto Error; + } + + pTCB->Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, packetlen); + if(!pTCB->Buffer){ + Display(TEXT("Ping: HeapAlloc Failed")); + goto Error; + } + + pTCB->BufferLength = packetlen; + memset(&pTCB->Overlapped, 0, sizeof(OVERLAPPED)); + + + // Allocate the buffer that will contain the ICMP request + etherHeader = pTCB->Buffer; + + ipHeader = etherHeader + sizeof(ETH_HEADER); + + icmpbuf = ipHeader + sizeof(IpHeader); + + + icmpbuflen = sizeof(IcmpHeader) + DeviceInfo->PacketSize; + + InitEtherHeader(DeviceInfo, (PETH_HEADER)etherHeader); + + + InitIcmpHeader(icmpbuf, icmpbuflen, DeviceInfo->PacketSize); + + // Set the sequence number and compute the checksum + SetIcmpSequence(icmpbuf, sizeof(IcmpHeader)); + + DisplayV(TEXT("Icmp header %d packetlen %d"), sizeof(IcmpHeader), icmpbuflen); + + ComputeIcmpChecksum(icmpbuf, sizeof(IcmpHeader), icmpbuflen); + + if(!InitIpHeader(DeviceInfo, (IpHeader *)ipHeader, (USHORT)icmpbuflen+sizeof(IpHeader))){ + goto Error; + } + + ComputeIPChecksum((IpHeader *)ipHeader); + + PrintIpHeader((IpHeader *)ipHeader); + + if(!WriteFileEx(hDevice, etherHeader, packetlen, &pTCB->Overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) WriteComplete)) + { + Display(TEXT("Ping: WriteFile failed %x"), GetLastError()); + goto Error; + } + + return TRUE; + +Error: + + if(pTCB) { + if(pTCB->Buffer){ + HeapFree (GetProcessHeap(), 0, pTCB->Buffer); + } + HeapFree (GetProcessHeap(), 0, pTCB); + } + return FALSE; +} + +DWORD +PingThread ( + PDEVICE_INFO DeviceInfo + ) +{ + RCB RCB; + HANDLE hDevice = DeviceInfo->hDevice; + DWORD status; + + + Display(TEXT("Pinging %ws from %ws with %d bytes of data"), + DeviceInfo->UnicodeDestIp, + DeviceInfo->UnicodeSourceIp, + DeviceInfo->PacketSize); + Sleep(1000); + + // + // Every time a ping response is recevied, PingEvent will + // be signalled. + // + DeviceInfo->PingEvent = CreateEvent(NULL, FALSE, FALSE, L"PingEvent"); + if (DeviceInfo->PingEvent == NULL) { + Display(TEXT("CreateEvent failed 0x%x"), GetLastError()); + goto Exit; + } + + DeviceInfo->NumberOfRequestSent = 0; + DeviceInfo->Sleep = FALSE; + DeviceInfo->TimeOut = 0; + PacketId = 1; + + // + // Get the MAC address of the local NIC + // + if (!GetSrcMac(hDevice, DeviceInfo->SrcMacAddr)) + { + Display(TEXT("Failed to obtain local MAC address")); + goto Exit; + } + + // + // Set the hardware filter to receive directed on broadcast packets. + // + if (!SetPacketFilter(hDevice, NDIS_PACKET_TYPE_DIRECTED|NDIS_PACKET_TYPE_BROADCAST)) + { + Display(TEXT("Failed to set packet filter")); + goto Exit; + } + + // + // Initialize read control block. Reads requests are serialized. + // Only one read is outstanding at any time. We allocate memory + // for the RCB in the stack. + // + RCB.DeviceInfo = DeviceInfo; + memset(&RCB.Overlapped, 0, sizeof(OVERLAPPED)); + + + // + // Get MAC address of the target machine by sending an ARP + // request. We have the target machine's IP address from the user. + // + if(!GetTargetMac(DeviceInfo, &RCB)){ + Display(TEXT("Couldn't find the host")); + goto Exit; + } + + // + // Set the hardware filter to receive directed packets only + // + if (!SetPacketFilter(hDevice, NDIS_PACKET_TYPE_DIRECTED)) + { + Display(TEXT("Failed to set packet filter")); + goto Exit; + } + + // + // Post a read buffer and start sending ping packets. + // + PostNextRead(&RCB); + + Ping(DeviceInfo); + + // + // We will exit out of this thread if the number of ping count + // exceeds the DEFAULT_SEND_COUNT or the main thread requested + // us to exit by setting ExitThread value to TRUE. + // + while(DeviceInfo->NumberOfRequestSent < DEFAULT_SEND_COUNT + && DeviceInfo->ExitThread == FALSE){ + + status = WaitForSingleObjectEx(DeviceInfo->PingEvent, 1000, TRUE ); + if ( status == WAIT_OBJECT_0 ) { // event fired, not timeout + // + // Probably we received a valid ping response from the target. + // + if(DeviceInfo->Sleep){ + Sleep(PING_SLEEP_TIME); // sleep for a sec before sending another ECHO + } + Ping(DeviceInfo); + continue; + } + // + // This is just a notification that either Read/Write operation got + // completed. We will know the result of the acutal operation later + // when the APC is called. + // + if( status == WAIT_IO_COMPLETION ) { + continue; + } + if (status != WAIT_TIMEOUT){ + + Display(TEXT("WaitForSingleObjectEx returned error %d"), status); + break; + } + // + // It seems like the wait timed out. So let us send another ping + // and see if we get any response. + // + DeviceInfo->TimeOut++; + if(DeviceInfo->TimeOut > MAX_PING_RETRY) { + Display(TEXT("No response from the target")); + break; + } + + Ping(DeviceInfo); + } + +Exit: + + CloseHandle(DeviceInfo->hDevice); + DeviceInfo->hDevice = INVALID_HANDLE_VALUE; + DeviceInfo->ThreadHandle = NULL; + if (DeviceInfo->PingEvent) { + CloseHandle(DeviceInfo->PingEvent); + DeviceInfo->PingEvent = NULL; + } + + Display(TEXT("PingThread is exiting")); + return 0; +} + + + + + diff --git a/general/pcidrv/test/myping.vcxproj b/general/pcidrv/test/myping.vcxproj new file mode 100644 index 00000000..182ebe8c --- /dev/null +++ b/general/pcidrv/test/myping.vcxproj @@ -0,0 +1,201 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{AAB2FA59-187D-45F7-A84F-09C7089848B3}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{E28A6724-75F7-4959-8204-0A5787BBF7B9}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>myping</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>myping</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>myping</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>myping</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies> + <BaseAddress>0x01000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies> + <BaseAddress>0x01000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies> + <BaseAddress>0x01000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\kmdf;..\kmdf\hw</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;wsock32.lib;ws2_32.lib;ole32.lib</AdditionalDependencies> + <BaseAddress>0x01000000</BaseAddress> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="myping.c" /> + <ClCompile Include="testapp.c" /> + <ResourceCompile Include="testapp.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/pcidrv/test/myping.vcxproj.Filters b/general/pcidrv/test/myping.vcxproj.Filters new file mode 100644 index 00000000..32295c73 --- /dev/null +++ b/general/pcidrv/test/myping.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>{B8B1F2DC-5ED4-4A1F-BFEE-587F0F5312D5}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{8259798A-8FE0-4AE5-B848-77626974747D}</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>{48C95CA9-FD65-42C9-8FAF-C20DEB7390E8}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="myping.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="testapp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="testapp.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/pcidrv/test/resource.h b/general/pcidrv/test/resource.h new file mode 100644 index 00000000..96cfe365 --- /dev/null +++ b/general/pcidrv/test/resource.h @@ -0,0 +1,17 @@ +#define ID_EDIT 1 + +#define IDM_PING 100 +#define IDM_CLOSE 101 +#define IDM_EXIT 102 +#define IDM_CLEAR 103 +#define IDM_ENUMERATE 104 +#define IDM_VERBOSE 105 + +#define IDD_DIALOG 115 +#define ID_OK 118 +#define ID_CANCEL 119 +#define IDC_DEVICE_INDEX 1000 +#define IDC_SOURCE_IP 1001 +#define IDC_DESTINATION_IP 1002 +#define IDC_PACKET_SIZE 1003 +#define IDC_STATIC -1 diff --git a/general/pcidrv/test/testapp.c b/general/pcidrv/test/testapp.c new file mode 100644 index 00000000..cd83f633 --- /dev/null +++ b/general/pcidrv/test/testapp.c @@ -0,0 +1,1224 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: Testapp.c + + +Abstract: + + Testapp for PCIDRV + +Environment: + + User mode only. + +--*/ + +#include "testapp.h" + + +// +// Global variables +// +HINSTANCE HWndInstance; +HWND HWndList; // handle to the embedded list box +TCHAR WindowTitle[]=TEXT("MyPing - Test Application for PCIDRV"); +LIST_ENTRY ListHead; +HDEVNOTIFY InterfaceNotificationHandle; +TCHAR OutText[500]; +UINT ListBoxIndex = 0; +GUID InterfaceGuid;// = GUID_DEVINTERFACE_PCIDRV; +ULONG DeviceIndex; +BOOLEAN Verbose = FALSE; + + +VOID +Display( + _In_ LPWSTR pstrFormat, // @parm A printf style format string + ... // @parm | ... | Variable paramters based on <p pstrFormat> + ) +{ + HRESULT hr; + va_list va; + + va_start(va, pstrFormat); + // + // Truncation is acceptable. + // + hr = StringCbVPrintf(OutText, sizeof(OutText)-sizeof(WCHAR), pstrFormat, va); + va_end(va); + + if(FAILED(hr)){ + return; + } + + SendMessage(HWndList, LB_INSERTSTRING, ListBoxIndex, (LPARAM)OutText); + SendMessage(HWndList, LB_SETCURSEL, ListBoxIndex, 0); + ListBoxIndex++; + +} + +_Use_decl_annotations_ +int +PASCAL +WinMain ( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nShowCmd + ) +{ + static TCHAR szAppName[]=TEXT("MYPING"); + HWND hWnd; + MSG msg; + WNDCLASS wndclass; + + InterfaceGuid = GUID_DEVINTERFACE_PCIDRV; + HWndInstance=hInstance; + + if (!hPrevInstance) + { + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground= GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = TEXT("GenericMenu"); + wndclass.lpszClassName= szAppName; + + RegisterClass(&wndclass); + } + + hWnd = CreateWindow (szAppName, + WindowTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + hInstance, + NULL); + + ShowWindow (hWnd, nShowCmd); + UpdateWindow(hWnd); + + while (GetMessage (&msg, NULL, 0,0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (0); +} + + +LRESULT FAR PASCAL +WndProc (HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + DWORD nEventType = (DWORD)wParam; + PDEV_BROADCAST_HDR p = (PDEV_BROADCAST_HDR) lParam; + DEV_BROADCAST_DEVICEINTERFACE filter; + WSADATA wsd; + + switch (message) + { + + case WM_COMMAND: + HandleCommands(hWnd, message, wParam, lParam); + return 0; + + case WM_CREATE: + + // Load Winsock + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) + { + MessageBox(hWnd, TEXT("WSAStartup failed"), TEXT("Error"), MB_OK); + exit(0); + } + + HWndList = CreateWindow (TEXT("listbox"), + NULL, + WS_CHILD|WS_VISIBLE|LBS_NOTIFY | + WS_VSCROLL | WS_BORDER, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + hWnd, + (HMENU)ID_EDIT, + HWndInstance, + NULL); + + filter.dbcc_size = sizeof(filter); + filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + filter.dbcc_classguid = InterfaceGuid; + InterfaceNotificationHandle = RegisterDeviceNotification(hWnd, &filter, 0); + + InitializeListHead(&ListHead); + EnumExistingDevices(hWnd); + + return 0; + + case WM_SIZE: + + MoveWindow(HWndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); + return 0; + + case WM_SETFOCUS: + SetFocus(HWndList); + return 0; + + case WM_DEVICECHANGE: + + // + // The DBT_DEVNODES_CHANGED broadcast message is sent + // everytime a device is added or removed. This message + // is typically handled by Device Manager kind of apps, + // which uses it to refresh window whenever something changes. + // The lParam is always NULL in this case. + // + if(DBT_DEVNODES_CHANGED == wParam) { + DisplayV(TEXT("Received DBT_DEVNODES_CHANGED broadcast message")); + return 0; + } + + // + // All the events we're interested in come with lParam pointing to + // a structure headed by a DEV_BROADCAST_HDR. This is denoted by + // bit 15 of wParam being set, and bit 14 being clear. + // + if((wParam & 0xC000) == 0x8000) { + + if (!p) + return 0; + + if (p->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { + + HandleDeviceInterfaceChange(hWnd, nEventType, (PDEV_BROADCAST_DEVICEINTERFACE) p); + } else if (p->dbch_devicetype == DBT_DEVTYP_HANDLE) { + + HandleDeviceChange(hWnd, nEventType, (PDEV_BROADCAST_HANDLE) p); + } + } + return 0; + + case WM_POWERBROADCAST: + HandlePowerBroadcast(hWnd, wParam, lParam); + return 0; + + case WM_CLOSE: + Cleanup(hWnd); + UnregisterDeviceNotification(InterfaceNotificationHandle); + return DefWindowProc(hWnd,message, wParam, lParam); + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + return DefWindowProc(hWnd,message, wParam, lParam); + } + + +LRESULT +HandleCommands( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) + +{ + PDIALOG_RESULT result = NULL; + PDEVICE_INFO deviceInfo = NULL; + + switch (wParam) { + + case IDM_CLOSE: + Cleanup(hWnd); + Display(TEXT("Handle to the device closed")); + EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_GRAYED); + EnableMenuItem(GetMenu(hWnd), IDM_CLOSE, MF_BYCOMMAND|MF_GRAYED); + break; + + case IDM_ENUMERATE: + // + // First cleanup everything, and then reenumerate all the devices. + Cleanup(hWnd); + EnumExistingDevices(hWnd); + EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_ENABLED); + break; + + case IDM_PING: + + result = (PDIALOG_RESULT)DialogBox(HWndInstance, MAKEINTRESOURCE(IDD_DIALOG), hWnd, DlgProc); + if(result) { + deviceInfo = FindDeviceInfo(result); + if(!deviceInfo){ + MessageBox(hWnd, TEXT("FindDeviceInfo failed"), TEXT("Error"), MB_OK); + break; + } + + if(!OpenDevice(hWnd, deviceInfo)){ + MessageBox(hWnd, TEXT("OpenDevice failed"), TEXT("Error"), MB_OK); + break; + } + + if (!CreatePingThread(deviceInfo)) { + MessageBox(hWnd, TEXT("CreatePingThread failed"), TEXT("Error"), MB_OK); + break; + } + + EnableMenuItem(GetMenu(hWnd), IDM_PING, MF_BYCOMMAND|MF_GRAYED); + EnableMenuItem(GetMenu(hWnd), IDM_CLOSE, MF_BYCOMMAND|MF_ENABLED); + + } + break; + + case IDM_CLEAR: + SendMessage(HWndList, LB_RESETCONTENT, 0, 0); + ListBoxIndex = 0; + break; + + case IDM_VERBOSE: { + + HMENU hMenu = GetMenu(hWnd); + Verbose = !Verbose; + if(Verbose) { + CheckMenuItem(hMenu, (UINT)wParam, MF_CHECKED); + } else { + CheckMenuItem(hMenu, (UINT)wParam, MF_UNCHECKED); + } + } + break; + + case IDM_EXIT: + Cleanup(hWnd); + PostQuitMessage(0); + break; + + default: + break; + } + + if(result) { + HeapFree (GetProcessHeap(), 0, result); + } + return TRUE; +} + +INT_PTR CALLBACK +DlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + BOOL success; + PDIALOG_RESULT dialogResult = NULL; + ULONG value; + WCHAR SourceIP[80]; + WCHAR DestinationIP[80]; + DWORD SourceIPLen = sizeof(SourceIP); + + switch(message) + { + case WM_INITDIALOG: + // + // Set default values. + // + if(GetRegistryInfo(SourceIP, &SourceIPLen, DestinationIP, &SourceIPLen)) { + SetDlgItemText(hDlg, IDC_SOURCE_IP, SourceIP); + SetDlgItemText(hDlg, IDC_DESTINATION_IP, DestinationIP); + } else { + SetDlgItemText(hDlg, IDC_SOURCE_IP, DEF_SOURCE_IP); + SetDlgItemText(hDlg, IDC_DESTINATION_IP, DEF_DEST_IP); + + } + + SetDlgItemInt(hDlg, IDC_PACKET_SIZE, MAX_PAYLOAD_SIZE, FALSE); + return TRUE; + + case WM_COMMAND: + switch( wParam) + { + case ID_OK: + // + // Allocate memory to store the input values. + // + dialogResult = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(DIALOG_RESULT)); + if(dialogResult) { + + dialogResult->DeviceIndex = GetDlgItemInt(hDlg, + IDC_DEVICE_INDEX, &success, FALSE ); + if(!success){ + break; + } + value = GetDlgItemText(hDlg, IDC_SOURCE_IP, + dialogResult->SourceIp, MAX_LEN-1 ); + if(!value){ + break; + } + + + GetDlgItemText(hDlg, IDC_DESTINATION_IP, + dialogResult->DestIp, MAX_LEN-1 ); + if(!value){ + break; + } + + value = GetDlgItemInt(hDlg,IDC_PACKET_SIZE, &success, FALSE ); + if(success){ + value = min(value, MAX_PAYLOAD_SIZE); + value = max(value, MIN_PAYLOAD_SIZE); + + } else { + value = MIN_PAYLOAD_SIZE; + } + + dialogResult->PacketSize = value; + + SetRegistryInfo(dialogResult->SourceIp, + sizeof(dialogResult->SourceIp), + dialogResult->DestIp, + sizeof(dialogResult->DestIp)); + + } + EndDialog(hDlg, (UINT_PTR)dialogResult); + return TRUE; + case ID_CANCEL: + EndDialog(hDlg, 0); + return TRUE; + + } + break; + + } + return FALSE; +} + + +BOOL +HandleDeviceInterfaceChange( + HWND hWnd, + DWORD evtype, + PDEV_BROADCAST_DEVICEINTERFACE dip + ) +{ + switch (evtype) + { + case DBT_DEVICEARRIVAL: + // + // New device arrived. Create a devicinfo structure and record + // information about the device. + // + Display(TEXT("New device Arrived (Interface Change Notification)")); + + if(!CreateDeviceInfo(dip->dbcc_name)) { + return FALSE; + } + + break; + + case DBT_DEVICEREMOVECOMPLETE: + // + // Device Removed. + // + Display(TEXT("Remove Complete (Interface Change Notification)"), NULL); + break; + + default: + DisplayV(TEXT("Unknown (Interface Change Notification)"), NULL); + break; + } + return TRUE; +} + +BOOL +HandleDeviceChange( + HWND hWnd, + DWORD evtype, + PDEV_BROADCAST_HANDLE dhp + ) +{ + PDEVICE_INFO deviceInfo = NULL; + PLIST_ENTRY thisEntry; + + // + // Walk the list to get the deviceInfo for this device + // by matching the notification handle saved in our deviceInfo + // and the one provided as part of the message. + // + for(thisEntry = ListHead.Flink; thisEntry != &ListHead; + thisEntry = thisEntry->Flink) + { + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + if(dhp->dbch_hdevnotify == deviceInfo->hHandleNotification) { + break; + } + deviceInfo = NULL; + } + + if(!deviceInfo) { + Display(TEXT("Error: spurious message Event Type %x, Device Type %x"), + evtype, dhp->dbch_devicetype); + return FALSE; + } + + switch (evtype) + { + + case DBT_DEVICEQUERYREMOVE: + + Display(TEXT("Query Remove (Handle Notification): %ws"), + deviceInfo->DeviceName); + // User is trying to disable, uninstall, or eject our device. + // Terminate the ping thread and close the handle + // to the device so that the target device can + // get removed. Do not unregister the notification + // at this point, because we want to know whether + // the device is successfully removed or not. + // + TerminatePingThread(deviceInfo); + break; + + case DBT_DEVICEREMOVECOMPLETE: + + Display(TEXT("Remove Complete (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Device is getting surprise removed. So terminate the + // ping thread to close the handle to device and + // unregister the PNP notification. + // + TerminatePingThread(deviceInfo); + + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + } + + // + // Unlink this deviceInfo from the list and free the memory + // + RemoveEntryList(&deviceInfo->ListEntry); + HeapFree (GetProcessHeap(), 0, deviceInfo); + + break; + + case DBT_DEVICEREMOVEPENDING: + + Display(TEXT("Remove Pending (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Device is successfully removed so unregister the notification + // and free the memory. + // + FreeDeviceInfo(deviceInfo); + + break; + + case DBT_DEVICEQUERYREMOVEFAILED : + Display(TEXT("Remove failed (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Remove failed. So reopen the device and register for + // notification on the new handle. But first we should unregister + // the previous notification. + // + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + } + + if(!OpenDevice(hWnd, deviceInfo)) { + Display(TEXT("Failed to reopen the device: %ws"), + deviceInfo->DeviceName); + FreeDeviceInfo(deviceInfo); + break; + } + + Display(TEXT("Reopened device %ws"), deviceInfo->DeviceName); + // + // Restart the ping operation. + // + if(CreatePingThread(deviceInfo)){ + FreeDeviceInfo(deviceInfo); + break; + } + + break; + + default: + Display(TEXT("Unknown (Handle Notification)")); + break; + + } + return TRUE; +} + + +BOOLEAN +EnumExistingDevices( + HWND hWnd +) +{ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0, i; + DWORD error; + PDEVICE_INFO deviceInfo =NULL; + + DisplayV(TEXT("Entered EnumExistingDevices")); + + // + // Make sure the list is empty + // + if(!IsListEmpty(&ListHead) ){ + MessageBox(hWnd, TEXT("ListHead should be empty"), TEXT("Error!"), MB_OK); + return FALSE; + } + + DeviceIndex = 0; + + hardwareDeviceInfo = SetupDiGetClassDevs ( + (LPGUID)&InterfaceGuid, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + goto Error; + } + + // + // Enumerate devices of a specific interface class + // + deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); + + for(i=0; SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID)&InterfaceGuid, + i, // + &deviceInterfaceData); i++ ) { + + // + // Allocate a function class device data structure to + // receive the information about this particular device. + // + + // + // First find out required length of the buffer + // + if (deviceInterfaceDetailData) { + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + } + + if(!SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + goto Error; + } + predictedLength = requiredLength; + + deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + predictedLength); + if (deviceInterfaceDetailData == NULL) { + goto Error; + } + + deviceInterfaceDetailData->cbSize = + sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + + + if (! SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + goto Error; + } + + deviceInfo = CreateDeviceInfo(deviceInterfaceDetailData->DevicePath); + + if(!deviceInfo) + goto Error; + + + } + + if(deviceInterfaceDetailData) { + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + } + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return 0; + +Error: + + error = GetLastError(); + MessageBox(hWnd, TEXT("EnumExisting Devices failed"), TEXT("Error!"), MB_OK); + if(deviceInterfaceDetailData) + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + Cleanup(hWnd); + return 0; +} + +PDEVICE_INFO +FindDeviceInfo( + PDIALOG_RESULT InputInfo + ) +{ + PLIST_ENTRY thisEntry, listHead; + PDEVICE_INFO deviceInfo = NULL, result = NULL; + + listHead = &ListHead; + + for(thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = thisEntry->Flink){ + + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + + if(deviceInfo->DeviceIndex == InputInfo->DeviceIndex){ + + if(deviceInfo->IsANetworkMiniport){ + Display(TEXT("You can't use this app on a device installed as a network device")); + break; + } + + if(deviceInfo->hDevice && + deviceInfo->hDevice != INVALID_HANDLE_VALUE){ + Display(TEXT("%ws device is already in use"), + deviceInfo->DeviceName); + break; + } + + + deviceInfo->DeviceIndex = InputInfo->DeviceIndex; + deviceInfo->PacketSize = InputInfo->PacketSize; + memcpy(deviceInfo->UnicodeSourceIp, InputInfo->SourceIp, MAX_LEN); + memcpy(deviceInfo->UnicodeDestIp, InputInfo->DestIp, MAX_LEN); + // + // Convert the unicode source and destination IP string + // to ANSI and store it. + // + WideCharToMultiByte(CP_ACP, //ANSI code page + 0, deviceInfo->UnicodeSourceIp, -1, + deviceInfo->SourceIp, MAX_LEN, NULL, NULL); + + // + // Convert Unicode string to ANSI. + // + WideCharToMultiByte(CP_ACP, 0, deviceInfo->UnicodeDestIp, -1, + deviceInfo->DestIp, MAX_LEN, NULL, NULL); + + + result = deviceInfo; + break; + } + + } + + return result; + +} + +PDEVICE_INFO +CreateDeviceInfo( + _In_ LPWSTR DevicePath + ) +{ + PDEVICE_INFO deviceInfo = NULL; + HRESULT hr; + + DisplayV(TEXT("Entered CreateDeviceInfo")); + + deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO)); + if(!deviceInfo) { + goto Error; + } + + + if(!GetDeviceDescription(DevicePath, + deviceInfo->DeviceName, + sizeof(deviceInfo->DeviceName), + &deviceInfo->IsANetworkMiniport + )) { + Display(TEXT("GetDeviceDescription failed %x"), GetLastError()); + goto Error; + } + + + // + // Copy the device path so that we can open the device using CreateFile. + // + hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, DevicePath); + if(FAILED(hr)){ + goto Error; + } + + DeviceIndex++; + deviceInfo->DeviceIndex = DeviceIndex; + + // + // Link this to the global list of devices. + // + InitializeListHead(&deviceInfo->ListEntry); + InsertTailList(&ListHead, &deviceInfo->ListEntry); + + Display(TEXT("Device %d is %ws"), DeviceIndex, deviceInfo->DeviceName); + + return deviceInfo; + +Error: + + if(deviceInfo) { + HeapFree (GetProcessHeap(), 0, deviceInfo); + } + return NULL; + +} + +VOID +FreeDeviceInfo( + _In_ PDEVICE_INFO DeviceInfo + ) +{ + DisplayV(TEXT("Entered FreeDeviceInfo")); + + if (DeviceInfo->hHandleNotification) { + UnregisterDeviceNotification(DeviceInfo->hHandleNotification); + DeviceInfo->hHandleNotification = NULL; + } + if (DeviceInfo->hDevice != INVALID_HANDLE_VALUE && + DeviceInfo->hDevice != NULL) { + CloseHandle(DeviceInfo->hDevice); + DeviceInfo->hDevice = INVALID_HANDLE_VALUE; + Display(TEXT("Closed handle to device %ws"), DeviceInfo->DeviceName ); + } + + RemoveEntryList(&DeviceInfo->ListEntry); + + HeapFree (GetProcessHeap(), 0, DeviceInfo); + + return; +} + +BOOL +SetRegistryInfo( + _In_reads_bytes_(SourceIPLen) LPWSTR SourceIP, + _In_ DWORD SourceIPLen, + _In_reads_bytes_(DestinationIPLen) LPWSTR DestinationIP, + _In_ DWORD DestinationIPLen + ) +{ + HKEY hKey; + BOOL ret = FALSE; + size_t srcStrLen, destStrLen; + + if (FAILED(StringCbLengthW(SourceIP, SourceIPLen, &srcStrLen))) { + return ret; + } + + if (FAILED(StringCbLengthW(DestinationIP, DestinationIPLen, &destStrLen))) { + return ret; + } + + // + // RegSetValueEx takes a DWORD, in the rare case that size_t is larger than + // a DWORD return an error. + // + if (srcStrLen > (DWORD_MAX - sizeof(WCHAR))|| + destStrLen > (DWORD_MAX - sizeof(WCHAR))) { + return ret; + } + + if (RegOpenKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) { + + if (ERROR_SUCCESS != RegCreateKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) { + Display(TEXT("RegCreateKey failed: %x"), GetLastError()); + return ret; + } + } + + if (ERROR_SUCCESS == RegSetValueEx(hKey, L"SourceIP", 0, REG_SZ, + (LPBYTE)SourceIP, (DWORD) srcStrLen+sizeof(WCHAR))) { + + if (ERROR_SUCCESS == RegSetValueEx(hKey, L"DestinationIP", 0, REG_SZ, + (LPBYTE)DestinationIP, (DWORD) destStrLen+sizeof(WCHAR))) { + ret = TRUE; + } + } + + RegCloseKey(hKey); + return ret; +} + +_Success_(return) +BOOL +GetRegistryInfo( + _Out_writes_bytes_(* SourceIPLen) PWSTR SourceIP, + _Inout_ LPDWORD SourceIPLen, + _Out_writes_bytes_(* DestinationIPLen) PWSTR DestinationIP, + _Inout_ LPDWORD DestinationIPLen + ) +{ + HKEY hKey; + DWORD dwType = REG_SZ; + BOOL ret = FALSE; + + if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REG_PATH, &hKey)) { + + if(ERROR_SUCCESS == RegQueryValueEx(hKey, L"SourceIP", NULL, &dwType, + (LPBYTE)SourceIP, SourceIPLen)){ + + if(ERROR_SUCCESS == RegQueryValueEx(hKey, L"DestinationIP", NULL, &dwType, + (LPBYTE)DestinationIP, DestinationIPLen)){ + + ret = TRUE; + } + + } + RegCloseKey(hKey); + } + + return ret; +} + + + +BOOLEAN +OpenDevice( + _In_ HWND HWnd, + _In_ PDEVICE_INFO DeviceInfo + ) +{ + DEV_BROADCAST_HANDLE filter; + HANDLE hDevice; + + DisplayV(TEXT("Entered OpenDevice")); + + // + // Open an handle to the device. + // + hDevice = CreateFile ( + DeviceInfo->DevicePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + FILE_FLAG_OVERLAPPED, + NULL); + + if (INVALID_HANDLE_VALUE == hDevice) { + Display(TEXT("Failed to open the device: %ws"), + DeviceInfo->DeviceName); + return FALSE; + } + + Display(TEXT("Opened handled to the device: %ws"), + DeviceInfo->DeviceName); + // + // Register handle based notification to receive pnp + // device change notification on the handle. + // + + memset (&filter, 0, sizeof(filter)); //zero the structure + filter.dbch_size = sizeof(filter); + filter.dbch_devicetype = DBT_DEVTYP_HANDLE; + filter.dbch_handle = hDevice; + + DeviceInfo->hHandleNotification = RegisterDeviceNotification(HWnd, &filter, 0); + if(!DeviceInfo->hHandleNotification){ + Display(TEXT("Failed to register notification: %ws"), + DeviceInfo->DeviceName); + CloseHandle(hDevice); + return FALSE; + } + + DeviceInfo->hDevice = hDevice; + + return TRUE; + +} + + +BOOL +CreatePingThread( + PDEVICE_INFO DeviceInfo + ) +{ + ULONG id; + + DisplayV(TEXT("CreatePingThread")); + + DeviceInfo->ExitThread = FALSE; + + // + // Start the ping operation in a separate thread. + // + DeviceInfo->ThreadHandle = CreateThread( NULL, // security attributes + 0, // initial stack size + (LPTHREAD_START_ROUTINE) PingThread, // Main() function + DeviceInfo, // arg to Reader thread + 0, // creation flags + (LPDWORD)&id); // returned thread id + + if ( NULL == DeviceInfo->ThreadHandle) { + Display(TEXT("CreateThread failed %x"), GetLastError()); + return FALSE; + } + + return TRUE; +} + +VOID +TerminatePingThread( + PDEVICE_INFO DeviceInfo + ) +{ + DWORD status; + + DisplayV(TEXT("TerminatePingThread")); + + if(DeviceInfo->ThreadHandle){ + + DeviceInfo->ExitThread = TRUE; + // + // Wait for the thread to exit + // + status = WaitForSingleObjectEx(DeviceInfo->ThreadHandle, 1000, TRUE ); + if(status == WAIT_FAILED){ + Display(TEXT("Wait failed %x"), GetLastError()); + } + CloseHandle(DeviceInfo->ThreadHandle); + DeviceInfo->ThreadHandle = NULL; + } + +} + +BOOLEAN +Cleanup( + HWND hWnd + ) +/*++ + + This routine walks the global list of currently enumerated devices + and close all handles and frees the memory. + --*/ +{ + PDEVICE_INFO deviceInfo =NULL; + PLIST_ENTRY thisEntry; + + DisplayV(TEXT("Entered Cleanup")); + + while (!IsListEmpty(&ListHead)) { + thisEntry = ListHead.Flink; + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + // + // First let us make sure the PingThread is not running. + // + TerminatePingThread(deviceInfo); + FreeDeviceInfo(deviceInfo); + } + return TRUE; +} + + +_Success_(return != FALSE) +BOOL +GetDeviceDescription( + _In_ LPTSTR DevPath, + _Out_writes_bytes_all_(OutBufferLen) LPTSTR OutBuffer, + _In_ ULONG OutBufferLen, + BOOL *NetClassDevice +) +{ + HDEVINFO hardwareDeviceInfo = NULL; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + SP_DEVINFO_DATA deviceInfoData; + DWORD dwRegType, error; + TCHAR classGuidString[MAX_GUID_STRING_LEN]; + HRESULT hr; + GUID classGuid; + BOOL ret = FALSE; + + DisplayV(TEXT("GetDeviceDescription")); + + hardwareDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL); + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + Display(TEXT("Couldn't create DeviceInfoList: %x"), GetLastError()); + goto Error; + } + + // + // Enumerate devices of toaster class + // + deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); + + SetupDiOpenDeviceInterface (hardwareDeviceInfo, DevPath, + 0, // + &deviceInterfaceData); + + deviceInfoData.cbSize = sizeof(deviceInfoData); + if(!SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + NULL, + &deviceInfoData) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + Display(TEXT("Couldn't get interface detail: %x"), GetLastError()); + goto Error; + } + // + // Get the friendly name for this instance, if that fails + // try to get the device description. + // + + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, + SPDRP_FRIENDLYNAME, + &dwRegType, + (BYTE*) OutBuffer, + OutBufferLen, + NULL)) + { + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, + SPDRP_DEVICEDESC, + &dwRegType, + (BYTE*) OutBuffer, + OutBufferLen, + NULL)){ + Display(TEXT("Couldn't get friendlyname: %x"), GetLastError()); + goto Error; + + } + + + } + + // + // Get the class guid of the device and find out whether this is a + // network miniport. + // + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, + &deviceInfoData, + SPDRP_CLASSGUID, + &dwRegType, + (BYTE*) classGuidString, + sizeof(classGuidString), + NULL)) { + Display(TEXT("Class guid is not available for device: %ws"), OutBuffer ); + } + + hr = CLSIDFromString(classGuidString, &classGuid); + if(FAILED(hr)) { + goto Error; + } + + if(IsEqualGUID(&classGuid, &GUID_DEVCLASS_NET)){ + *NetClassDevice = TRUE; + } else { + *NetClassDevice = FALSE; + } + + ret = TRUE; + +Error: + + if(hardwareDeviceInfo) { + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + } + return ret; +} + + +BOOL +HandlePowerBroadcast( + HWND hWnd, + WPARAM wParam, + LPARAM lParam) +{ + BOOL fRet = TRUE; + + switch (wParam) + { + case PBT_APMQUERYSTANDBY: + DisplayV(TEXT("PBT_APMQUERYSTANDBY")); + break; + case PBT_APMQUERYSUSPEND: + DisplayV(TEXT("PBT_APMQUERYSUSPEND")); + break; + case PBT_APMSTANDBY : + DisplayV(TEXT("PBT_APMSTANDBY")); + break; + case PBT_APMSUSPEND : + DisplayV(TEXT("PBT_APMSUSPEND")); + break; + case PBT_APMQUERYSTANDBYFAILED: + DisplayV(TEXT("PBT_APMQUERYSTANDBYFAILED")); + break; + case PBT_APMRESUMESTANDBY: + DisplayV(TEXT("PBT_APMRESUMESTANDBY")); + break; + case PBT_APMQUERYSUSPENDFAILED: + DisplayV(TEXT("PBT_APMQUERYSUSPENDFAILED")); + break; + case PBT_APMRESUMESUSPEND: + DisplayV(TEXT("PBT_APMRESUMESUSPEND")); + break; + case PBT_APMBATTERYLOW: + DisplayV(TEXT("PBT_APMBATTERYLOW")); + break; + case PBT_APMOEMEVENT: + DisplayV(TEXT("PBT_APMOEMEVENT")); + break; + case PBT_APMRESUMEAUTOMATIC: + DisplayV(TEXT("PBT_APMRESUMEAUTOMATIC")); + break; + case PBT_APMRESUMECRITICAL: + DisplayV(TEXT("PBT_APMRESUMECRITICAL")); + break; + case PBT_APMPOWERSTATUSCHANGE: + DisplayV(TEXT("PBT_APMPOWERSTATUSCHANGE")); + break; + default: + DisplayV(TEXT("Default")); + break; + } + return fRet; +} + + diff --git a/general/pcidrv/test/testapp.h b/general/pcidrv/test/testapp.h new file mode 100644 index 00000000..3a75e4f5 --- /dev/null +++ b/general/pcidrv/test/testapp.h @@ -0,0 +1,260 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + notify.h + +Abstract: + +--*/ + +#ifndef __TESTAPP_H +#define __TESTAPP_H + +#pragma warning(disable:4214 4201 4115 4100) + +#define UNICODE 1 +#define INITGUID + +#include <windows.h> // for using Windows data types and functions +#include <winsock2.h> // for using winsock utility inet_addr/ntohs functions. +#include <setupapi.h> // for using SetupDi functions +#include <dbt.h> // for PNP device notification interfaces +#include <winioctl.h> // for defining ioctls +#include <ntddndis.h> // for NDIS OIDs +#include <strsafe.h> // for safe string functions +#include <devguid.h> // for GUID_DEVCLASS_NET +#include <cfgmgr32.h> // for MAX_GUID_STRING_LEN +#include <OBJBASE.H> // for CLSIDFromString. Link to ole32.lib + +#include "public.h" +#include "resource.h" +#include <dontuse.h> + +// +// Registry path where the IP addresses are saved +// +#define REG_PATH L"Software\\Microsoft\\PCIDRV\\MyPing" +#define DEF_SOURCE_IP L"192.168.0.2" +#define DEF_DEST_IP L"192.168.0.1" + +#define PING_SLEEP_TIME 100 +#define MAC_ADDR_LEN 6 + +#define MAX_LEN 64 +#define MAX_PAYLOAD_SIZE 1428 +#define MIN_PAYLOAD_SIZE 32 +#define MAX_PING_RETRY 10 + +extern BOOLEAN Verbose; + +typedef struct _DEVICE_INFO +{ + LIST_ENTRY ListEntry; + HANDLE hDevice; // file handle + HDEVNOTIFY hHandleNotification; // notification handle + TCHAR DeviceName[MAX_PATH];// friendly name of device description + TCHAR DevicePath[MAX_PATH];// + ULONG DeviceIndex; // Serial number of the device. + CHAR SourceIp[MAX_LEN]; + CHAR DestIp[MAX_LEN]; + WCHAR UnicodeSourceIp[MAX_LEN]; + WCHAR UnicodeDestIp[MAX_LEN]; + ULONG PacketSize; + UCHAR SrcMacAddr[MAC_ADDR_LEN]; + UCHAR TargetMacAddr[MAC_ADDR_LEN]; + HANDLE PingEvent; + ULONG NumberOfRequestSent; + BOOL Sleep; + ULONG TimeOut; + BOOL IsANetworkMiniport; + BOOLEAN ExitThread; + HANDLE ThreadHandle; + +} DEVICE_INFO, *PDEVICE_INFO; + + +typedef struct _DIALOG_RESULT +{ + ULONG DeviceIndex; + WCHAR SourceIp[MAX_LEN]; + WCHAR DestIp[MAX_LEN]; + ULONG PacketSize; +} DIALOG_RESULT, *PDIALOG_RESULT; + + +// +// Copied Macros from ntddk.h. Used to using the kernel-mode +// style of linked list. +// + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (PCHAR)(address) - \ + (ULONG_PTR)(&((type *)0)->field))) + + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + + +#ifndef min +#define min(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) +#endif + +#ifndef max +#define max(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) +#endif + +#define DisplayV(pstrFormat, ...) if (Verbose) {Display(pstrFormat, __VA_ARGS__);} + +LRESULT FAR PASCAL +WndProc ( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ); + +BOOLEAN EnumExistingDevices( + HWND hWnd + ); + +BOOL HandleDeviceInterfaceChange( + HWND hwnd, + DWORD evtype, + PDEV_BROADCAST_DEVICEINTERFACE dip + ); + +BOOL HandleDeviceChange( + HWND hwnd, + DWORD evtype, + PDEV_BROADCAST_HANDLE dhp + ); + +LRESULT +HandleCommands( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ); + +BOOL +HandlePowerBroadcast( + HWND hWnd, + WPARAM wParam, + LPARAM lParam); + +BOOLEAN Cleanup( + HWND hWnd + ); + +_Success_(return != FALSE) +BOOL +GetDeviceDescription( + _In_ LPTSTR DevPath, + _Out_writes_bytes_all_(OutBufferLen) LPTSTR OutBuffer, + _In_ ULONG OutBufferLen, + BOOL *NetClassDevice +); + +BOOLEAN +OpenDevice( + _In_ HWND HWnd, + _In_ PDEVICE_INFO DeviceInfo + ); + + +INT_PTR CALLBACK +DlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam); + +DWORD +PingThread ( + PDEVICE_INFO DeviceInfo + ); + +VOID Display( + _In_ LPWSTR pstrFormat, + ... + ) ; + + +BOOL +CreatePingThread( + PDEVICE_INFO DeviceInfo + ); + +PDEVICE_INFO +FindDeviceInfo( + PDIALOG_RESULT InputInfo + ); + +VOID +FreeDeviceInfo( + _In_ PDEVICE_INFO DeviceInfo + ); + +PDEVICE_INFO +CreateDeviceInfo( + _In_ LPWSTR DevicePath + ); + +VOID +TerminatePingThread( + PDEVICE_INFO DeviceInfo + ); + +_Success_(return) +BOOL +GetRegistryInfo( + _Out_writes_bytes_(* SourceIPLen) PWSTR SourceIP, + _Inout_ LPDWORD SourceIPLen, + _Out_writes_bytes_(* DestinationIPLen) PWSTR DestinationIP, + _Inout_ LPDWORD DestinationIPLen + ); + +BOOL +SetRegistryInfo( + _In_reads_bytes_(SourceIPLen) LPWSTR SourceIP, + _In_ DWORD SourceIPLen, + _In_reads_bytes_(DestinationIPLen) LPWSTR DestinationIP, + _In_ DWORD DestinationIPLen + ); + + +#endif + + diff --git a/general/pcidrv/test/testapp.rc b/general/pcidrv/test/testapp.rc new file mode 100644 index 00000000..dcef4be0 --- /dev/null +++ b/general/pcidrv/test/testapp.rc @@ -0,0 +1,37 @@ +#include <windows.h> +#include "resource.h" + +GenericMenu MENU + { + POPUP "&Menu" + { + MENUITEM "&Start Ping", IDM_PING + MENUITEM "&Stop", IDM_CLOSE + MENUITEM "&Re-enumerate All Devices" IDM_ENUMERATE + MENUITEM "Clear &Display", IDM_CLEAR + MENUITEM "Verbose", IDM_VERBOSE + MENUITEM "E&xit", IDM_EXIT + } + } + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG DIALOG DISCARDABLE 0, 0, 291, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Ping" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",ID_OK,71,96,50,14,BS_NOTIFY + PUSHBUTTON "CANCEL",ID_CANCEL,167,96,50,14,BS_NOTIFY + LTEXT "Device Index :",IDC_STATIC,19,13,55,8 + LTEXT "Source IP :",IDC_STATIC,19,35,55,8 + EDITTEXT IDC_DEVICE_INDEX,75,11,24,14,ES_NUMBER + EDITTEXT IDC_SOURCE_IP,76,32,103,14,ES_AUTOHSCROLL + LTEXT "Destination IP :",IDC_STATIC,18,55,55,8 + EDITTEXT IDC_DESTINATION_IP,75,53,101,14,ES_AUTOHSCROLL + LTEXT "Packet Size",IDC_STATIC,18,77,55,8 + EDITTEXT IDC_PACKET_SIZE,75,75,24,14,ES_NUMBER +END diff --git a/general/perfcounters/kcs/ReadMe.md b/general/perfcounters/kcs/ReadMe.md new file mode 100644 index 00000000..4f28894c --- /dev/null +++ b/general/perfcounters/kcs/ReadMe.md @@ -0,0 +1,15 @@ +Kernel Counter Sample (Kcs) +=========================== + +The Kcs sample driver demonstrates the use of the [kernel-mode performance library](http://msdn.microsoft.com/en-us/library/windows/hardware/ff548159). The sample driver does not control any hardware; it simply provides example code that demonstrates how to provide counter data from a kernel-mode driver. The code contains comments to explain what each function does. The sample creates geometric wave and trigonometric wave counter sets. + +This module contains sample code to demonstrate how to provide counter data from a kernel driver. + +This sample driver should not be used in a production environment. + +Kcs is designed for Windows 7 and later versions of Windows. + +The Microsoft Windows operating system allows system components and third parties to expose performance metrics in a standard way by using [Performance Counters](http://msdn.microsoft.com/en-us/library/windows/hardware/aa373083). Kernel-mode PCW providers are installed in the system as Performance Counter Library (PERFLIB) (Version 2 providers), which allows their counters to be browsed, and allows for data collection and instance enumeration. Consumers can query KM PCW providers by using PDH and PERFLIB Version 1 without any modification to the consumer code. + + + diff --git a/general/perfcounters/kcs/kcs.c b/general/perfcounters/kcs/kcs.c new file mode 100644 index 00000000..ae4405b9 --- /dev/null +++ b/general/perfcounters/kcs/kcs.c @@ -0,0 +1,407 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + kcs.c + +Abstract: + + This module contains sample code to demonstrate how to provide + counter data from a kernel driver. + +Environment: + + Kernel mode only. + +--*/ + + +#include <wdm.h> +#include "kcs.h" +#include "kcsCounters.h" + +#pragma code_seg("PAGE") + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD KcsUnload; + +NTSTATUS +KcsAddGeometricInstance ( + _In_ PPCW_BUFFER Buffer, + _In_ PCWSTR Name, + _In_ ULONG MinimalValue, + _In_ ULONG Amplitude + ) + +/*++ + +Routine Description: + + This utility function adds instance to the callback buffer. + +Arguments: + + Buffer - Data will be returned in this buffer. + + Name - Name of instances to be added. + + MinimalValue - Minimum value of the wave. + + Amplitude - Amplitude of the wave. + +Return Value: + + NTSTATUS indicating if the function succeeded. + +--*/ + +{ + ULONG Index; + LARGE_INTEGER Timestamp; + UNICODE_STRING UnicodeName; + GEOMETRIC_WAVE_VALUES Values; + + PAGED_CODE(); + + KeQuerySystemTime(&Timestamp); + + Index = (Timestamp.QuadPart / 10000000) % 10; + + Values.Triangle = MinimalValue + Amplitude * abs(5 - Index) / 5; + Values.Square = MinimalValue + Amplitude * (Index < 5); + + RtlInitUnicodeString(&UnicodeName, Name); + + return KcsAddGeometricWave(Buffer, &UnicodeName, 0, &Values); +} + +NTSTATUS NTAPI +KcsGeometricWaveCallback ( + _In_ PCW_CALLBACK_TYPE Type, + _In_ PPCW_CALLBACK_INFORMATION Info, + _In_opt_ PVOID Context + ) + +/*++ + +Routine Description: + + This function returns the list of counter instances and counter data. + +Arguments: + + Type - Request type. + + Info - Buffer for returned data. + + Context - Not used. + +Return Value: + + NTSTATUS indicating if the function succeeded. + +--*/ + +{ + NTSTATUS Status; + UNICODE_STRING UnicodeName; + + UNREFERENCED_PARAMETER(Context); + + PAGED_CODE(); + + switch (Type) { + case PcwCallbackEnumerateInstances: + + // + // Instances are being enumerated, so we add them without values. + // + + RtlInitUnicodeString(&UnicodeName, L"Small Wave"); + Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, + &UnicodeName, + 0, + NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + + RtlInitUnicodeString(&UnicodeName, L"Medium Wave"); + Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, + &UnicodeName, + 0, + NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + + RtlInitUnicodeString(&UnicodeName, L"Large Wave"); + Status = KcsAddGeometricWave(Info->EnumerateInstances.Buffer, + &UnicodeName, + 0, + NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + + break; + + case PcwCallbackCollectData: + + // + // Add values for 3 instances of Geometric Wave Counter Set. + // + + Status = KcsAddGeometricInstance(Info->CollectData.Buffer, + L"Small Wave", + 40, + 20); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Status = KcsAddGeometricInstance(Info->CollectData.Buffer, + L"Medium Wave", + 30, + 40); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Status = KcsAddGeometricInstance(Info->CollectData.Buffer, + L"Large Wave", + 20, + 60); + if (!NT_SUCCESS(Status)) { + return Status; + } + + break; + } + + return STATUS_SUCCESS; +} + +NTSTATUS +KcsAddTrignometricInstance ( + _In_ PPCW_BUFFER Buffer, + _In_ PCWSTR Name, + _In_ ULONG MinimalValue, + _In_ ULONG Amplitude + ) + +/*++ + +Routine Description: + + This utility function adds instance to the callback buffer. + +Arguments: + + Buffer - Data will be returned in this buffer. + + Name - Name of instances to be added. + + MinimalValue - Minimum value of the wave. + + Amplitude - Amplitude of the wave. + +Return Value: + + NTSTATUS indicating if the function succeeded. + +--*/ + +{ + double Angle; + KFLOATING_SAVE FloatSave; + NTSTATUS Status; + LARGE_INTEGER Timestamp; + UNICODE_STRING UnicodeName; + TRIGNOMETRIC_WAVE_VALUES Values; + + PAGED_CODE(); + + Status = KeSaveFloatingPointState(&FloatSave); + if (!NT_SUCCESS(Status)) { + return Status; + } + + KeQuerySystemTime(&Timestamp); + + Angle = (double)(Timestamp.QuadPart / 400000) * (22/7) / 180; + + Values.Constant = MinimalValue; + Values.Cosine = (ULONG)(MinimalValue + Amplitude * cos(Angle)); + Values.Sine = (ULONG)(MinimalValue + Amplitude * sin(Angle)); + + KeRestoreFloatingPointState(&FloatSave); + + // + // Add instance name & values to the caller's buffer. + // + + RtlInitUnicodeString(&UnicodeName, Name); + + return KcsAddTrignometricWave(Buffer, &UnicodeName, 0, &Values); +} + +NTSTATUS NTAPI +KcsTrignometricWaveCallback ( + _In_ PCW_CALLBACK_TYPE Type, + _In_ PPCW_CALLBACK_INFORMATION Info, + _In_opt_ PVOID Context + ) + +/*++ + +Routine Description: + + This function returns the list of counter instances and counter data. + +Arguments: + + Type - Request type. + + Info - Buffer for returned data. + + Context - Not used. + +Return Value: + + NTSTATUS indicating if the function succeeded. + +--*/ + +{ + NTSTATUS Status; + UNICODE_STRING UnicodeName; + + UNREFERENCED_PARAMETER(Context); + + PAGED_CODE(); + + switch (Type) { + case PcwCallbackEnumerateInstances: + RtlInitUnicodeString(&UnicodeName, L"default"); + Status = KcsAddTrignometricWave(Info->EnumerateInstances.Buffer, + &UnicodeName, + 0, + NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + + break; + + case PcwCallbackCollectData: + + // + // Add values for Single Instance of Trignometirc Wave Counter Set. + // + + return KcsAddTrignometricInstance(Info->CollectData.Buffer, + L"default", + 50, + 30); + } + + return STATUS_SUCCESS; +} + +VOID +KcsUnload ( + _In_ PDRIVER_OBJECT DriverObject + ) + +/*++ + +Routine Description: + + This function unregisters countersets + +Arguments: + + DriverObject - Not used. + +Return Value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(DriverObject); + + PAGED_CODE(); + + // + // Unregister Countersets. + // + + KcsUnregisterGeometricWave(); + KcsUnregisterTrignometricWave(); +} + +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + This function registers countersets on initial loading of the driver. + +Arguments: + + DriverObject - Supplies the driver object of the driver being loaded. + + RegistryPath - Not used. + +Return Value: + + NTSTATUS indicating if driver was properly loaded. + +--*/ + +{ + NTSTATUS Status; + + UNREFERENCED_PARAMETER(RegistryPath); + + PAGED_CODE(); + + // + // Register Countersets. + // + + Status = KcsRegisterGeometricWave(KcsGeometricWaveCallback, NULL); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Status = KcsRegisterTrignometricWave(KcsTrignometricWaveCallback, NULL); + if (!NT_SUCCESS(Status)) { + KcsUnregisterTrignometricWave(); + return Status; + } + + // + // Success path - set up unload routine and return success. + // + + DriverObject->DriverUnload = KcsUnload; + + return STATUS_SUCCESS; +} + diff --git a/general/perfcounters/kcs/kcs.h b/general/perfcounters/kcs/kcs.h new file mode 100644 index 00000000..4d845cc3 --- /dev/null +++ b/general/perfcounters/kcs/kcs.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + kcs.h + +Abstract: + + This module contains sample code to demonstrate how to provide + counter data from a kernel driver. + +Environment: + + Kernel mode only. + +--*/ + +typedef struct _GEOMETRIC_WAVE_VALUES { + ULONG Square; + ULONG Triangle; +} GEOMETRIC_WAVE_VALUES, *PGEOMETRIC_WAVE_VALUES; + +typedef struct _TRIGNOMETRIC_WAVE_VALUES { + ULONG Constant; + ULONG Cosine; + ULONG Sine; +} TRIGNOMETRIC_WAVE_VALUES, *PTRIGNOMETRIC_WAVE_VALUES;
\ No newline at end of file diff --git a/general/perfcounters/kcs/kcs.man b/general/perfcounters/kcs/kcs.man new file mode 100644 index 00000000..a5a16ffb --- /dev/null +++ b/general/perfcounters/kcs/kcs.man @@ -0,0 +1,101 @@ +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" + > + <instrumentation> + <counters + xmlns="http://schemas.microsoft.com/win/2005/12/counters" + xmlns:auto-ns1="http://schemas.microsoft.com/win/2004/08/events" + schemaVersion="1.1" + > + <provider callback = "custom" + applicationIdentity = "Kcs.sys" + providerType = "kernelMode" + providerName = "KernelCountersSample" + providerGuid = "{d2ffffff-965a-4cf9-9c07-fe25378c2a23}"> + <counterSet guid = "{d2ffffff-c923-4794-b696-70577630b5cf}" + uri = "Microsoft.Wdk.Samples.Kcs.GeometricWave" + name = "Geometric Waves" + description = "This counter set displays a Triangle and a Square wave" + symbol = "GeometricWave" + instances = "multipleAggregate" + > + <structs> + <struct name="GeometricWaveValues" type="GEOMETRIC_WAVE_VALUES"/> + </structs> + <counter id = "1" + uri = "Microsoft.Wdk.Samples.Kcs.GeometricWave.Triangle" + name = "Triangle" + struct = "GeometricWaveValues" + field = "Triangle" + description = "This counter displays triangle wave" + aggregate = "avg" + type = "perf_counter_rawcount" + detailLevel = "standard"> + </counter> + + <counter id = "2" + uri = "Microsoft.Wdk.Samples.Kcs.GeometricWave.Square" + name = "Square Wave" + struct = "GeometricWaveValues" + field = "Square" + description = "This counter displays Square Wave" + aggregate = "avg" + type = "perf_counter_rawcount" + detailLevel = "standard"> + </counter> + </counterSet> + <counterSet guid = "{ffffffff-eaa6-45ba-bf6d-4c7cb0d6ef73}" + uri = "Microsoft.Wdk.Samples.Kcs.TrignometricWave" + name = "Trignometric Waves" + description = "This counter set displays a sine, cosine and a constant wave" + symbol = "TrignometricWave" + instances = "single"> + <structs> + <struct name="TrignometricWaveValues" type="TRIGNOMETRIC_WAVE_VALUES"/> + </structs> + <counter id = "1" + uri = "Microsoft.Wdk.Samples.Kcs.TrignometricWave.Sine" + name = "Sine Wave" + description = "This counter displays Sine Wave" + struct = "TrignometricWaveValues" + field = "Sine" + type = "perf_counter_rawcount" + detailLevel = "standard"> + <counterAttributes> + <counterAttribute name = "reference" /> + </counterAttributes> + </counter> + <counter id = "2" + uri = "Microsoft.Wdk.Samples.Kcs.TrignometricWave.Cosine" + name = "Cosine Wave" + description = "This counter displays Cosine Wave" + struct = "TrignometricWaveValues" + field = "Cosine" + type = "perf_counter_rawcount" + detailLevel = "standard"> + <counterAttributes> + <counterAttribute name = "reference" /> + </counterAttributes> + </counter> + <counter id = "3" + uri = "Microsoft.Wdk.Samples.Kcs.TrignometricWave.Constant" + name = "Constant Value" + description = "This counter displays Constant Value" + struct = "TrignometricWaveValues" + field = "Constant" + type = "perf_counter_rawcount" + detailLevel = "standard"> + <counterAttributes> + <counterAttribute name = "reference" /> + </counterAttributes> + </counter> + </counterSet> + </provider> + </counters> + </instrumentation> +</instrumentationManifest>
\ No newline at end of file diff --git a/general/perfcounters/kcs/kcs.rc b/general/perfcounters/kcs/kcs.rc new file mode 100644 index 00000000..7c19d061 --- /dev/null +++ b/general/perfcounters/kcs/kcs.rc @@ -0,0 +1 @@ +#include "kcsCounters.rc" diff --git a/general/perfcounters/kcs/kcs.sln b/general/perfcounters/kcs/kcs.sln new file mode 100644 index 00000000..6630e582 --- /dev/null +++ b/general/perfcounters/kcs/kcs.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kcs", "kcs.vcxproj", "{FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|Win32.ActiveCfg = Debug|Win32 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|Win32.Build.0 = Debug|Win32 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|Win32.ActiveCfg = Release|Win32 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|Win32.Build.0 = Release|Win32 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|x64.ActiveCfg = Debug|x64 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Debug|x64.Build.0 = Debug|x64 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|x64.ActiveCfg = Release|x64 + {FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/perfcounters/kcs/kcs.vcxproj b/general/perfcounters/kcs/kcs.vcxproj new file mode 100644 index 00000000..c58a9026 --- /dev/null +++ b/general/perfcounters/kcs/kcs.vcxproj @@ -0,0 +1,174 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{FA4BC0C3-DA1C-46DA-BFF4-AA448B5D0A0A}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{C44D3FE1-3E60-4619-A1F9-E34A55C6FCA7}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>kcs</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>kcs</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>kcs</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>kcs</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\ntoskrnl.lib;$(DDK_LIB_PATH)\libcntpr.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <Target Name="Run Ctrpp" BeforeTargets="ClCompile"> + <PropertyGroup> + <CTRPP_ODIR>$([System.IO.Path]::GetDirectoryName($(ProjectDir)\$(IntDir)))</CTRPP_ODIR> + </PropertyGroup> + <Exec Command=""$(WDKContentRoot)\bin\x86\ctrpp.exe" kcs.man -prefix Kcs -o "$(CTRPP_ODIR)\KcsCounters.h" -ch "$(CTRPP_ODIR)\KcsCounters_counters.h" -rc "$(CTRPP_ODIR)\KcsCounters.rc"" WorkingDirectory="$(MSBuildProjectDirectory)" /> + </Target> + <ItemGroup> + <ClCompile Include="Kcs.c" /> + <ResourceCompile Include="Kcs.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/perfcounters/kcs/kcs.vcxproj.Filters b/general/perfcounters/kcs/kcs.vcxproj.Filters new file mode 100644 index 00000000..fedf64ea --- /dev/null +++ b/general/perfcounters/kcs/kcs.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{1E487FA6-DCB9-4A49-A9B9-3A1C9D75EB43}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{E4CC3C2E-1709-47A1-A48A-1EB157A1251C}</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>{3D42F00B-B811-48EC-BB7A-2D8047551422}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{4AE0C581-1388-4311-8C6C-9087111D70F5}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Kcs.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Kcs.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/registry/regfltr/ReadMe.md b/general/registry/regfltr/ReadMe.md new file mode 100644 index 00000000..731e8ca3 --- /dev/null +++ b/general/registry/regfltr/ReadMe.md @@ -0,0 +1,23 @@ +RegFltr Sample Driver +===================== + +The RegFltr sample shows how to write a [registry filter driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff545879).In addition to providing some basic examples, this sample demonstrates the following: + +- How to handle transactional registry operations. +- How and when to capture input parameters. +- Issues and workarounds for version 1.0 of registry filtering. +- Changes in version 1.1 of registry filtering. +- How to use version 1 of the [**REG\_CREATE\_KEY\_INFORMATION**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560920) and [**REG\_OPEN\_KEY\_INFORMATION**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560957) data structures. + +The RegFltr sample demonstrates the registry filtering system on Windows Vista, Windows Server 2008 and later versions of the Windows operating system. It does not work for Windows XP or Windows Server 2003. + +The RegFltr sample contains several examples of user-mode and kernel-mode registry-filtering operations. Each example comes with its own corresponding registry callback routine, and performs the following steps: + +1. Does some setup work. +2. Registers the callback routine. +3. Performs one or more registry operations. +4. Unregisters the callback routine. +5. Verifies that the sample completed correctly. + +The sample driver is a minimal driver that is not intended to be used on production systems. To keep the samples simple, the registry callback routines provided do not check for all possible situations and error conditions. This sample is designed to demonstrate typical scenarios and no other registry filtering driver is expected to be active. + diff --git a/general/registry/regfltr/exe/capture.c b/general/registry/regfltr/exe/capture.c new file mode 100644 index 00000000..aaef2555 --- /dev/null +++ b/general/registry/regfltr/exe/capture.c @@ -0,0 +1,151 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Capture.c + +Abstract: + + A sample that shows how to capture input parameters + +Environment: + + User mode only + +--*/ + +#include "regctrl.h" + + +VOID +CaptureSample( + ) +/*++ + +Routine Description: + + This sample shows how to capture input parameters when the registery + operation comes from user mode. + + The main part of this sample and a detailed explanation of why and how to + capture user mode parameters can be found in ..\sys\capture.c. The user + mode part of this sample simply calls RegSetValueEx and DeleteValue + since the REG_XXX_INFORMATION structure for these two operations are + only partially captured. + + See ..\sys\Capture.c for the callback routine used in this sample. + +Return Value: + + None + +--*/ +{ + LONG Res; + HRESULT hr; + DWORD ValueData = 0xDEADBEEF; + BOOL Result; + BOOL Success = FALSE; + DWORD BytesReturned; + REGISTER_CALLBACK_INPUT RegisterCallbackInput = {0}; + REGISTER_CALLBACK_OUTPUT RegisterCallbackOutput = {0}; + UNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput = {0}; + + + InfoPrint(""); + InfoPrint("=== Capture Sample ===="); + + // + // Register callback + // + + RtlZeroMemory(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR)); + + hr = StringCbPrintf(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + CALLBACK_ALTITUDE); + + if (!SUCCEEDED(hr)) { + ErrorPrint("Copying altitude string failed. Error %d", hr); + goto Exit; + } + + RegisterCallbackInput.CallbackMode = CALLBACK_MODE_CAPTURE; + + Result = DeviceIoControl(g_Driver, + IOCTL_REGISTER_CALLBACK, + &RegisterCallbackInput, + sizeof(REGISTER_CALLBACK_INPUT), + &RegisterCallbackOutput, + sizeof(REGISTER_CALLBACK_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("RegisterCallback failed. Error %d", GetLastError()); + goto Exit; + } + + Success = TRUE; + + // + // Create a value and delete it. Both should be successful. + // + + Res = RegSetValueEx(g_RootKey, + VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_SUCCESS) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + Res = RegDeleteValue(g_RootKey, VALUE_NAME); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegDeleteValue on original value returned unexpected status: %d", + Res); + Success = FALSE; + } + + // + // Unregister the callback + // + + UnRegisterCallbackInput.Cookie = RegisterCallbackOutput.Cookie; + + Result = DeviceIoControl(g_Driver, + IOCTL_UNREGISTER_CALLBACK, + &UnRegisterCallbackInput, + sizeof(UNREGISTER_CALLBACK_INPUT), + NULL, + 0, + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("UnRegisterCallback failed. Error %d", GetLastError()); + Success = FALSE; + } + + Exit: + + if (Success) { + InfoPrint("Capture Sample succeeded."); + } else { + ErrorPrint("Capture Sample failed."); + } + +} + diff --git a/general/registry/regfltr/exe/common.h b/general/registry/regfltr/exe/common.h new file mode 100644 index 00000000..7b2ca958 --- /dev/null +++ b/general/registry/regfltr/exe/common.h @@ -0,0 +1,168 @@ +/*++
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ Common.h
+
+Abstract:
+
+ Definitions common to both the driver and the executable.
+
+Environment:
+
+ User and kernel mode
+
+--*/
+
+#pragma once
+
+//
+// Driver and device names.
+//
+
+#define DRIVER_NAME L"RegFltr"
+#define DRIVER_NAME_WITH_EXT L"RegFltr.sys"
+
+#define NT_DEVICE_NAME L"\\Device\\RegFltr"
+#define DOS_DEVICES_LINK_NAME L"\\DosDevices\\RegFltr"
+#define WIN32_DEVICE_NAME L"\\\\.\\RegFltr"
+
+//
+// SDDL string used when creating the device. This string
+// limits access to this driver to system and admins only.
+//
+
+#define DEVICE_SDDL L"D:P(A;;GA;;;SY)(A;;GA;;;BA)"
+
+//
+// IOCTLs exposed by the driver.
+//
+
+#define IOCTL_DO_KERNELMODE_SAMPLES CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 0), METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
+#define IOCTL_REGISTER_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 1), METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
+#define IOCTL_UNREGISTER_CALLBACK CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 2), METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
+#define IOCTL_GET_CALLBACK_VERSION CTL_CODE (FILE_DEVICE_UNKNOWN, (0x800 + 3), METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
+
+//
+// Common definitions
+//
+
+#define ROOT_KEY_ABS_PATH L"\\REGISTRY\\MACHINE\\Software\\_RegFltrRoot"
+#define ROOT_KEY_REL_PATH L"Software\\_RegFltrRoot"
+#define KEY_NAME L"_RegFltrKey"
+#define MODIFIED_KEY_NAME L"_RegFltrModifiedKey"
+#define NOT_MODIFIED_KEY_NAME L"_RegFltrNotModifiedKey"
+#define VALUE_NAME L"_RegFltrValue"
+#define MODIFIED_VALUE_NAME L"_RegFltrModifiedValue"
+#define NOT_MODIFIED_VALUE_NAME L"_RegFltrNotModifiedValue
"
+
+#define CALLBACK_LOW_ALTITUDE L"380000"
+#define CALLBACK_ALTITUDE L"380010"
+#define CALLBACK_HIGH_ALTITUDE L"380020"
+
+#define MAX_ALTITUDE_BUFFER_LENGTH 10
+
+//
+// List of callback modes
+//
+typedef enum _CALLBACK_MODE {
+ CALLBACK_MODE_PRE_NOTIFICATION_BLOCK,
+ CALLBACK_MODE_PRE_NOTIFICATION_BYPASS,
+ CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_ERROR,
+ CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_SUCCESS,
+ CALLBACK_MODE_TRANSACTION_REPLAY,
+ CALLBACK_MODE_TRANSACTION_ENLIST,
+ CALLBACK_MODE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE,
+ CALLBACK_MODE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION,
+ CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR,
+ CALLBACK_MODE_SET_CALL_CONTEXT,
+ CALLBACK_MODE_SET_OBJECT_CONTEXT,
+ CALLBACK_MODE_CAPTURE,
+ CALLBACK_MODE_VERSION_BUGCHECK,
+ CALLBACK_MODE_VERSION_CREATE_OPEN_V1,
+} CALLBACK_MODE;
+
+
+//
+// List of kernel mode samples
+//
+typedef enum _KERNELMODE_SAMPLE {
+ KERNELMODE_SAMPLE_PRE_NOTIFICATION_BLOCK = 0,
+ KERNELMODE_SAMPLE_PRE_NOTIFICATION_BYPASS,
+ KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_ERROR,
+ KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_SUCCESS,
+ KERNELMODE_SAMPLE_TRANSACTION_REPLAY,
+ KERNELMODE_SAMPLE_TRANSACTION_ENLIST,
+ KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE,
+ KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION,
+ KERNELMODE_SAMPLE_SET_CALL_CONTEXT,
+ KERNELMODE_SAMPLE_SET_OBJECT_CONTEXT,
+ KERNELMODE_SAMPLE_VERSION_CREATE_OPEN_V1,
+ MAX_KERNELMODE_SAMPLES
+} KERNELMODE_SAMPLE;
+
+
+//
+// Input and output data structures for the various driver IOCTLs
+//
+
+typedef struct _REGISTER_CALLBACK_INPUT {
+
+ //
+ // specifies the callback mode for the callback context
+ //
+ CALLBACK_MODE CallbackMode;
+
+ //
+ // specifies the altitude to register the callback at
+ //
+ WCHAR Altitude[MAX_ALTITUDE_BUFFER_LENGTH];
+
+} REGISTER_CALLBACK_INPUT, *PREGISTER_CALLBACK_INPUT;
+
+typedef struct _REGISTER_CALLBACK_OUTPUT {
+
+ //
+ // receives the cookie value from registering the callback
+ //
+ LARGE_INTEGER Cookie;
+
+} REGISTER_CALLBACK_OUTPUT, *PREGISTER_CALLBACK_OUTPUT;
+
+
+typedef struct _UNREGISTER_CALLBACK_INPUT {
+ //
+ // specifies the cookie value for the callback
+ //
+ LARGE_INTEGER Cookie;
+
+} UNREGISTER_CALLBACK_INPUT, *PUNREGISTER_CALLBACK_INPUT;
+
+
+typedef struct _GET_CALLBACK_VERSION_OUTPUT {
+
+ //
+ // Receives the version number of the registry callback
+ //
+ ULONG MajorVersion;
+ ULONG MinorVersion;
+
+} GET_CALLBACK_VERSION_OUTPUT, *PGET_CALLBACK_VERSION_OUTPUT;
+
+
+typedef struct _DO_KERNELMODE_SAMPLES_OUTPUT {
+
+ //
+ // An array that receives the results of the kernel mode samples.
+ //
+ BOOLEAN SampleResults[MAX_KERNELMODE_SAMPLES];
+
+} DO_KERNELMODE_SAMPLES_OUTPUT, *PDO_KERNELMODE_SAMPLES_OUTPUT;
+
+
diff --git a/general/registry/regfltr/exe/post.c b/general/registry/regfltr/exe/post.c new file mode 100644 index 00000000..d10a7a22 --- /dev/null +++ b/general/registry/regfltr/exe/post.c @@ -0,0 +1,366 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Post.c + +Abstract: + + Samples that show what callbacks can do during the post-notification + phase. + +Environment: + + User mode only + +--*/ + + +#include "regctrl.h" + +/*++ + + In registry callback version 1.0, there is a bug with post-notification + processing and multiple registry filter drivers that can break the samples + here. It is fixed with version 1.1. + + The bug occurs when a driver blocks or bypasses a registry operation in the + pre-notification phase. Even though the processing of the operation stops + there, registry filter drivers registered at higher altitudes will still + get a post-notification for the operation. If the higher altitude driver + tries to change the status of the operation from failure to success or + vice versa, this change will be ignored and the status returned + will be the status returned by the driver who bypassed or blocked the + operation during the pre-notification phase. + + For more information on how notification processing works with multiple + registry filter drivers registered see ..\sys\MultiAlt.c + + For more information on issues in version 1.0 and changes in version 1.1 + see ..\sys\Version.c + + Beginning with Windows 8.1, it is no longer possible to pass the object + provided to a RegNtPostCreateKeyEx or RegNtPostOpenKeyEx callout to + ObOpenObjectByPointer. To work around this, filters should perform all + create key or open key processing in a RegNtPreCreateKeyEx or + RegNtPreOpenKeyEx callout. If for any reason the desired processing cannot + be performed in a RegNtPreCreateKeyEx or RegNtPreOpenKeyEx callout, then + use CmSetCallbackObjectContext to tag a newly-created or newly-opened key + as unprocessed and process it in the pre-operation callback for a + subsequent operation. + +--*/ + + +VOID +PostNotificationOverrideSuccessSample( + ) +/*++ + +Routine Description: + + This sample shows how registry callbacks can fail a registry operation + in the post-notification phase. + + Two values are created. The creates normally should succeeded, but one + is intercepted by the callback and failed with ERROR_ACCESS_DENIED. + + See ..\sys\Post.c for the callback routine used in this sample. + +--*/ +{ + LONG Res; + HRESULT hr; + BOOL Result; + BOOL Success = FALSE; + DWORD BytesReturned; + DWORD ValueData = 0xDEADBEEF; + REGISTER_CALLBACK_INPUT RegisterCallbackInput = {0}; + REGISTER_CALLBACK_OUTPUT RegisterCallbackOutput = {0}; + UNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput = {0}; + + + InfoPrint(""); + InfoPrint("=== Post-Notification Override Success Sample ===="); + + // + // Register a callback with the specified callback mode and altitude. + // + + RtlZeroMemory(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR)); + + hr = StringCbPrintf(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + CALLBACK_ALTITUDE); + + if (!SUCCEEDED(hr)) { + ErrorPrint("Copying altitude string failed. Error %d", hr); + goto Exit; + } + + RegisterCallbackInput.CallbackMode = CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_SUCCESS; + + Result = DeviceIoControl(g_Driver, + IOCTL_REGISTER_CALLBACK, + &RegisterCallbackInput, + sizeof(REGISTER_CALLBACK_INPUT), + &RegisterCallbackOutput, + sizeof(REGISTER_CALLBACK_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("RegisterCallback failed. Error %d", GetLastError()); + goto Exit; + } + + Success = TRUE; + + // + // Set two values. + // Setting the "not modified" value will succeed. + // Setting the other value will fail with file not found. + // + + Res = RegSetValueEx(g_RootKey, + NOT_MODIFIED_VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_SUCCESS) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + + Res = RegSetValueEx(g_RootKey, + VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_ACCESS_DENIED) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + // + // Unregister the callback + // + + UnRegisterCallbackInput.Cookie = RegisterCallbackOutput.Cookie; + + Result = DeviceIoControl(g_Driver, + IOCTL_UNREGISTER_CALLBACK, + &UnRegisterCallbackInput, + sizeof(UNREGISTER_CALLBACK_INPUT), + NULL, + 0, + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("UnRegisterCallback failed. Error %d", GetLastError()); + Success = FALSE; + } + + + // + // Verify that the set value call was failed by + // checking that the value with VALUE_NAME does not + // exist. + // + + Res = RegDeleteValue(g_RootKey, VALUE_NAME); + + if (Res != ERROR_FILE_NOT_FOUND) { + ErrorPrint("RegDeleteValue on value returned unexpected status: %d", + Res); + Success = FALSE; + } + + Exit: + + RegDeleteValue(g_RootKey, VALUE_NAME); + RegDeleteValue(g_RootKey, NOT_MODIFIED_VALUE_NAME); + + if (Success) { + InfoPrint("Post-Notification Override Success Sample succeeded."); + } else { + ErrorPrint("Post-Notification Override Success Sample FAILED."); + } + +} + + +VOID +PostNotificationOverrideErrorSample( + ) +/*++ + +Routine Description: + + This sample shows how a registry callback can change a failed registry + operation into a successful operation in the post-notification phase. + + A key that does not exist is opened. The opens should fail, but it is + intercepted by the callback and the open is redirected to a key that + does exist. + + See ..\sys\Post.c for the callback routine used in this sample. + +Return Value: + + None + +--*/ +{ + + LONG Res; + HRESULT hr; + BOOL Success = FALSE; + BOOL Result; + HKEY Key = NULL; + HKEY ModifiedKey = NULL; + DWORD BytesReturned; + REGISTER_CALLBACK_INPUT RegisterCallbackInput = {0}; + REGISTER_CALLBACK_OUTPUT RegisterCallbackOutput = {0}; + UNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput = {0}; + + InfoPrint(""); + InfoPrint("=== Post-Notification Override Error Sample ===="); + + // + // Create a key with name MODIFIED_KEY_NAME + // + + Res = RegCreateKeyEx(g_RootKey, + MODIFIED_KEY_NAME, + 0, + NULL, + 0, + KEY_ALL_ACCESS, + NULL, + &ModifiedKey, + NULL); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegCreateKeyEx returned unexpected error %d", Res); + goto Exit; + } + + // + // Now try to open a key by KEY_NAME which does not exist. Verify that + // this fails. + // + + Res = RegOpenKeyEx(g_RootKey, + KEY_NAME, + 0, + KEY_ALL_ACCESS, + &Key); + + if (Res != ERROR_FILE_NOT_FOUND) { + ErrorPrint("RegOpenKeyEx returned unexpected error %d", Res); + goto Exit; + } + + // + // Register a callback with the specified callback mode and altitude. + // + + RtlZeroMemory(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR)); + + hr = StringCbPrintf(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + CALLBACK_ALTITUDE); + + if (!SUCCEEDED(hr)) { + ErrorPrint("Copying altitude string failed. Error %d", hr); + goto Exit; + } + + + RegisterCallbackInput.CallbackMode = CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_ERROR; + + Result = DeviceIoControl(g_Driver, + IOCTL_REGISTER_CALLBACK, + &RegisterCallbackInput, + sizeof(REGISTER_CALLBACK_INPUT), + &RegisterCallbackOutput, + sizeof(REGISTER_CALLBACK_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("RegisterCallback failed. Error %d", GetLastError()); + goto Exit; + } + + Success = TRUE; + + // + // Open key again. The callback will intercept this and make it succeed. + // + + Res = RegOpenKeyEx(g_RootKey, + KEY_NAME, + 0, + KEY_ALL_ACCESS, + &Key); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegOpenKeyEx returned unexpected error %d", Res); + Success = FALSE; + } + + // + // Unregister the callback + // + + UnRegisterCallbackInput.Cookie = RegisterCallbackOutput.Cookie; + + Result = DeviceIoControl(g_Driver, + IOCTL_UNREGISTER_CALLBACK, + &UnRegisterCallbackInput, + sizeof(UNREGISTER_CALLBACK_INPUT), + NULL, + 0, + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("UnRegisterCallback failed. Error %d", GetLastError()); + Success = FALSE; + } + + Exit: + + if (Key != NULL) { + RegCloseKey(Key); + } + if (ModifiedKey != NULL) { + RegCloseKey(ModifiedKey); + } + RegDeleteKey(g_RootKey, KEY_NAME); + RegDeleteKey(g_RootKey, MODIFIED_KEY_NAME); + + if (Success) { + InfoPrint("Post-Notification Override Error Sample succeeded."); + } else { + ErrorPrint("Post-Notification Override Error Sample FAILED."); + } + +} + diff --git a/general/registry/regfltr/exe/pre.c b/general/registry/regfltr/exe/pre.c new file mode 100644 index 00000000..14d7e57e --- /dev/null +++ b/general/registry/regfltr/exe/pre.c @@ -0,0 +1,428 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Pre.c + +Abstract: + + Samples that show what callbacks can do during the pre-notification + phase. + +Environment: + + User mode only + +--*/ + + + +#include "regctrl.h" + + +VOID +PreNotificationBlockSample( + ) +/*++ + +Routine Description: + + This sample shows how to block a registry operation in the + pre-notification phase. + + Two keys are created. The create operations should succeed, but one + is intercepted by the callback and failed with ERROR_ACCESS_DENIED. + The same is done for two values. + + See ..\sys\Pre.c for the callback routine used in this sample. + +--*/ +{ + + LONG Res; + HRESULT hr; + HKEY Key = NULL; + HKEY NotModifiedKey = NULL; + DWORD ValueData = 0xDEADBEEF; + DWORD BytesReturned; + BOOL Result; + BOOL Success = FALSE; + REGISTER_CALLBACK_INPUT RegisterCallbackInput = {0}; + REGISTER_CALLBACK_OUTPUT RegisterCallbackOutput = {0}; + UNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput = {0}; + + InfoPrint(""); + InfoPrint("=== Pre-Notification Block Sample ===="); + + // + // Register callback + // + + RtlZeroMemory(RegisterCallbackInput.Altitude, MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR)); + hr = StringCbPrintf(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + CALLBACK_ALTITUDE); + + if (!SUCCEEDED(hr)) { + ErrorPrint("Copying altitude string failed. Error %d", hr); + goto Exit; + } + + RegisterCallbackInput.CallbackMode = CALLBACK_MODE_PRE_NOTIFICATION_BLOCK; + + Result = DeviceIoControl(g_Driver, + IOCTL_REGISTER_CALLBACK, + &RegisterCallbackInput, + sizeof(REGISTER_CALLBACK_INPUT), + &RegisterCallbackOutput, + sizeof(REGISTER_CALLBACK_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("RegisterCallback failed. Error %d", GetLastError()); + goto Exit; + } + + Success = TRUE; + + // + // Create two keys. + // Creating the "not modified" key will succeed. + // Creating the other key will fail with ERROR_ACCESS_DENIED + // + + // + // NOTE: In the kernel debugger output, you will see 3 pre-notifications + // for create key even though we only call create key twice. + // You will also see the message that create key is blocked twice. + // + // Kd output: + // + // RegFltr: Callback: Altitude-380010, NotifyClass-RegNtPreCreateKeyEx. + // RegFltr: Callback: Altitude-380010, NotifyClass-RegNtPostCreateKeyEx. + // RegFltr: Callback: Altitude-380010, NotifyClass-RegNtPreCreateKeyEx. + // RegFltr: Callback: Create key _RegFltrKey blocked. + // RegFltr: Callback: Altitude-380010, NotifyClass-RegNtPreCreateKeyEx. + // RegFltr: Callback: Create key _RegFltrKey blocked. + // + // The reason this happens is that RegCreateKeyEx is more than just a + // wrapper around NtCreateKey. If the call to NtCreateKey fails, + // RegCreateKeyEx will retry the call in slightly different ways + // depending on the error returned. + // + + Res = RegCreateKeyEx(g_RootKey, + NOT_MODIFIED_KEY_NAME, + 0, + L"Regfltr_test_class", + 0, + KEY_ALL_ACCESS, + NULL, + &NotModifiedKey, + NULL); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegCreateKeyEx returned unexpected error %d", Res); + Success = FALSE; + } + + Res = RegCreateKeyEx(g_RootKey, + KEY_NAME, + 0, + L"Regfltr_test_class", + 0, + KEY_ALL_ACCESS, + NULL, + &Key, + NULL); + + if (Res != ERROR_ACCESS_DENIED) { + ErrorPrint("RegCreateKeyEx returned unexpected error %d", Res); + Success = FALSE; + } + + // + // Set two values. + // Setting the "not modified" value will succeed. + // Setting the other value will fail with ERROR_ACCESS_DENIED. + // + + Res = RegSetValueEx(g_RootKey, + NOT_MODIFIED_VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_SUCCESS) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + Res = RegSetValueEx(g_RootKey, + VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_ACCESS_DENIED) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + // + // Unregister the callback + // + + UnRegisterCallbackInput.Cookie = RegisterCallbackOutput.Cookie; + + Result = DeviceIoControl(g_Driver, + IOCTL_UNREGISTER_CALLBACK, + &UnRegisterCallbackInput, + sizeof(UNREGISTER_CALLBACK_INPUT), + NULL, + 0, + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("UnRegisterCallback failed. Error %d", GetLastError()); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + RegCloseKey(Key); + } + RegDeleteKey(g_RootKey, KEY_NAME); + + if (NotModifiedKey != NULL) { + RegCloseKey(NotModifiedKey); + } + RegDeleteKey(g_RootKey, NOT_MODIFIED_KEY_NAME); + + RegDeleteValue(g_RootKey, NOT_MODIFIED_VALUE_NAME); + RegDeleteValue(g_RootKey, VALUE_NAME); + + if (Success) { + InfoPrint("Pre-Notification Block Sample succeeded."); + } else { + ErrorPrint("Pre-Notification Block Sample FAILED."); + } + +} + + +VOID +PreNotificationBypassSample( + ) +/*++ + +Routine Description: + + This sample shows how to bypass a registry operation so that the CM does + not process the operation. Unlike block, an operation that is bypassed + is still considered successful so the callback must provide the caller + with what the CM would have provided. + + A key and a value are created. However both operations are bypassed by the + callback so that the key and value actually created have different names + than would is expected. + + See ..\sys\Pre.c for the callback routine used in this sample. + +Return Value: + + None + +--*/ +{ + LONG Res; + HRESULT hr; + HKEY Key = NULL; + DWORD ValueData = 0xDEADBEEF; + BOOL Result; + BOOL Success = FALSE; + DWORD BytesReturned; + REGISTER_CALLBACK_INPUT RegisterCallbackInput = {0}; + REGISTER_CALLBACK_OUTPUT RegisterCallbackOutput = {0}; + UNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput = {0}; + + + InfoPrint(""); + InfoPrint("=== Pre-Notification Bypass Sample ===="); + + // + // Register callback + // + + RtlZeroMemory(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR)); + + hr = StringCbPrintf(RegisterCallbackInput.Altitude, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + CALLBACK_ALTITUDE); + + if (!SUCCEEDED(hr)) { + ErrorPrint("Copying altitude string failed. Error %d", hr); + goto Exit; + } + + RegisterCallbackInput.CallbackMode = CALLBACK_MODE_PRE_NOTIFICATION_BYPASS; + + Result = DeviceIoControl(g_Driver, + IOCTL_REGISTER_CALLBACK, + &RegisterCallbackInput, + sizeof(REGISTER_CALLBACK_INPUT), + &RegisterCallbackOutput, + sizeof(REGISTER_CALLBACK_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("RegisterCallback failed. Error %d", GetLastError()); + goto Exit; + } + + Success = TRUE; + + // + // Create a key and create a value. Both should succeed. + // + + Res = RegCreateKeyEx(g_RootKey, + KEY_NAME, + 0, + L"Regfltr_test_class", + 0, + KEY_ALL_ACCESS, + NULL, + &Key, + NULL); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegCreateKeyEx returned unexpected error %d", Res); + Success = FALSE; + } + + Res = RegSetValueEx(g_RootKey, + VALUE_NAME, + 0, + REG_DWORD, + (BYTE *) &ValueData, + sizeof(ValueData)); + + if(Res != ERROR_SUCCESS) { + ErrorPrint("RegSetValueEx return unexpected status %d", Res); + Success = FALSE; + } + + // + // Unregister the callback + // + + UnRegisterCallbackInput.Cookie = RegisterCallbackOutput.Cookie; + + Result = DeviceIoControl(g_Driver, + IOCTL_UNREGISTER_CALLBACK, + &UnRegisterCallbackInput, + sizeof(UNREGISTER_CALLBACK_INPUT), + NULL, + 0, + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("UnRegisterCallback failed. Error %d", GetLastError()); + Success = FALSE; + } + + // + // Check that a key with the expected name KEY_NAME cannot be found + // but a key with the "modified" name can be found. + // + + if (Key != NULL) { + RegCloseKey(Key); + } + + Res = RegOpenKeyEx(g_RootKey, + KEY_NAME, + 0, + KEY_ALL_ACCESS, + &Key); + + if (Res != ERROR_FILE_NOT_FOUND) { + ErrorPrint("RegOpenKeyEx returned unexpected error: %d", Res); + if (Key != NULL) { + RegCloseKey(Key); + Key = NULL; + } + Success = FALSE; + } + + Res = RegOpenKeyEx(g_RootKey, + MODIFIED_KEY_NAME, + 0, + KEY_ALL_ACCESS, + &Key); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegOpenKeyEx returned unexpected error: %d", Res); + Success = FALSE; + } + + // + // Do the same check by trying to delete a value with VALUE_NAME and + // with the "modified" name. + // + + Res = RegDeleteValue(g_RootKey, VALUE_NAME); + + if (Res != ERROR_FILE_NOT_FOUND) { + ErrorPrint("RegDeleteValue on original value returned unexpected status: %d", + Res); + Success = FALSE; + } + + Res = RegDeleteValue(g_RootKey, MODIFIED_VALUE_NAME); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("RegDeleteValue on original value returned unexpected status: %d", + Res); + Success = FALSE; + } + + Exit: + + if (Success) { + InfoPrint("Pre-Notification Bypass Sample succeeded."); + } else { + ErrorPrint("Pre-Notification Bypass Sample failed."); + } + + // + // Clean up + // + + if (Key != NULL) { + RegCloseKey(Key); + } + RegDeleteKey(g_RootKey, KEY_NAME); + RegDeleteKey(g_RootKey, MODIFIED_KEY_NAME); + +} + diff --git a/general/registry/regfltr/exe/regctrl.c b/general/registry/regfltr/exe/regctrl.c new file mode 100644 index 00000000..bf486e77 --- /dev/null +++ b/general/registry/regfltr/exe/regctrl.c @@ -0,0 +1,288 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + regctrl.c + +Abstract: + + Invokes the usermode and kernel mode callback samples. + +Environment: + + User mode Win32 console application + +Revision History: + +--*/ + +#include "regctrl.h" + +// +// Global variables +// + +// +// Handle to the driver +// +HANDLE g_Driver; + +// +// Handle to the root test key +// +HKEY g_RootKey; + +// +// Version number for the registry callback +// +ULONG g_MajorVersion; +ULONG g_MinorVersion; + + + +BOOL +GetCallbackVersion(); + +VOID +DoKernelModeSamples(); + +VOID +DoUserModeSamples(); + +LPCWSTR +GetKernelModeSampleName ( + _In_ KERNELMODE_SAMPLE Sample + ); + + +VOID __cdecl +wmain( + _In_ ULONG argc, + _In_reads_(argc) LPCWSTR argv[] + ) +{ + + BOOL Result; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + Result = UtilLoadDriver(DRIVER_NAME, + DRIVER_NAME_WITH_EXT, + WIN32_DEVICE_NAME, + &g_Driver); + + if (Result != TRUE) { + ErrorPrint("UtilLoadDriver failed, exiting..."); + exit(1); + } + + printf("\n"); + printf("Starting Callback samples...\n"); + printf("\n"); + printf("To get more detailed output from the sample, do either one of these steps:\n"); + printf("\n"); + printf("\tA. In kernel debugger: \n"); + printf("\tkd> ed nt!Kd_IHVDRIVER_Mask 0x8\n\n"); + printf("\tB. Run this script and reboot:\n"); + printf("\treg add \"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Debug Print Filter\" /v IHVDRIVER /t REG_DWORD /d 0x8\n\n"); + + // + // Get the registry callback version to determine what samples can + // run on the system. + // + + if (GetCallbackVersion()) { + InfoPrint("Callback version is %u.%u", g_MajorVersion, g_MinorVersion); + } + + DoKernelModeSamples(); + DoUserModeSamples(); + + UtilUnloadDriver(g_Driver, NULL, DRIVER_NAME); + +} + + +BOOL +GetCallbackVersion( + ) +/*++ + +Routine Description: + + This routine asks the driver for the registry callback version and + stores it in the global variables g_MajorVersion and g_MinorVersion. + +--*/ +{ + + DWORD BytesReturned = 0; + BOOL Result; + GET_CALLBACK_VERSION_OUTPUT Output = {0}; + + Result = DeviceIoControl(g_Driver, + IOCTL_GET_CALLBACK_VERSION, + NULL, + 0, + &Output, + sizeof(GET_CALLBACK_VERSION_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("DeviceIoControl for GET_CALLBACK_VERSION failed, error %d\n", GetLastError()); + return FALSE; + } + + g_MajorVersion = Output.MajorVersion; + g_MinorVersion = Output.MinorVersion; + + return TRUE; + +} + +VOID +DoUserModeSamples( + ) +/*++ + +Routine Description: + + Creates the callback root test key and calls the usermode samples. + +--*/ +{ + + LONG Res; + + Res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, + ROOT_KEY_REL_PATH, + 0, + NULL, + 0, + KEY_ALL_ACCESS, + NULL, + &g_RootKey, + NULL); + + if (Res != ERROR_SUCCESS) { + ErrorPrint("Creating root key failed. Error %d", Res); + goto Exit; + } + + PreNotificationBlockSample(); + PreNotificationBypassSample(); + PostNotificationOverrideSuccessSample(); + PostNotificationOverrideErrorSample(); + CaptureSample(); + + Exit: + + if (g_RootKey != NULL) { + RegCloseKey(g_RootKey); + } + RegDeleteKey(HKEY_LOCAL_MACHINE, ROOT_KEY_REL_PATH); + +} + + +VOID +DoKernelModeSamples( + ) +/*++ + +Routine Description: + + Tells the driver to run the kernel mode samples and prints out the + results. + +--*/ +{ + + UINT Index; + DWORD BytesReturned = 0; + BOOL Result; + DO_KERNELMODE_SAMPLES_OUTPUT Output = {0}; + + Result = DeviceIoControl (g_Driver, + IOCTL_DO_KERNELMODE_SAMPLES, + NULL, + 0, + &Output, + sizeof(DO_KERNELMODE_SAMPLES_OUTPUT), + &BytesReturned, + NULL); + + if (Result != TRUE) { + ErrorPrint("DeviceIoControl for DO_KERNELMODE_SAMPLES failed, error %d\n", GetLastError()); + return; + } + + InfoPrint(""); + InfoPrint("=== Results of KernelMode Samples ==="); + + for (Index = 0; Index < MAX_KERNELMODE_SAMPLES; Index++) { + InfoPrint("\t%S: %s", + GetKernelModeSampleName(Index), + Output.SampleResults[Index]? "Succeeded" : "FAILED"); + } + +} + + + +LPCWSTR +GetKernelModeSampleName ( + _In_ KERNELMODE_SAMPLE Sample + ) +/*++ + +Routine Description: + + Converts from a KERNELMODE_SAMPLE value to a string + +Arguments: + + Sample - value that identifies a kernel mode sample + +Return Value: + + Returns a string of the name of Sample. + +--*/ +{ + switch (Sample) { + case KERNELMODE_SAMPLE_PRE_NOTIFICATION_BLOCK: + return L"Pre-Notification Block Sample"; + case KERNELMODE_SAMPLE_PRE_NOTIFICATION_BYPASS: + return L"Pre-Notification Bypass Sample"; + case KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_SUCCESS: + return L"Post-Notification Override Success Sample"; + case KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_ERROR: + return L"Post-Notification Override Error Sample"; + case KERNELMODE_SAMPLE_TRANSACTION_REPLAY: + return L"Transaction Replay Sample"; + case KERNELMODE_SAMPLE_TRANSACTION_ENLIST: + return L"Transaction Enlist Sample"; + case KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE: + return L"Multiple Altitude Block During Pre Sample"; + case KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION: + return L"Multiple Altitude Internal Invocation Sample"; + case KERNELMODE_SAMPLE_SET_CALL_CONTEXT: + return L"Set Call Context Sample"; + case KERNELMODE_SAMPLE_SET_OBJECT_CONTEXT: + return L"Set Object Context Sample"; + case KERNELMODE_SAMPLE_VERSION_CREATE_OPEN_V1: + return L"Create Open V1 Sample"; + default: + return L"Unsupported Kernel Mode Sample"; + } +} + diff --git a/general/registry/regfltr/exe/regctrl.h b/general/registry/regfltr/exe/regctrl.h new file mode 100644 index 00000000..798b29fc --- /dev/null +++ b/general/registry/regfltr/exe/regctrl.h @@ -0,0 +1,108 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + regctrl.h + +Environment: + + User mode only + +--*/ + +#pragma once + +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <devioctl.h> +#include <tchar.h> +#include <strsafe.h> + +#include "common.h" + +// +// Utility macro +// + +#define ARRAY_LENGTH(array) (sizeof (array) / sizeof (array[0])) + +// +// Logging macros +// + +#define InfoPrint(str, ...) \ + printf(##str"\n", \ + __VA_ARGS__) + +#define ErrorPrint(str, ...) \ + printf("ERROR: %u: "##str"\n", \ + __LINE__, \ + __VA_ARGS__) + +// +// Global variables +// + +// +// Handle to the driver +// +extern HANDLE g_Driver; + +// +// Handle to the root test key +// +extern HKEY g_RootKey; + +// +// Version number for the registry callback +// +extern ULONG g_MajorVersion; +extern ULONG g_MinorVersion; + + +// +// The user mode samples +// + +VOID +PreNotificationBlockSample(); + +VOID +PreNotificationBypassSample(); + +VOID +PostNotificationOverrideSuccessSample(); + +VOID +PostNotificationOverrideErrorSample(); + +VOID +CaptureSample(); + +// +// Utility routines to load and unload the driver +// + +BOOL +UtilLoadDriver( + _In_ LPTSTR szDriverNameNoExt, + _In_ LPTSTR szDriverNameWithExt, + _In_ LPTSTR szWin32DeviceName, + _Out_ HANDLE *pDriver + ); + +BOOL +UtilUnloadDriver( + _In_ HANDLE hDriver, + _In_opt_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverNameNoExt + ); + + diff --git a/general/registry/regfltr/exe/regctrl.rc b/general/registry/regfltr/exe/regctrl.rc new file mode 100644 index 00000000..5e0506fa --- /dev/null +++ b/general/registry/regfltr/exe/regctrl.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Registry Filter Test App" +#define VER_INTERNALNAME_STR "regctrl.exe" +#define VER_ORIGINALFILENAME_STR "regctrl.exe" + +#include "common.ver"
\ No newline at end of file diff --git a/general/registry/regfltr/exe/regctrl.vcxproj b/general/registry/regfltr/exe/regctrl.vcxproj new file mode 100644 index 00000000..a0a9e234 --- /dev/null +++ b/general/registry/regfltr/exe/regctrl.vcxproj @@ -0,0 +1,204 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{F3CBF3E0-E60F-409E-9402-A508C8008EB7}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{7DBA6C3C-01A4-4CB0-A5A2-0D1E014C3F17}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>regctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>regctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>regctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>regctrl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;ntdll.lib;kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;ntdll.lib;kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;ntdll.lib;kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DDK_INC_PATH)</AdditionalIncludeDirectories> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);advapi32.lib;ntdll.lib;kernel32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="capture.c" /> + <ClCompile Include="post.c" /> + <ClCompile Include="pre.c" /> + <ClCompile Include="regctrl.c" /> + <ClCompile Include="util.c" /> + <ResourceCompile Include="regctrl.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/registry/regfltr/exe/regctrl.vcxproj.Filters b/general/registry/regfltr/exe/regctrl.vcxproj.Filters new file mode 100644 index 00000000..33b9e1e1 --- /dev/null +++ b/general/registry/regfltr/exe/regctrl.vcxproj.Filters @@ -0,0 +1,39 @@ +<?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>{9713D19A-A900-45FB-AA68-19BDFD105192}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{8A005B43-A062-4866-BEC2-037F5820B234}</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>{768BFEC7-A3C9-42EA-BCB0-30162CB4DA90}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="capture.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="post.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="pre.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="regctrl.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="regctrl.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/registry/regfltr/exe/util.c b/general/registry/regfltr/exe/util.c new file mode 100644 index 00000000..34d24c38 --- /dev/null +++ b/general/registry/regfltr/exe/util.c @@ -0,0 +1,707 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + util.c + +Abstract: + + Utility routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + +--*/ + + + +#include "regctrl.h" + + +BOOL +UtilCreateService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName, + _In_ LPTSTR szDriverPath +); + +BOOL +UtilStartService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName +); + +BOOL +UtilStopService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName +); + +BOOL +UtilDeleteService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName +); + +BOOL +UtilOpenDevice( + _In_ LPTSTR szWin32DeviceName, + _Out_ HANDLE * phDevice); + +BOOL +UtilGetServiceState( + _In_ SC_HANDLE hService, + _Out_ DWORD * State); + +BOOL +UtilWaitForServiceState( + _In_ SC_HANDLE hService, + _In_ DWORD State); + + +BOOL +UtilLoadDriver( + _In_ LPTSTR szDriverName, + _In_ LPTSTR szDriverFileName, + _In_ LPTSTR szWin32DeviceName, + _Out_ HANDLE *pDriver + ) +/*++ + +Routine Description: + + This routine uses the Service Control Manager APIs to create an entry + for a standalone driver. It then opens a handle to the driver. + The driver is assumed to be in the current directory. + + NOTE: This routine creates an entry for a standalone driver. If this + is modified for use with a driver that requires a Tag, Group, and/or + Dependencies, it may be necessary to query the registry for existing + driver information (in order to determine a unique Tag, etc.). + +Arguments: + + szDriverName - name of the driver (no extension) + + szDriverFileName - name of driver (with extension) + + szWin32DeviceName - Name of driver (no extension) prefixed with \\.\ + + pDriver - pointer to a variable that receives the handle to the driver + +Return Value: + + TRUE if driver is loaded successfully. + +--*/ +{ + BOOL ReturnValue = FALSE; + TCHAR* pPathSeparator; + TCHAR szDriverPath[MAX_PATH] = _T(""); + DWORD dwSize; + SC_HANDLE hSCM = NULL; + HANDLE hDriver = NULL; + + *pDriver = NULL; + + // + // Construct driver path. + // + + dwSize = GetModuleFileName(NULL, szDriverPath, ARRAY_LENGTH(szDriverPath)); + + if (dwSize == 0) { + ErrorPrint("GetModuleFileName failed, last error 0x%u", GetLastError()); + goto Exit; + } + + pPathSeparator = _tcsrchr(szDriverPath, _T('\\')); + + if (pPathSeparator != NULL) { + pPathSeparator[1] = _T('\0'); + _tcscat_s(szDriverPath, MAX_PATH, szDriverFileName); + } else { + ErrorPrint("_tcsrchr failed to file \\ in driver path."); + goto Exit; + } + + // + // Get a handle to SCM + // + + hSCM = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + + if (hSCM == NULL) { + ErrorPrint("OpenSCManager failed, last error 0x%x", GetLastError()); + goto Exit; + } + + // + // First, uninstall and unload the driver. + // + + ReturnValue = UtilUnloadDriver( INVALID_HANDLE_VALUE, hSCM, szDriverName); + + if (ReturnValue != TRUE) { + ErrorPrint("UnloadDriver failed"); + goto Exit; + } + + // + // Install the driver. + // + + ReturnValue = UtilCreateService(hSCM, szDriverName, szDriverPath); + + if (ReturnValue == FALSE) { + ErrorPrint("UtilCreateService failed"); + goto Exit; + } + + // + // Load the driver. + // + + ReturnValue = UtilStartService(hSCM, szDriverName); + + if (ReturnValue == FALSE) { + ErrorPrint("UtilStartService failed"); + goto Exit; + } + + // + // Open a handle to the device. + // + + ReturnValue = UtilOpenDevice(szWin32DeviceName, &hDriver); + + if (ReturnValue == FALSE) { + ErrorPrint("UtilOpenDevice failed"); + goto Exit; + } + + *pDriver = hDriver; + ReturnValue = TRUE; + +Exit: + + if (hSCM != NULL) { + CloseServiceHandle(hSCM); + } + + return ReturnValue; +} + + +BOOL +UtilUnloadDriver( + _In_ HANDLE hDriver, + _In_opt_ SC_HANDLE hPassedSCM, + _In_ LPTSTR szDriverName + ) +/*++ + +Routine Description: + + Unloads the driver using SCManager. + +Arguments: + + hDriver - handle to the driver + + hPassedSCM - handle to the SCManager (optional) + + szDriverName - name of driver (no extension) + +Return Value: + + TRUE if driver is successfully unloaded + +--*/ +{ + + BOOL ReturnValue = FALSE; + SC_HANDLE hSCM = hPassedSCM; + + // + // Get a handle to SCM if not passed in + // + + if (hSCM == NULL) { + + hSCM = OpenSCManager ( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + + if (hSCM == NULL) { + ErrorPrint("OpenSCManager failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + + + // + // Close our handle to the device. + // + + if ((hDriver != NULL) && (hDriver != INVALID_HANDLE_VALUE)) { + CloseHandle (hDriver); + hDriver = INVALID_HANDLE_VALUE; + } + + // + // Unload the driver. + // + + ReturnValue = UtilStopService(hSCM, szDriverName); + + if (ReturnValue == FALSE) { + ErrorPrint("UtilStopService failed"); + goto Exit; + } + + // + // Delete the service. + // + + ReturnValue = UtilDeleteService(hSCM, szDriverName); + + if (ReturnValue == FALSE) { + ErrorPrint("UtilDeleteService failed"); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if ((hPassedSCM == NULL) && (hSCM != NULL)) { + CloseServiceHandle(hSCM); + } + + return ReturnValue; +} + + + +BOOL +UtilGetServiceState ( + _In_ SC_HANDLE hService, + _Out_ DWORD* State + ) +/*++ + +Routine Description: + + Gets the state of the service using QueryServiceStatusEx + +Arguments: + + hService - handle to the service to query + + State - pointer to a variable that receives the state + +Return Value: + + TRUE if service is queried successfully. + +--*/ +{ + SERVICE_STATUS_PROCESS ServiceStatus; + DWORD BytesNeeded; + BOOL Result; + + *State = 0; + + Result = QueryServiceStatusEx ( hService, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&ServiceStatus, + sizeof(ServiceStatus), + &BytesNeeded); + + if (Result == FALSE) { + ErrorPrint("QueryServiceStatusEx failed, last error 0x%x", GetLastError()); + return FALSE; + } + + *State = ServiceStatus.dwCurrentState; + + return TRUE; +} + + +BOOL +UtilWaitForServiceState ( + _In_ SC_HANDLE hService, + _In_ DWORD State + ) +/*++ + +Routine Description: + + This routine waits for the service to reach a certain state + +Arguments: + + hService - handle to the service + + State - the desired state + +Return Value: + + TRUE if service reaches the desired state or FALSE if querying the + service returns an error. + +--*/ +{ + + DWORD ServiceState; + BOOL Result; + + for (;;) { + + Result = UtilGetServiceState (hService, &ServiceState); + + if (Result == FALSE) { + return FALSE; + } + + if (ServiceState == State) { + break; + } + + Sleep (1000); + } + + return TRUE; +} + +// +// UtilCreateService +// + +BOOL +UtilCreateService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName, + _In_ LPTSTR szDriverPath + ) +/*++ + +Routine Description: + + Uses SCManager to create a service + +Arguments: + + hSCM - handle to the SCManager + + szDriverName - name of driver (no extension) which will serve as the + created service's name + + szDriverPath - path to driver + +Return Value: + + TRUE if service is created successfully, FALSE otherwise. + +--*/ +{ + BOOL ReturnValue = FALSE; + + // + // Create the service + // + + SC_HANDLE hService = CreateService ( + hSCM, // handle to SC manager + szDriverName, // name of service + szDriverName, // display name + SERVICE_ALL_ACCESS, // access mask + SERVICE_KERNEL_DRIVER, // service type + SERVICE_DEMAND_START, // start type + SERVICE_ERROR_NORMAL, // error control + szDriverPath, // full path to driver + NULL, // load ordering + NULL, // tag id + NULL, // dependency + NULL, // account name + NULL // password + ); + + if ((hService == NULL) && (GetLastError() != ERROR_SERVICE_EXISTS)) { + ErrorPrint("CreateService failed, last error 0x%x", GetLastError()); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (hService) { + CloseServiceHandle(hService); + } + + return ReturnValue; +} + + +BOOL +UtilStartService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName + ) +/*++ + +Routine Description: + + Starts a service + +Arguments: + + hSCM - handle to the SCManager + + szDriverName - name of driver (without extension), services as name of + the service to start + +Return Value: + + TRUE if service is successfully started, FALSE otherwise. + +--*/ +{ + BOOL ReturnValue = FALSE; + + // + // Open the service. The function assumes that + // UtilCreateService has been called before this one + // and the service is already installed. + // + + SC_HANDLE hService = OpenService ( hSCM, szDriverName, SERVICE_ALL_ACCESS ); + + if (hService == NULL) { + ErrorPrint("OpenService failed, last error 0x%x", GetLastError()); + goto Exit; + } + + // + // Start the service + // + + if (! StartService (hService, 0, NULL)) { + + if (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING) { + ErrorPrint("StartService failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + + if (FALSE == UtilWaitForServiceState (hService, SERVICE_RUNNING)) { + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (hService) { + CloseServiceHandle(hService); + } + + return ReturnValue; +} + + +BOOL +UtilStopService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName + ) +/*++ + +Routine Description: + + Stops a service + +Arguments: + + hSCM - handle to the SCManager + + szDriverName - name of driver (without extension), services as name of + the service + +Return Value: + + TRUE if service is successfully stopped, FALSE otherwise. + +--*/ +{ + BOOL ReturnValue = FALSE; + SERVICE_STATUS ServiceStatus; + + // + // Open the service so we can stop it + // + + SC_HANDLE hService = OpenService ( hSCM, szDriverName, SERVICE_ALL_ACCESS ); + + if (hService == NULL) { + if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { + ReturnValue = TRUE; + } else { + ErrorPrint("OpenService failed, last error 0x%x", GetLastError()); + } + goto Exit; + } + + // + // Stop the service + // + + if (FALSE == ControlService (hService, SERVICE_CONTROL_STOP, &ServiceStatus)) { + if (GetLastError() != ERROR_SERVICE_NOT_ACTIVE) { + ErrorPrint("ControlService failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + + if (FALSE == UtilWaitForServiceState (hService, SERVICE_STOPPED)) { + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + if (hService) { + CloseServiceHandle (hService); + } + + return ReturnValue; +} + + +BOOL +UtilDeleteService( + _In_ SC_HANDLE hSCM, + _In_ LPTSTR szDriverName + ) +/*++ + +Routine Description: + + Deletes a service + +Arguments: + + hSCM - handle to the SCManager + + szDriverName - name of driver (without extension), services as name of + the service + +Return Value: + + TRUE if service is successfully deleted, FALSE otherwise. + +--*/ +{ + BOOL ReturnValue = FALSE; + + // + // Open the service so we can delete it + // + + SC_HANDLE hService = OpenService ( hSCM, szDriverName, SERVICE_ALL_ACCESS ); + + if (hService == NULL) { + if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST) { + ReturnValue = TRUE; + } else { + ErrorPrint("OpenService failed, last error 0x%x", GetLastError()); + } + goto Exit; + } + + // + // Delete the service + // + + if (! DeleteService (hService)) { + if (GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) { + ErrorPrint("DeleteService failed, last error 0x%x", GetLastError()); + goto Exit; + } + } + + ReturnValue = TRUE; + +Exit: + + if (hService) { + CloseServiceHandle (hService); + } + + return ReturnValue; +} + + +BOOL + +UtilOpenDevice( + _In_ LPTSTR szWin32DeviceName, + _Out_ HANDLE *phDevice + ) +/*++ + +Routine Description: + + Opens a device + +Arguments: + + szWin32DeviceName - name of the device + + phDevice - pointer to a variable that receives the handle to the device + +Return Value: + + TRUE if the device is successfully opened, FALSE otherwise. + +--*/ +{ + BOOL ReturnValue = FALSE; + HANDLE hDevice; + + // + // Open the device + // + + hDevice = CreateFile ( szWin32DeviceName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (hDevice == INVALID_HANDLE_VALUE) { + ErrorPrint("CreateFile(%ls) failed, last error 0x%x", + szWin32DeviceName, + GetLastError() ); + goto Exit; + } + + ReturnValue = TRUE; + +Exit: + + *phDevice = hDevice; + return ReturnValue; +} diff --git a/general/registry/regfltr/regfltr.sln b/general/registry/regfltr/regfltr.sln new file mode 100644 index 00000000..1b1e31c3 --- /dev/null +++ b/general/registry/regfltr/regfltr.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{C7CD81BA-CF73-4628-909C-77E4B3370C77}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sys", "Sys", "{700EF2F6-A93B-4398-AE93-EFA0C49511C6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regctrl", "exe\regctrl.vcxproj", "{F3CBF3E0-E60F-409E-9402-A508C8008EB7}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regfltr", "sys\regfltr.vcxproj", "{12666DFF-2CD6-4000-AFE6-0796D9B6D330}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|Win32.ActiveCfg = Debug|Win32 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|Win32.Build.0 = Debug|Win32 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|Win32.ActiveCfg = Release|Win32 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|Win32.Build.0 = Release|Win32 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|x64.ActiveCfg = Debug|x64 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Debug|x64.Build.0 = Debug|x64 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|x64.ActiveCfg = Release|x64 + {F3CBF3E0-E60F-409E-9402-A508C8008EB7}.Release|x64.Build.0 = Release|x64 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|Win32.ActiveCfg = Debug|Win32 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|Win32.Build.0 = Debug|Win32 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|Win32.ActiveCfg = Release|Win32 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|Win32.Build.0 = Release|Win32 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|x64.ActiveCfg = Debug|x64 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Debug|x64.Build.0 = Debug|x64 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|x64.ActiveCfg = Release|x64 + {12666DFF-2CD6-4000-AFE6-0796D9B6D330}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F3CBF3E0-E60F-409E-9402-A508C8008EB7} = {C7CD81BA-CF73-4628-909C-77E4B3370C77} + {12666DFF-2CD6-4000-AFE6-0796D9B6D330} = {700EF2F6-A93B-4398-AE93-EFA0C49511C6} + EndGlobalSection +EndGlobal diff --git a/general/registry/regfltr/sys/capture.c b/general/registry/regfltr/sys/capture.c new file mode 100644 index 00000000..7b350e73 --- /dev/null +++ b/general/registry/regfltr/sys/capture.c @@ -0,0 +1,620 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + capture.c + +Abstract: + + This file contains + 1. Documentation for what parameters need to be captured + 2. A simple sample showing how to capture the parameters for + SetValueKey and DeleteValueKey operations. + 3. Helper routines for capturing buffers and UNICODE_STRINGs. + +Environment: + + Kernel mode only + +--*/ + + +#include "regfltr.h" + + +/*++ + + Probing and Capturing Parameters + + This section defines how registry filtering drivers should handle input + parameters. + + + I. Probed Parameters + + All members in related registry structures (e.g. REG_CREATE_KEY_INFORMATION, + REG_SAVE_KEY_INFORMATION) and all structures and buffers pointed to by + their buffers are already probed by registry. Parameters are probed only + when ExGetPreviousMode indicates that the previous mode was user mode. If + the previous mode is kernel mode (i.e. KernelMode. is returned by + ExGetPreviousMode), all parameters are considered valid and no probing is + done in this case. + + + II. Captured parameters + + Most but not all members in related registry structures are captured. + If the previous mode is kernel mode, all parameters are considered valid + and no capturing is done in this case. If the previous mode is user mode, + all parameters are probed but not necessarily captured. Since this impacts + how registry filtering drivers should handle input parameters, we outline + below exactly which parameters are captured. It is important to note that + some members currently probed but not captured by the OS may be captured + in the future. On the other hand registry filtering drivers can rely on + the fact that parameters currently captured will be captured in all future + OS releases. + + * Note: As of Windows 8, all structures except output buffers are fully + captured. + + 1. Fully captured structures: + + Note: A fully captured structure is a captured structure where all + structures and buffers pointed to by its members are also fully + captured. + + For example: the UNICODE_STRING structure pointed to by the + CompleteName member in the fully captured REG_CREATE_KEY_INFORMATION + structure is also captured (including the Buffer member of the + UNICODE_STRING). + + List of fully captured structures (in Windows 7): + + REG_CREATE_KEY_INFORMATION (** incorrect) + REG_CREATE_KEY_INFORMATION_V1 (** incorrect) + REG_DELETE_KEY_INFORMATION + REG_FLUSH_KEY_INFORMATION + REG_KEY_HANDLE_CLOSE_INFORMATION + REG_OPEN_KEY_INFORMATION + REG_OPEN_KEY_INFORMATION_V1 + REG_QUERY_KEY_SECURITY_INFORMATION (** added) + REG_REPLACE_KEY_INFORMATION + REG_RESTORE_KEY_INFORMATION + REG_SAVE_KEY_INFORMATION + REG_SET_KEY_SECURITY_INFORMATION. + REG_UNLOAD_KEY_INFORMATION + + ** There were incorrect entries in this list that are now + corrected. REG_CREATE_KEY_INFORMATION and + REG_CREATE_KEY_INFORMATION_V1 are not fully captured and should + be on the partially captured structures. + REG_QUERY_KEY_SECURITY_INFORMATION has now been added to the list + of fully captured structures. + + 2. Partially captured structures + + Note: This section has been modified for clarity in the Windows 8 + release of the WDK. However this information only applies to Windows 7 + since in Windows 8 all input buffers and structures are captured. + + This section defines which members are captured in the partially + captured structures. + + Notes: + + A. CallContext, ObjectContext members are not consumed by registry + and are not treated as probed or captured by this document. + B. Integer types (e.g. enum, int, �) are considered captured in the + structure and are not explicitly listed below. + C. The Object member is always captured and it's not explicitly + listed below. + D. Output buffers are probed but not captured + + List of partially captured structures and the members that are NOT + captured: + + REG_CREATE_KEY_INFORMATION: Class->Buffer + REG_CREATE_KEY_INFORMATION_V1: Class->Buffer + REG_DELETE_VALUE_KEY_INFORMATION: ValueName->Buffer + REG_LOAD_KEY_INFORMATION: KeyName->Buffer + REG_QUERY_VALUE_KEY_INFORMATION: ValueName->Buffer + REG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION: BufferLength + REG_RENAME_KEY_INFORMATION: NewName->Buffer + REG_SET_VALUE_KEY_INFORMATION: Data + + + All other REG_Xxx_INFORMATION structures do not have fields that + require capturing other than those mentioned in notes B and C. + + Example: + + REG_ENUMERATE_KEY_INFORMATION: + Object: captured, see (C) above + Index: captured, see (B) above + KeyInformationClass : captured, see (B) above + KeyInformation: only probed, see (D) above + Length: captured, see (B) above + ResultLength: only probed, see (D) above + CallContext, ObjectContext: unknown, see (A) above + Reserved: currently undefined + + List of these structures: + + REG_CALLBACK_CONTEXT_CLEANUP_INFORMATION + REG_DELETE_KEY_INFORMATION + REG_ENUMERATE_KEY_INFORMATION + REG_KEY_HANDLE_CLOSE_INFORMATION + REG_QUERY_KEY_INFORMATION + REG_QUERY_KEY_SECURITY_INFORMATION + REG_REPLACE_KEY_INFORMATION + REG_RESTORE_KEY_INFORMATION + REG_SAVE_KEY_INFORMATION + REG_SET_INFORMATION_KEY_INFORMATION + REG_SET_KEY_SECURITY_INFORMATION + REG_UNLOAD_KEY_INFORMATION + + + III. Handling Registry Filtering Parameters + + Registry filtering drivers must handle input parameters correctly. If the + previous mode is user mode and the driver needs to use a parameter, it must + depending on the scenario either wrap every access with a try-except + construct or capture the parameter. If the driver wants to call a Zw + registry API or any other kernel mode Zw API, it must ensure that all the + arguments passed to the call are captured because these APIs will not + probe or capture their inputs if the call originated from kernel mode. + + There is no need for drivers to probe any of the parameters as the registry + has already probed them. If the driver uses the OS probe APIs to probe a + parameter that has already been captured by the registry, it will throw an + exception. + + Note: Special handling should be provided for NULL buffers. In some cases + such buffer might be considered valid even for kernel mode. + +--*/ + + +NTSTATUS +CallbackCapture( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 +) +/*++ + +Routine Description: + + This helper callback routine shows how to capture a buffer and a + unicode string with the name of a value. The bulk of the work is down + in the helper capture routines: CaptureBuffer and CaptureUnicodeString. + + In the pre-notification phase, we bypass the set value and delete value + operations and complete them manually by calling ZwSetValueKey and + ZwDeleteValueKey. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_SET_VALUE_KEY_INFORMATION PreSetValueInfo; + PREG_DELETE_VALUE_KEY_INFORMATION PreDeleteValueInfo; + HANDLE RootKey = NULL; + PVOID LocalData = NULL; + PVOID Data = NULL; + UNICODE_STRING LocalValueName = {0}; + PUNICODE_STRING ValueName = NULL; + KPROCESSOR_MODE Mode = KernelMode; + + UNREFERENCED_PARAMETER(CallbackCtx); + + switch(NotifyClass) { + + case RegNtPreSetValueKey: + + PreSetValueInfo = (PREG_SET_VALUE_KEY_INFORMATION) Argument2; + + // + // REG_SET_VALUE_KEY_INFORMATION is a partially captured structure. + // The value name is captured but the data is not. Since we are + // passing the data to a zw* method, we need to capture it. + // + // *Note: as of win8, the data buffer is captured as well + // by the registry. + // + + Mode = ExGetPreviousMode(); + + if (!g_IsWin8OrGreater && (Mode == UserMode)) { + Status = CaptureBuffer(&LocalData, + PreSetValueInfo->Data, + PreSetValueInfo->DataSize, + REGFLTR_CAPTURE_POOL_TAG); + if (!NT_SUCCESS(Status)) { + break; + } + Data = LocalData; + } else { + Data = PreSetValueInfo->Data; + } + + // + // Get a handle to the root key the value is being created under. + // This is in PreInfo->Object. + // + + Status = ObOpenObjectByPointer(PreSetValueInfo->Object, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + NULL, + KernelMode, + &RootKey); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + break; + } + + // + // Set the value. + // + + Status = ZwSetValueKey(RootKey, + PreSetValueInfo->ValueName, + 0, + PreSetValueInfo->Type, + Data, + PreSetValueInfo->DataSize); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue in CallbackModify failed. Status 0x%x", + Status); + ZwClose(RootKey); + break; + } + + // + // Finally return STATUS_CALLBACK_BYPASS to tell the registry + // not to proceed with the original registry operation and to return + // STATUS_SUCCESS to the caller. + // + + InfoPrint("\tCallback: Set value %wZ bypassed.", PreSetValueInfo->ValueName); + Status = STATUS_CALLBACK_BYPASS; + ZwClose(RootKey); + break; + + case RegNtPreDeleteValueKey: + + PreDeleteValueInfo = (PREG_DELETE_VALUE_KEY_INFORMATION) Argument2; + + // + // REG_DELETE_VALUE_KEY_INFORMATION is a partially captured + // structure. The value name's buffer is not captured. Since we are + // passing the name to a zw* method, we need to capture it. + // + // *Note: as of Win8, the data buffer is captured already + // by the registry. + // + + Mode = ExGetPreviousMode(); + + if (!g_IsWin8OrGreater && (Mode == UserMode)) { + Status = CaptureUnicodeString(&LocalValueName, + PreDeleteValueInfo->ValueName, + REGFLTR_CAPTURE_POOL_TAG); + if (!NT_SUCCESS(Status)) { + break; + } + ValueName = &LocalValueName; + } else { + ValueName = PreDeleteValueInfo->ValueName; + } + + // + // Get a handle to the root key the value is being created under. + // This is in PreInfo->Object. + // + + Status = ObOpenObjectByPointer(PreDeleteValueInfo->Object, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + NULL, + KernelMode, + &RootKey); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + break; + } + + // + // Set the value. + // + + Status = ZwDeleteValueKey(RootKey, + ValueName); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwDeleteValue failed. Status 0x%x", + Status); + ZwClose(RootKey); + break; + } + + // + // Finally return STATUS_CALLBACK_BYPASS to tell the registry + // not to proceed with the original registry operation and to return + // STATUS_SUCCESS to the caller. + // + + InfoPrint("\tCallback: Delete value %S bypassed.", ValueName->Buffer); + Status = STATUS_CALLBACK_BYPASS; + ZwClose(RootKey); + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + // + // Free buffers used for capturing user mode values. + // + + if (LocalData != NULL){ + FreeCapturedBuffer(LocalData, REGFLTR_CAPTURE_POOL_TAG); + } + + if (LocalValueName.Buffer != NULL) { + FreeCapturedUnicodeString(&LocalValueName, REGFLTR_CAPTURE_POOL_TAG); + } + + return Status; +} + + + + +NTSTATUS +CaptureBuffer( + _Outptr_result_maybenull_ PVOID *CapturedBuffer, + _In_reads_bytes_(Length) PVOID Buffer, + _In_ SIZE_T Length, + _In_ ULONG PoolTag + ) +/*++ + +Routine Description: + + Captures a buffer using allocations with the specified pool tag. Captured + buffer should be freed using FreeCapturedBuffer. + +Arguments: + + CapturedBuffer - pointer to a variable that receives the location of the + captured buffer. + + Buffer - the buffer to capture + + Length - Length of Buffer + + PoolTag - pool tag + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PVOID TempBuffer = NULL; + + NT_ASSERT(CapturedBuffer != NULL); + + if (Length == 0) { + *CapturedBuffer = NULL; + return Status; + } + + TempBuffer = (PCALLBACK_CONTEXT) ExAllocatePoolWithTag( + PagedPool, + Length, + PoolTag); + + // + // It's a good practice to keep the contents of a try-except block to + // the bare minimum. By keeping the pool allocation call outside of the + // try-except block we don't mask possible pool corruptions. + // + + if (TempBuffer != NULL) { + try { + RtlCopyMemory(TempBuffer, Buffer, Length); + } except (ExceptionFilter(GetExceptionInformation())) { + ErrorPrint("Capturing buffer failed with exception"); + ExFreePoolWithTag(TempBuffer, PoolTag); + TempBuffer = NULL; + Status = GetExceptionCode(); + } + } else { + ErrorPrint("Capturing buffer failed wtih insufficient resources"); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + *CapturedBuffer = TempBuffer; + + return Status; + } + + +VOID +FreeCapturedBuffer( + _In_ PVOID CapturedBuffer, + _In_ ULONG PoolTag + ) +/*++ + +Routine Description: + + Frees a captured buffer. + +Arguments: + + CapturedBuffer - captured buffer + + PoolTag - pool tag + +--*/ +{ + if (CapturedBuffer != NULL) { + ExFreePoolWithTag(CapturedBuffer, PoolTag); + } +} + + +NTSTATUS +CaptureUnicodeString( + _Inout_ UNICODE_STRING *DestString, + _In_ PCUNICODE_STRING SourceString, + _In_ ULONG PoolTag + ) +/*++ + +Routine Description: + + Captures a unicode string. The buffer is captured based on SourceString's + Length field with the addition of sizeof(WCHAR) bytes for a NULL to + signal the end of the string. + + Use FreeCapturedUnicodeString to free the captured string. + +Arguments: + + DestString - Pointer to the unicode string that will receive the + captured buffer. + + SourceString - Pointer tot he unicode string to be captured. + + PoolTag - pool tag + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + + + if (SourceString->Length == 0) { + DestString->Length = 0; + DestString->Buffer = NULL; + DestString->MaximumLength = 0; + return Status; + } + + // + // Only SourceString->Length should be checked. The registry does not + // validate SourceString->MaximumLength. + // + // An additional sizeof(WCHAR) bytes are added to the buffer size since + // SourceString->Length does not include the NULL at the end of the string. + // + + DestString->Length = SourceString->Length; + DestString->MaximumLength = SourceString->Length + sizeof(WCHAR); + + DestString->Buffer = (PWSTR) ExAllocatePoolWithTag( + PagedPool, + DestString->MaximumLength, + PoolTag); + + if (DestString->Buffer != NULL) { + + RtlZeroMemory(DestString->Buffer, DestString->MaximumLength); + + // + // It's a good practice to keep the contents of a try-except block to + // the bare minimum. By keeping the pool allocation call outside of the + // try-except block we don't mask possible pool corruptions. + // + + try { + RtlCopyMemory(DestString->Buffer, + SourceString->Buffer, + SourceString->Length); + } except (ExceptionFilter(GetExceptionInformation())) { + ErrorPrint("Capturing Unicode String failed with exception"); + ExFreePoolWithTag(DestString->Buffer, PoolTag); + DestString->Buffer = NULL; + Status = GetExceptionCode(); + } + + } else { + ErrorPrint("Capturing Unicode String failed wtih insufficient resources"); + Status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (DestString->Buffer == NULL) { + DestString->Length = 0; + DestString->MaximumLength = 0; + } + + return Status; + +} + + +VOID +FreeCapturedUnicodeString( + _In_ UNICODE_STRING *String, + _In_ ULONG PoolTag + ) +/*++ + +Routine Description: + + Frees a captured buffer. + +Arguments: + + CapturedBuffer - captured buffer + + PoolTag - pool tag + +--*/ +{ + if (String->Length != 0) { + String->Length = 0; + String->MaximumLength = 0; + FreeCapturedBuffer(String->Buffer, PoolTag); + String->Buffer = NULL; + } +} diff --git a/general/registry/regfltr/sys/context.c b/general/registry/regfltr/sys/context.c new file mode 100644 index 00000000..e599606f --- /dev/null +++ b/general/registry/regfltr/sys/context.c @@ -0,0 +1,582 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Context.c + +Abstract: + + Samples that show how to set call contexts and object contexts. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +BOOLEAN +SetObjectContextSample( + ) +/*++ + +Routine Description: + + This sample shows how a registry callback can associate a context on + a registry object using CmSetCallbackObjectContext. + + This context is available in the ObjectContext field of the + REG_Xxx_KEY_INFORMATION data structures. The registry object is a handle + to a key and not the registry key itself. When the handle is closed + or the callback is unregistered, the callback will receive a + RegNtCallbackObjectContextCleanup notification to give a chance to + clean up the context. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES KeyAttributes; + HANDLE RootKeyWithContext = NULL; + DWORD ValueData = 0; + BOOLEAN Success = FALSE; + + + InfoPrint(""); + InfoPrint("=== Set Object Context Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_SET_OBJECT_CONTEXT, + CALLBACK_ALTITUDE); + + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register the callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Open the root key again. The callback will associate an object + // context with the RootKeyWithContext handle. + // + + RtlInitUnicodeString(&Name, ROOT_KEY_ABS_PATH); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwOpenKey(&RootKeyWithContext, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKey on root key failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Set value using both the g_RootKey handle and the RootKeyWithContext + // handle. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue failed. Status 0x%x", Status); + Success = FALSE; + } + + if (RootKeyWithContext != NULL) { + Status = ZwSetValueKey(RootKeyWithContext, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue failed. Status 0x%x", Status); + Success = FALSE; + } + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + } + + // + // Check that the RegNtCallbackObjectContextCleanup notification was + // received when we unregistered the callback. + // + + if (CallbackCtx->ContextCleanupCount != 1) { + ErrorPrint("Callback was not invoked for a context cleanup notification."); + Success = FALSE; + } + + // + // Check that there were two notifications that had the object context set. + // These are the pre and post set value using the RootKeyWithContext handle. + // + + if (CallbackCtx->NotificationWithContextCount != 2) { + ErrorPrint("Callback OperationWithContext count expected 2, instead it was %d", + CallbackCtx->NotificationWithContextCount); + Success = FALSE; + } + + // + // Check that there were two notifications that did not have the object + // context set. These are the pre and post set value using the + // g_RootKey handle. + // + + if (CallbackCtx->NotificationWithNoContextCount != 2) { + ErrorPrint("Callback OperationWithNoContext count expected 2, instead it was %d", + CallbackCtx->NotificationWithNoContextCount); + Success = FALSE; + } + + Exit: + + if (Success == TRUE) { + InfoPrint("Set Object Context Sample Succeeded."); + } else { + ErrorPrint("Set Object Context Sample FAILED."); + } + + // + // Clean up + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + + if (RootKeyWithContext != NULL) { + ZwClose(RootKeyWithContext); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + return Success; +} + + +NTSTATUS +CallbackSetObjectContext( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 +) +/*++ + +Routine Description: + + This helper callback routine shows how to associate a registry key object + with context information using CmSetCallbackObjectContext. The context + set is then only available to this callback. A callback that sets the + object context should be prepared for a RegNtCallbackObjectContextCleanup + where it must clean up the context. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + Always STATUS_SUCCESS; + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_CALLBACK_CONTEXT_CLEANUP_INFORMATION CleanupInfo; + PREG_POST_OPERATION_INFORMATION PostInfo; + PVOID ObjectContext = NULL; + + switch(NotifyClass) { + + case RegNtPostOpenKeyEx: + + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + + // + // If the open key was successful, set an object context + // to the key object. + // + // Note that one of the parameters of CmSetCallbackObjectContext + // is the cookie gotten from registering a callback. The object + // context will only be available to the callback with that + // particular cookie. + // + + if (NT_SUCCESS(PostInfo->Status)) { + + // + // Never call CmSetCallbackObjectContext outside of the + // callback routine. + // + + Status = CmSetCallbackObjectContext(PostInfo->Object, + &CallbackCtx->Cookie, + CallbackCtx, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmSetCallbackobjectContext failed. Status 0x%x", + Status); + } + } + break; + + case RegNtPreSetValueKey: + case RegNtPostSetValueKey: + + // + // All registry operations using the handle received from the open + // key operation will come with the ObjectContext field set to the + // context information. Other operations on the same key but + // using a different handle will not have the ObjectContext field + // set. + // + + if (NotifyClass == RegNtPreSetValueKey) { + ObjectContext = ((PREG_SET_VALUE_KEY_INFORMATION) Argument2)->ObjectContext; + } else { + ObjectContext = ((PREG_POST_OPERATION_INFORMATION) Argument2)->ObjectContext; + } + + if (ObjectContext == NULL) { + InterlockedIncrement(&CallbackCtx->NotificationWithNoContextCount); + } else if (ObjectContext == CallbackCtx) { + InterlockedIncrement(&CallbackCtx->NotificationWithContextCount); + } else { + ErrorPrint("Unexpected ObjectContext value: 0x%p", ObjectContext); + } + + break; + + case RegNtCallbackObjectContextCleanup: + + // + // This is a special notification only invoked for callbacks + // that have set context information to an object. This notification + // is either sent when the registry object is being closed or if + // the callback is being unregistered. In the first case, this + // notification comes after the RegNtPreKeyHandleClose + // notification and before the RegNtPostKeyHandleClose notification. + // + + CleanupInfo = (PREG_CALLBACK_CONTEXT_CLEANUP_INFORMATION) Argument2; + if (CleanupInfo->ObjectContext != CallbackCtx) { + ErrorPrint("ContextCleanup's ObjectContext has unexpected value: 0x%p.", + CleanupInfo->ObjectContext); + } else { + InterlockedIncrement(&CallbackCtx->ContextCleanupCount); + } + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; +} + + +BOOLEAN +SetCallContextSample( + ) +/*++ + +Routine Description: + + This sample shows how a registry callback can associate a context + with a registry operation during the pre-notification phase so that it + is available in the post-notification phase. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + DWORD ValueData = 0; + BOOLEAN Success = FALSE; + + + InfoPrint(""); + InfoPrint("=== Set Operation Context Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_SET_CALL_CONTEXT, + CALLBACK_ALTITUDE); + + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register callback with the context + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Create a key and set a value. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + + // + // Check that the callback records 2 in OperationContextCount. + // The count should be incremented once in the post-notification for the + // create key and once for the set value. + // + + if (CallbackCtx->NotificationWithContextCount != 2) { + ErrorPrint("Callback OperationWithContextCount expected 2, got %d", + CallbackCtx->NotificationWithContextCount); + Success = FALSE; + } + + Exit: + + if (Success == TRUE) { + InfoPrint("Set Call Context sample succeeded."); + } else { + ErrorPrint("Set Call Context sample FAILED."); + } + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + return Success; + +} + + + +NTSTATUS +CallbackSetCallContext( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine shows how to attach context information to + the registry operation itself in the pre-notification phase and + have access to that context in the post-notification phase. The context + is private to this callback. + + ***Note: Any callback that receives a pre-notification will receive + a post-notifcation EXCEPT if the callback returns a non-success value + (this includes STATUS_CALLBACK_BYPASS) during the pre phase. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + Always STATUS_SUCCESS + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_POST_OPERATION_INFORMATION PostInfo; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + PREG_SET_VALUE_KEY_INFORMATION PreSetValueInfo; + + switch(NotifyClass) { + + // + // Set the call context by setting it to the CallContext field of the + // REG_XXX_KEY_INFORMATION structure during the pre-notification phase. + // + + case RegNtPreSetValueKey: + PreSetValueInfo = (PREG_SET_VALUE_KEY_INFORMATION) Argument2; + PreSetValueInfo->CallContext = CallbackCtx; + break; + + case RegNtPreCreateKeyEx: + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) Argument2; + PreCreateInfo->CallContext = CallbackCtx; + break; + + // + // In the post-notification phase, check that the CallContext field + // of REG_POST_OPERATION_INFORMATION contains the context we set in + // the pre phase. + // + + case RegNtPostSetValueKey: + case RegNtPostCreateKeyEx: + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + if (PostInfo->CallContext != CallbackCtx) { + ErrorPrint("Unexpected CallContext value: 0x%p", PostInfo->CallContext); + } else { + InterlockedIncrement(&CallbackCtx->NotificationWithContextCount); + } + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; +} + diff --git a/general/registry/regfltr/sys/driver.c b/general/registry/regfltr/sys/driver.c new file mode 100644 index 00000000..d169a1be --- /dev/null +++ b/general/registry/regfltr/sys/driver.c @@ -0,0 +1,468 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + regfltr.c + +Abstract: + + Sample driver used to run the kernel mode registry callback samples. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +DRIVER_INITIALIZE DriverEntry; +DRIVER_UNLOAD DeviceUnload; + +_Dispatch_type_(IRP_MJ_CREATE) DRIVER_DISPATCH DeviceCreate; +_Dispatch_type_(IRP_MJ_CLOSE) DRIVER_DISPATCH DeviceClose; +_Dispatch_type_(IRP_MJ_CLEANUP) DRIVER_DISPATCH DeviceCleanup; +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH DeviceControl; + +// +// Pointer to the device object used to register registry callbacks +// +PDEVICE_OBJECT g_DeviceObj; + +// +// Registry callback version +// +ULONG g_MajorVersion; +ULONG g_MinorVersion; + +// +// Set to TRUE if TM and RM were successfully created and the transaction +// callback was successfully enabled. +// +BOOLEAN g_RMCreated; + + +// +// OS version globals initialized in driver entry +// + +BOOLEAN g_IsWin8OrGreater = FALSE; + +VOID +DetectOSVersion() +/*++ + +Routine Description: + + This routine determines the OS version and initializes some globals used + in the sample. + +Arguments: + + None + +Return value: + + None. On failure, global variables stay at default value + +--*/ +{ + + RTL_OSVERSIONINFOEXW VersionInfo = {0}; + NTSTATUS Status; + ULONGLONG ConditionMask = 0; + + // + // Set VersionInfo to Win7's version number and then use + // RtlVerifVersionInfo to see if this is win8 or greater. + // + + VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo); + VersionInfo.dwMajorVersion = 6; + VersionInfo.dwMinorVersion = 1; + + VER_SET_CONDITION(ConditionMask, VER_MAJORVERSION, VER_LESS_EQUAL); + VER_SET_CONDITION(ConditionMask, VER_MINORVERSION, VER_LESS_EQUAL); + + + + Status = RtlVerifyVersionInfo(&VersionInfo, + VER_MAJORVERSION | VER_MINORVERSION, + ConditionMask); + if (NT_SUCCESS(Status)) { + g_IsWin8OrGreater = FALSE; + InfoPrint("DetectOSVersion: This machine is running Windows 7 or an older OS."); + } else if (Status == STATUS_REVISION_MISMATCH) { + g_IsWin8OrGreater = TRUE; + InfoPrint("DetectOSVersion: This machine is running Windows 8 or a newer OS."); + } else { + ErrorPrint("RtlVerifyVersionInfo returned unexpected error status 0x%x.", + Status); + + // + // default action is to assume this is not win8 + // + g_IsWin8OrGreater = FALSE; + } + +} + + + +NTSTATUS +DriverEntry ( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + This routine is called by the operating system to initialize the driver. + It allocates a device object, initializes the supported Io callbacks, and + creates a symlink to make the device accessible to Win32. + + It gets the registry callback version and stores it in the global + variables g_MajorVersion and g_MinorVersion. It also calls + CreateKTMResourceManager to create a resource manager that is used in + the transaction samples. + +Arguments: + + DriverObject - Supplies the system control object for this test driver. + + RegistryPath - The string location of the driver's corresponding services + key in the registry. + +Return value: + + Success or appropriate failure code. + +--*/ +{ + NTSTATUS Status; + UNICODE_STRING NtDeviceName; + UNICODE_STRING DosDevicesLinkName; + UNICODE_STRING DeviceSDDLString; + + UNREFERENCED_PARAMETER(RegistryPath); + + DbgPrintEx(DPFLTR_IHVDRIVER_ID, + DPFLTR_ERROR_LEVEL, + "RegFltr: DriverEntry()\n"); + + DbgPrintEx(DPFLTR_IHVDRIVER_ID, + DPFLTR_ERROR_LEVEL, + "RegFltr: Use ed nt!Kd_IHVDRIVER_Mask 8 to enable more detailed printouts\n"); + + // + // Create our device object. + // + + RtlInitUnicodeString(&NtDeviceName, NT_DEVICE_NAME); + RtlInitUnicodeString(&DeviceSDDLString, DEVICE_SDDL); + + Status = IoCreateDeviceSecure( + DriverObject, // pointer to driver object + 0, // device extension size + &NtDeviceName, // device name + FILE_DEVICE_UNKNOWN, // device type + 0, // device characteristics + TRUE, // not exclusive + &DeviceSDDLString, // SDDL string specifying access + NULL, // device class guid + &g_DeviceObj); // returned device object pointer + + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Set dispatch routines. + // + + DriverObject->MajorFunction[IRP_MJ_CREATE] = DeviceCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = DeviceClose; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DeviceCleanup; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DeviceControl; + DriverObject->DriverUnload = DeviceUnload; + + // + // Create a link in the Win32 namespace. + // + + RtlInitUnicodeString(&DosDevicesLinkName, DOS_DEVICES_LINK_NAME); + + Status = IoCreateSymbolicLink(&DosDevicesLinkName, &NtDeviceName); + + if (!NT_SUCCESS(Status)) { + IoDeleteDevice(DriverObject->DeviceObject); + return Status; + } + + // + // Get callback version. + // + + CmGetCallbackVersion(&g_MajorVersion, &g_MinorVersion); + InfoPrint("Callback version %u.%u", g_MajorVersion, g_MinorVersion); + + // + // Some variations depend on knowing if the OS is win8 or above + // + + DetectOSVersion(); + + // + // Set up KTM resource manager and pass in RMCallback as our + // callback routine. + // + + Status = CreateKTMResourceManager(RMCallback, NULL); + + if (NT_SUCCESS(Status)) { + g_RMCreated = TRUE; + } + + // + // Initialize the callback context list + // + + InitializeListHead(&g_CallbackCtxListHead); + ExInitializeFastMutex(&g_CallbackCtxListLock); + g_NumCallbackCtxListEntries = 0; + + return STATUS_SUCCESS; + +} + + + +NTSTATUS +DeviceCreate ( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp + ) +/*++ + +Routine Description: + + Dispatches file create requests. + +Arguments: + + DeviceObject - The device object receiving the request. + + Irp - The request packet. + +Return Value: + + STATUS_NOT_IMPLEMENTED + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + + + +NTSTATUS +DeviceClose ( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp + ) +/*++ + +Routine Description: + + Dispatches close requests. + +Arguments: + + DeviceObject - The device object receiving the request. + + Irp - The request packet. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + + + +NTSTATUS +DeviceCleanup ( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp + ) +/*++ + +Routine Description: + + Dispatches cleanup requests. Does nothing right now. + +Arguments: + + DeviceObject - The device object receiving the request. + + Irp - The request packet. + +Return Value: + + STATUS_SUCCESS + +--*/ +{ + UNREFERENCED_PARAMETER(DeviceObject); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return STATUS_SUCCESS; +} + + + +NTSTATUS +DeviceControl ( + _In_ PDEVICE_OBJECT DeviceObject, + _Inout_ PIRP Irp + ) +/*++ + +Routine Description: + + Dispatches ioctl requests. + +Arguments: + + DeviceObject - The device object receiving the request. + + Irp - The request packet. + +Return Value: + + Status returned from the method called. + +--*/ +{ + PIO_STACK_LOCATION IrpStack; + ULONG Ioctl; + NTSTATUS Status; + + UNREFERENCED_PARAMETER(DeviceObject); + + Status = STATUS_SUCCESS; + + IrpStack = IoGetCurrentIrpStackLocation(Irp); + Ioctl = IrpStack->Parameters.DeviceIoControl.IoControlCode; + + switch (Ioctl) + { + + case IOCTL_DO_KERNELMODE_SAMPLES: + Status = DoCallbackSamples(DeviceObject, Irp); + break; + + case IOCTL_REGISTER_CALLBACK: + Status = RegisterCallback(DeviceObject, Irp); + break; + + case IOCTL_UNREGISTER_CALLBACK: + Status = UnRegisterCallback(DeviceObject, Irp); + break; + + case IOCTL_GET_CALLBACK_VERSION: + Status = GetCallbackVersion(DeviceObject, Irp); + break; + + default: + ErrorPrint("Unrecognized ioctl code 0x%x", Ioctl); + } + + // + // Complete the irp and return. + // + + Irp->IoStatus.Status = Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; + +} + + +VOID +DeviceUnload ( + _In_ PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + Cleans up any driver-level allocations and prepares for unload. All + this driver needs to do is to delete the device object and the + symbolic link between our device name and the Win32 visible name. + +Arguments: + + DeviceObject - The device object receiving the request. + + Irp - The request packet. + +Return Value: + + STATUS_NOT_IMPLEMENTED + +--*/ +{ + UNICODE_STRING DosDevicesLinkName; + + // + // Clean up the KTM data structures + // + + DeleteKTMResourceManager(); + + // + // Delete the link from our device name to a name in the Win32 namespace. + // + + RtlInitUnicodeString(&DosDevicesLinkName, DOS_DEVICES_LINK_NAME); + IoDeleteSymbolicLink(&DosDevicesLinkName); + + // + // Finally delete our device object + // + + IoDeleteDevice(DriverObject->DeviceObject); + + DbgPrintEx(DPFLTR_IHVDRIVER_ID, + DPFLTR_ERROR_LEVEL, + "RegFltr: DeviceUnload\n"); +} + diff --git a/general/registry/regfltr/sys/multialt.c b/general/registry/regfltr/sys/multialt.c new file mode 100644 index 00000000..b471d0ba --- /dev/null +++ b/general/registry/regfltr/sys/multialt.c @@ -0,0 +1,776 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + MultiAlt.c + +Abstract: + + Samples that feature multiple callbacks registered at different + altitudes and show what notifications they do and don't recieve. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +BOOLEAN +MultipleAltitudeBlockDuringPreSample( + ) +/*++ + +Routine Description: + + This sample features a stack of three callbacks at different altitudes and + demonstrates what happens when middle callback blocks an operation + in the pre-notification phase. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + + PCALLBACK_CONTEXT CallbackCtxHigh = NULL; + PCALLBACK_CONTEXT CallbackCtxMid = NULL; + PCALLBACK_CONTEXT CallbackCtxLow = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Multiple Altitude Block During Pre Sample ===="); + + // + // Create callback contexts for the 3 callbacks. + // The high and low callbacks will only monitor how many notifications + // they receive. + // + + CallbackCtxHigh = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR, + CALLBACK_HIGH_ALTITUDE); + CallbackCtxMid = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE, + CALLBACK_ALTITUDE); + CallbackCtxLow = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR, + CALLBACK_LOW_ALTITUDE); + + if ((CallbackCtxHigh == NULL) || + (CallbackCtxMid == NULL) || + (CallbackCtxLow == NULL)) { + goto Exit; + } + + // + // Register the callbacks + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxHigh->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxHigh, + &CallbackCtxHigh->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxMid->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxMid, + &CallbackCtxMid->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxLow->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxLow, + &CallbackCtxLow->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Do a create key operation which will be blocked by the middle + // callback and fail with STATUS_ACCESS_DENIED + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwCreateKey returned unexpected status 0x%x", Status); + Success = FALSE; + } + + + // + // Unregister the callbacks + // + + Status = CmUnRegisterCallback(CallbackCtxHigh->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + } + + Status = CmUnRegisterCallback(CallbackCtxMid->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + } + + Status = CmUnRegisterCallback(CallbackCtxLow->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + } + + + // + // Verify that the highest alitude callback receives a pre and a post + // notification. It receives a post notification because it returned + // STATUS_SUCCESS in the pre-notification so it is guaranteed to get a + // post notification. + // + + if ((CallbackCtxHigh->PreNotificationCount != 1) || + (CallbackCtxHigh->PostNotificationCount != 1)) { + ErrorPrint("High Callback should have seen 1 pre and 1 post notifications."); + ErrorPrint("High Callback actually saw %d pre and %d post notifications.", + CallbackCtxHigh->PreNotificationCount, + CallbackCtxHigh->PostNotificationCount); + Success = FALSE; + } + + // + // Verify the middle callback receives only a pre notification. + // It does not get a post notification because it return a non-success + // value in the pre-notification phase. + // + + if ((CallbackCtxMid->PreNotificationCount != 1) || + (CallbackCtxMid->PostNotificationCount != 0)) { + ErrorPrint("Mid Callback should have seen 1 pre and 0 post notifications."); + ErrorPrint("Mid Callback actually saw %d pre and %d post notifications.", + CallbackCtxMid->PreNotificationCount, + CallbackCtxMid->PostNotificationCount); + Success = FALSE; + } + + // + // Verify the lowest callback receives no notifications. + // Once the middle callback blocks, no callbacks at lower altitudes are + // notified. + // + + if ((CallbackCtxLow->PreNotificationCount != 0) || + (CallbackCtxLow->PostNotificationCount != 0)) { + ErrorPrint("Low Callback should have seen 0 pre and 0 post notifications."); + ErrorPrint("Low Callback actually saw %d pre and %d post notifications.", + CallbackCtxLow->PreNotificationCount, + CallbackCtxLow->PostNotificationCount); + Success = FALSE; + } + + Exit: + + if (Success) { + InfoPrint("Multiple Altitude Block During Pre Sample succeeded."); + } else { + ErrorPrint("Multiple Altitude Block During Pre Sample FAILED."); + } + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (CallbackCtxHigh != NULL) { + ExFreePoolWithTag(CallbackCtxHigh, REGFLTR_CONTEXT_POOL_TAG); + } + + if (CallbackCtxMid != NULL) { + ExFreePoolWithTag(CallbackCtxMid, REGFLTR_CONTEXT_POOL_TAG); + } + + if (CallbackCtxLow != NULL) { + ExFreePoolWithTag(CallbackCtxLow, REGFLTR_CONTEXT_POOL_TAG); + } + + return Success; +} + + +BOOLEAN +MultipleAltitudeInternalInvocationSample( + ) +/*++ + +Routine Description: + + This sample features a stack of 3 callbacks at different altitudes and + demonstrates what happens when the middle callback invokes a registry + operation. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtxHigh = NULL; + PCALLBACK_CONTEXT CallbackCtxMid = NULL; + PCALLBACK_CONTEXT CallbackCtxLow = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + BOOLEAN Success = FALSE; + + + InfoPrint(""); + InfoPrint("=== Multiple Altitude Internal Invocation Sample ===="); + + // + // Create callback contexts for the 3 callbacks. + // The high and low callbacks will only monitor how many notifications + // they receive. + // + + CallbackCtxHigh = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR, + CALLBACK_HIGH_ALTITUDE); + CallbackCtxMid = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION, + CALLBACK_ALTITUDE); + CallbackCtxLow = CreateCallbackContext(CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR, + CALLBACK_LOW_ALTITUDE); + + if ((CallbackCtxHigh == NULL) || + (CallbackCtxMid == NULL) || + (CallbackCtxLow == NULL)) { + goto Exit; + } + + // + // Register the callbacks + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxHigh->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxHigh, + &CallbackCtxHigh->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxMid->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxMid, + &CallbackCtxMid->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtxLow->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtxLow, + &CallbackCtxLow->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Create a key. When the middle callback receives the pre-notification + // and the post-notification for this create it will perform an open key + // and a close key operation. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey returned unexpected status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callbacks + // + + Status = CmUnRegisterCallback(CallbackCtxHigh->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Status = CmUnRegisterCallback(CallbackCtxMid->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Status = CmUnRegisterCallback(CallbackCtxLow->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + + // + // Verify the highest altitude callback receives one pre and one post + // notification. This callback does not get notifications for the + // registry operations called by the middle callback. + // + + if ((CallbackCtxHigh->PreNotificationCount != 1) || + (CallbackCtxHigh->PostNotificationCount != 1)) { + ErrorPrint("High Callback should have seen 1 pre and 1 post notifications."); + ErrorPrint("High Callback actually saw %d pre and %d post notifications.", + CallbackCtxHigh->PreNotificationCount, + CallbackCtxHigh->PostNotificationCount); + Success = FALSE; + } + + // + // Verify the middle callback receives one pre and one post notification. + // This callback does not get notifications for the registry operations + // that it calls. + // + + if ((CallbackCtxMid->PreNotificationCount != 1) || + (CallbackCtxMid->PostNotificationCount != 1)) { + ErrorPrint("Mid Callback should have seen 1 pre and 1 post notifications."); + ErrorPrint("Mid Callback actually saw %d pre and %d post notifications.", + CallbackCtxMid->PreNotificationCount, + CallbackCtxMid->PostNotificationCount); + Success = FALSE; + } + + // + // Verify the lowest callback receives 5 pre-notifications and 5 + // post-notifications. This callback receives 1 pre and 1 post from the + // original create key operation. It also receives 2 pre and 2 post for + // the open key and close key operations called by the middle callback + // during the pre phase of the create key and then 2 pre and 2 post again + // for the calls in the post phase of the create key. + // + + if ((CallbackCtxLow->PreNotificationCount != 5) || + (CallbackCtxLow->PostNotificationCount != 5)) { + ErrorPrint("Low Callback should have seen 5 pre and 5 post notifications."); + ErrorPrint("Low Callback actually saw %d pre and %d post notifications.", + CallbackCtxLow->PreNotificationCount, + CallbackCtxLow->PostNotificationCount); + Success = FALSE; + } + + Exit: + + if (Success) { + InfoPrint("Multiple Altitude Internal Invocation Sample succeeded."); + } else { + ErrorPrint("Multiple Altitude Internal Invocation Sample FAILED."); + } + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (CallbackCtxHigh != NULL) { + ExFreePoolWithTag(CallbackCtxHigh, REGFLTR_CONTEXT_POOL_TAG); + } + + if (CallbackCtxMid != NULL) { + ExFreePoolWithTag(CallbackCtxMid, REGFLTR_CONTEXT_POOL_TAG); + } + + if (CallbackCtxLow != NULL) { + ExFreePoolWithTag(CallbackCtxLow, REGFLTR_CONTEXT_POOL_TAG); + } + + return Success; +} + + +NTSTATUS +CallbackMonitor( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine just monitors how many pre and post registry + operations it receives and records it in the callback context. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + Always STATUS_SUCCESS + +--*/ +{ + UNREFERENCED_PARAMETER(Argument2); + + switch(NotifyClass) { + case RegNtPreDeleteKey: + case RegNtPreSetValueKey: + case RegNtPreDeleteValueKey: + case RegNtPreSetInformationKey: + case RegNtPreRenameKey: + case RegNtPreEnumerateKey: + case RegNtPreEnumerateValueKey: + case RegNtPreQueryKey: + case RegNtPreQueryValueKey: + case RegNtPreQueryMultipleValueKey: + case RegNtPreKeyHandleClose: + case RegNtPreCreateKeyEx: + case RegNtPreOpenKeyEx: + case RegNtPreFlushKey: + case RegNtPreLoadKey: + case RegNtPreUnLoadKey: + case RegNtPreQueryKeySecurity: + case RegNtPreSetKeySecurity: + case RegNtPreRestoreKey: + case RegNtPreSaveKey: + case RegNtPreReplaceKey: + InterlockedIncrement(&CallbackCtx->PreNotificationCount); + break; + case RegNtPostDeleteKey: + case RegNtPostSetValueKey: + case RegNtPostDeleteValueKey: + case RegNtPostSetInformationKey: + case RegNtPostRenameKey: + case RegNtPostEnumerateKey: + case RegNtPostEnumerateValueKey: + case RegNtPostQueryKey: + case RegNtPostQueryValueKey: + case RegNtPostQueryMultipleValueKey: + case RegNtPostKeyHandleClose: + case RegNtPostCreateKeyEx: + case RegNtPostOpenKeyEx: + case RegNtPostFlushKey: + case RegNtPostLoadKey: + case RegNtPostUnLoadKey: + case RegNtPostQueryKeySecurity: + case RegNtPostSetKeySecurity: + case RegNtPostRestoreKey: + case RegNtPostSaveKey: + case RegNtPostReplaceKey: + InterlockedIncrement(&CallbackCtx->PostNotificationCount); + break; + } + + return STATUS_SUCCESS; + +} + + +NTSTATUS +CallbackMultipleAltitude( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine first calls CallbackMonitor to record the + number of pre and post notifications received by the callback. Then it + does one of two things depending on the callback mode specified in the + callback context. + + If callback mode is CALLBACK_MODE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE: + Return STATUS_ACCESS_DENIED when we receive a pre-notification for a + create key operation. + + If callback mode is CALLBACK_MODE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION: + Call ZwOpenKey and ZwCloseKey when we receive a pre or post notification + for a create key operation. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + + NTSTATUS Status = STATUS_SUCCESS; + PVOID Object = NULL; + HANDLE ObjectHandle = NULL; + PCUNICODE_STRING ObjectName = NULL; + UNICODE_STRING CapturedObjectName = {0}; + OBJECT_ATTRIBUTES KeyAttributes = {0}; + PREG_POST_OPERATION_INFORMATION PostInfo; + + CallbackMonitor(CallbackCtx, NotifyClass, Argument2); + + if(CallbackCtx->CallbackMode == CALLBACK_MODE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE) { + switch(NotifyClass) { + case RegNtPreSetValueKey: + case RegNtPreCreateKeyEx: + InfoPrint("\tCallback: CreateKey/SetValueKey blocked."); + Status = STATUS_ACCESS_DENIED; + break; + default: + // + // Do nothing for other notifications + // + break; + } + } + + if (CallbackCtx->CallbackMode == CALLBACK_MODE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION) { + + // + // Get the Object that we will open and close. + // + + switch(NotifyClass) { + case RegNtPreCreateKeyEx: + Object = ((PREG_CREATE_KEY_INFORMATION) Argument2)->RootObject; + + // + // RootObject should never be NULL. + // + + ASSERT(Object != NULL); + + break; + + case RegNtPostCreateKeyEx: + + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + + // + // Make sure the operation is successful so far. + // + + if (!NT_SUCCESS(PostInfo->Status)) { + ErrorPrint("Post notification status is unexpectedly 0x%x.", + PostInfo->Status); + break; + } + + // + // If the operation si successful so far, PostInfo->Object should + // not be NULL. However, a misbehaving registry filter driver + // can make this NULL so we do not ASSERT here as we do in the + // pre-notification case. + // + + Object = PostInfo->Object; + if (Object == NULL) { + ErrorPrint("PostInfo->Object is unexpectedly null in RegNtPostCreateKeyEx."); + ErrorPrint("PostInfo->Status is 0x%x", + PostInfo->Status); + } + + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + + if (Object != NULL) { + + // + // Use CmCallbackGetKeyObjectID to get the absolute path to Object. + // + +#if (NTDDI_VERSION >= NTDDI_WIN8) + + // + // In Windows 8, CmCallbackGetKeyObjectIDEx was added to give + // developers a copy of the object name rather than the actual + // object name string. This is a safer programming approach and + // allows the system to safely clean up the old object name in + // operations like renaming the key. + // + // Call CmCallbackReleaseKeyObjectIDEx to release the object name + // returned by CmCallbackGetKeyObjectIDEx. + // + + Status = CmCallbackGetKeyObjectIDEx(&CallbackCtx->Cookie, + Object, + NULL, + &ObjectName, + 0); // Flag: reserved for future + + if (!NT_SUCCESS (Status)) { + ErrorPrint("CmCallbackGetKeyObjectIDEx failed. Status 0x%x", Status); + goto Exit; + } + + CapturedObjectName.Length = ObjectName->Length; + CapturedObjectName.MaximumLength = ObjectName->MaximumLength; + CapturedObjectName.Buffer = ObjectName->Buffer; + +#else + + Status = CmCallbackGetKeyObjectID(&CallbackCtx->Cookie, + Object, + NULL, + &ObjectName); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("CmCallbackGetKeyObjectID failed. Status 0x%x", Status); + goto Exit; + } + + // + // The UNICODE_STRING referenced by ObjectName from + // CmCallbackGetKeyObjectID must not be changed. If you need to + // modify the string, create a copy. + // + // Although this sample does not change the path, we show the + // code to capture the string for demonstration purposes. + // + + Status = CaptureUnicodeString(&CapturedObjectName, ObjectName, + REGFLTR_CAPTURE_POOL_TAG); + + if (!NT_SUCCESS(Status)) { + goto Exit; + } + +#endif //NTDDI_VERSION >= NTDDI_WIN8 + + + InitializeObjectAttributes(&KeyAttributes, + &CapturedObjectName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + InfoPrint("\tCallback: Internal Invocation of ZwOpenKey"); + Status = ZwOpenKey(&ObjectHandle, + KEY_ALL_ACCESS, + &KeyAttributes); + if (!NT_SUCCESS (Status)) { + ErrorPrint("ZwOpenKey failed. Status 0x%x", Status); + } else { + InfoPrint("\tCallback: Internal Invocation of ZwCloseKey"); + ZwClose(ObjectHandle); + } + +#if (NTDDI_VERSION >= NTDDI_WIN8) + + CmCallbackReleaseKeyObjectIDEx(ObjectName); + +#else + + FreeCapturedUnicodeString(&CapturedObjectName, REGFLTR_CAPTURE_POOL_TAG); + +#endif //NTDDI_VERSION >= NTDDI_WIN8 + + } + } + + Exit: + + return Status; +} + + diff --git a/general/registry/regfltr/sys/post.c b/general/registry/regfltr/sys/post.c new file mode 100644 index 00000000..bff979fe --- /dev/null +++ b/general/registry/regfltr/sys/post.c @@ -0,0 +1,768 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Post.c + +Abstract: + + Samples that show what callbacks can do during the post-notification + phase. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +/*++ + + In registry callback version 1.0, there is a bug with post-notification + processing and multiple registry filter drivers that can break the samples + here. It is fixed with version 1.1. + + The bug occurs when a driver blocks or bypasses a registry operation in the + pre-notification phase. Even though the processing of the operation stops + there, registry filter drivers registered at higher altitudes will still + get a post-notification for the operation. If the higher altitude driver + tries to change the status of the operation from failure to success or + vice versa, this change will be ignored and the status returned + will be the status returned by the driver who bypassed or blocked the + operation during the pre-notification phase. + + For more information on how notification processing works with multiple + registry filter drivers registered see MultiAlt.c + + For more information on issues in version 1.0 and changes in version 1.1 + see Version.c + + + Beginning with Windows 8.1, it is no longer possible to pass the object + provided to a RegNtPostCreateKeyEx or RegNtPostOpenKeyEx callout to + ObOpenObjectByPointer. To work around this, filters should perform all + create key or open key processing in a RegNtPreCreateKeyEx or + RegNtPreOpenKeyEx callout. If for any reason the desired processing cannot + be performed in a RegNtPreCreateKeyEx or RegNtPreOpenKeyEx callout, then + use CmSetCallbackObjectContext to tag a newly-created or newly-opened key + as unprocessed and process it in the pre-operation callback for a + subsequent operation. + +--*/ + + + +BOOLEAN +PostNotificationOverrideSuccessSample( + ) +/*++ + +Routine Description: + + This sample shows how registry callbacks can fail a registry operation + in the post-notification phase. + + Two values are created. The creates normally should succeeded, but one + is intercepted by the callback and failed with STATUS_ACCESS_DENIED. + + NOTE: This sample does not take into account transactions. See txr.c for + examples on how to handle transactional registry operations. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + UNICODE_STRING Name; + DWORD ValueData = 0; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Post-Notification Override Success Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_SUCCESS, + CALLBACK_ALTITUDE); + + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Set two values. + // Setting the "not modified" value will succeed. + // Setting the other value will fail with file not found. + // + + RtlInitUnicodeString(&Name, NOT_MODIFIED_VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue return unexpected status 0x%x", Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwSetValue return unexpected status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + + // + // Verify that the set value calls were failed by + // checking that the value with VALUE_NAME does not + // exist. + // + // Deleting the other value should return STATUS_OBJECT_NAME_NOT_FOUND + // Deleting value with the modified name should succeed. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwDeleteValueKey(g_RootKey, &Name); + + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwDeleteValueKey on value failed. Status: 0x%x", Status); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + RtlInitUnicodeString(&Name, NOT_MODIFIED_VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Post-Notification Override Success Sample succeeded."); + } else { + ErrorPrint("Post-Notification Override Success Sample FAILED."); + } + return Success; + +} + + +NTSTATUS +CallbackPostNotificationOverrideSuccess( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine intercepts create key and set value post + notifications and fails the operation with STATUS_ACCESS_DENIED. + + NOTE: This sample does not take into account transactions. See txr.c for + examples on how to handle transactional registry operations. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + + NTSTATUS Status = STATUS_SUCCESS; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + PREG_SET_VALUE_KEY_INFORMATION PreSetValueInfo; + PREG_POST_OPERATION_INFORMATION PostInfo; + UNICODE_STRING Name; + HANDLE Key = NULL; + + UNREFERENCED_PARAMETER(CallbackCtx); + + switch(NotifyClass) { + case RegNtPostCreateKeyEx: + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) PostInfo->PreInformation; + + // + // REG_CREATE_KEY_INFORMATION is a partially captured + // structure however no uncaptured fields are used here. For more + // information on what parameters need to be captured, see + // capture.c. + // + + // + // Only intercept the operation if the key being created has the + // name KEY_NAME. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + if (!RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreCreateInfo->CompleteName, + TRUE)) { + break; + } + + // + // Make sure the operation is successful so far. + // + + if (!NT_SUCCESS(PostInfo->Status)) { + ErrorPrint("Operation status in post notification is unexpectedly 0x%x", + PostInfo->Status); + break; + } + + // + // Since this is the post-notification phase, the key has + // already been created. It is stored in PostInfo->Object. + // Get a handle on the key and delete it. + // + + Status = ObOpenObjectByPointer(PostInfo->Object, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + PreCreateInfo->ObjectType, + KernelMode, + &Key); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x\n", Status); + break; + } + + Status = ZwDeleteKey(Key); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwDeleteKey failed. Status 0x%x\n", Status); + break; + } + + ZwClose(Key); + + // + // Dereference the object because it will not be returned to + // the user. NULL out the references to the object in the + // post and pre information structures. + // + + ObDereferenceObject(PostInfo->Object); + PostInfo->Object = NULL; + *PreCreateInfo->ResultObject = NULL; + + InfoPrint("\tCallback: Create key %wZ overrided from success to error.", + PreCreateInfo->CompleteName); + + // + // Put the status to be returned in PostInfo->ReturnStatus and + // return STATUS_CALLBACK_BYPASS to let CM know that + // we want to change the return status. + // + // DO NOT set PostInfo->Status + // + + PostInfo->ReturnStatus = STATUS_ACCESS_DENIED; + Status = STATUS_CALLBACK_BYPASS; + break; + + case RegNtPostSetValueKey: + + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + PreSetValueInfo = (PREG_SET_VALUE_KEY_INFORMATION) PostInfo->PreInformation; + + // + // NOTE: REG_SET_VALUE_KEY_INFORMATION is a partially captured + // structure. The value name is captured but the data buffer is + // not. Since we are only using the value name we do not need to + // capture any parameters. For more information on what parameters + // need to be captured, see capture.c. + // + + // + // Only intercept the operation if the value being set has the + // name VALUE_NAME. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + if (!RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreSetValueInfo->ValueName, + TRUE)) { + break; + } + + // + // Make sure the operation is successful so far. + // + + if (!NT_SUCCESS(PostInfo->Status)) { + ErrorPrint("Post notification status is unexpectedly 0x%x.", + PostInfo->Status); + break; + } + + // + // To fail the operation, we have to delete the value that has + // been created. To do so, we need a handle to the root key. + // + + Status = ObOpenObjectByPointer(PreSetValueInfo->Object, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + NULL, + KernelMode, + &Key); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x\n", Status); + break; + } + + Status = ZwDeleteValueKey(Key, PreSetValueInfo->ValueName); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwDeleteValueKey failed. Status 0x%x\n", Status); + break; + } + + ZwClose(Key); + + // + // Put the status to be returned in PostInfo->ReturnStatus and + // return STATUS_CALLBACK_BYPASS to let CM know that + // we want to change the return status. + // + // DO NOT set PostInfo->Status + // + + InfoPrint("\tCallback: Value %wZ overrided from success to error.", + PreSetValueInfo->ValueName); + PostInfo->ReturnStatus = STATUS_ACCESS_DENIED; + Status = STATUS_CALLBACK_BYPASS; + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; + +} + + +BOOLEAN +PostNotificationOverrideErrorSample( + ) +/*++ + +Routine Description: + + This sample shows how a registry callback can change a failed registry + operation into a successful operation in the post-notification phase. + + A key that does not exist is opened. The opens should fail, but it is + intercepted by the callback and the open is redirected to a key that + does exist. + + NOTE: This sample does not take into account transactions. See txr.c for + examples on how to handle transactional registry operations. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + BOOLEAN Success = FALSE; + HANDLE Key = NULL; + HANDLE ModifiedKey = NULL; + + InfoPrint(""); + InfoPrint("=== Post-Notification Override Error Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_ERROR, + CALLBACK_ALTITUDE); + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Create a key with name MODIFIED_KEY_NAME + // + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&ModifiedKey, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("Creating modified key failed. Status 0x%x", Status); + goto Exit; + } + + // + // Now try to open a key by KEY_NAME which does not exist. Verify that + // this fails. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwCreateKey returned unexpected status 0x%x", Status); + goto Exit; + } + + // + // Register our callback with the context + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Open key again. The callback will intercept this and make it succeed. + // + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKey failed unexpectedly. Status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (ModifiedKey != NULL) { + ZwDeleteKey(ModifiedKey); + ZwClose(ModifiedKey); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Post-Notification Override Error Sample succeeded."); + } else { + ErrorPrint("Post-Notification Override Error Sample FAILED."); + } + + return Success; +} + + +NTSTATUS +CallbackPostNotificationOverrideError( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine intercepts open key post notifications + and if they are failing with STATUS_ACCESS_DENIED, it makes + the operation successful by redirecting the open to antoher key. + + NOTE: This sample does not take into account transactions. See txr.c for + examples on how to handle transactional registry operations. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_OPEN_KEY_INFORMATION PreOpenInfo; + PREG_POST_OPERATION_INFORMATION PostInfo; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES KeyAttributes; + HANDLE Key = NULL; + HANDLE RootKey = NULL; + PVOID Object; + + UNREFERENCED_PARAMETER(CallbackCtx); + + switch(NotifyClass) { + case RegNtPostOpenKeyEx: + + PostInfo = (PREG_POST_OPERATION_INFORMATION) Argument2; + PreOpenInfo = (PREG_OPEN_KEY_INFORMATION) PostInfo->PreInformation; + + // + // NOTE: REG_OPEN_KEY_INFORMATION is a fully captured structure + // so there is no need for the callback to capture any parameters. + // For more information on what parameters need to be captured, see + // capture.c. + // + + // + // Only intercept the operation if the key being created has the + // name KEY_NAME. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + if (!RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreOpenInfo->CompleteName, + TRUE)) { + break; + } + + // + // Verify that operation is currently failing as expected + // + + if (PostInfo->Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("Operation did not fail with status not found as expected. Post status: 0x%x", + PostInfo->Status); + break; + } + + // + // To make the operation successful, an object MUST be supplied as + // the opened handle. In this sample, the object will be a handle + // to another key that does exist. + // + + // + // First open the key and get its handle. + // + + Status = ObOpenObjectByPointer(PreOpenInfo->RootObject, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + PreOpenInfo->ObjectType, + KernelMode, + &RootKey); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + break; + } + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + RootKey, + PreOpenInfo->SecurityDescriptor); + + Status = ZwOpenKey(&Key, + PreOpenInfo->DesiredAccess, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKey failed. Status 0x%x", Status); + ZwClose(RootKey); + break; + } + + ZwClose(RootKey); + + // + // Then, get the object pointer from the new key's handle. + // + + Status = ObReferenceObjectByHandle(Key, + PreOpenInfo->DesiredAccess, + PreOpenInfo->ObjectType, + KernelMode, + &Object, + NULL); + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObReferenceObjectByHandle failed. Status 0x%x", Status); + ZwClose(Key); + break; + } + + // + // Finally, set the ResultObject field in the PreInfo and + // the Object field in the PostInfo to the object just opened. + // + + *PreOpenInfo->ResultObject = Object; + PreOpenInfo->GrantedAccess = PreOpenInfo->DesiredAccess; + + if (PostInfo->Object != NULL) { + ErrorPrint("PostInfo->Object should be NULL! Instead is 0x%p", + PostInfo->Object); + } + PostInfo->Object = Object; + + ZwClose(Key); + InfoPrint("\tCallback: Opening key %wZ overrided from error to success.", + PreOpenInfo->CompleteName); + + // + // Put the status to be returned in PostInfo->ReturnStatus and + // return STATUS_CALLBACK_BYPASS to let CM know that + // we want to change the return status. + // + // DO NOT set PostInfo->Status + // + + PostInfo->ReturnStatus = STATUS_SUCCESS; + Status = STATUS_CALLBACK_BYPASS; + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; + +} + diff --git a/general/registry/regfltr/sys/pre.c b/general/registry/regfltr/sys/pre.c new file mode 100644 index 00000000..0cc895c9 --- /dev/null +++ b/general/registry/regfltr/sys/pre.c @@ -0,0 +1,799 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Pre.c + +Abstract: + + Samples that show what callbacks can do during the pre-notification + phase. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +BOOLEAN +PreNotificationBlockSample( + ) +/*++ + +Routine Description: + + This sample shows how to block a registry operation in the + pre-notification phase. + + Two keys are created. The create operations should succeed, but one + is intercepted by the callback and failed with STATUS_ACCESS_DENIED. + The same is done for two values. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + HANDLE NotModifiedKey = NULL; + DWORD ValueData = 0; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Pre-Notification Block Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_PRE_NOTIFICATION_BLOCK, + CALLBACK_ALTITUDE); + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Create two keys. + // Creating the "not modified" key will succeed. + // Creating the other key will fail with STATUS_ACCESS_DENIED + // + + RtlInitUnicodeString(&Name, NOT_MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&NotModifiedKey, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (Status != STATUS_SUCCESS) { + ErrorPrint("ZwCreateKey returned unexpected status 0x%x", Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwCreateKey returned unexpected status 0x%x", Status); + Success = FALSE; + } + + + // + // Set two values. + // Setting the "not modified" value will succeed. + // Setting the other value will fail with STATUS_ACCESS_DENIED. + // + + RtlInitUnicodeString(&Name, NOT_MODIFIED_VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(Status != STATUS_SUCCESS) { + ErrorPrint("ZwSetValue return unexpected status 0x%x", Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwSetValue return unexpected status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (NotModifiedKey != NULL) { + ZwDeleteKey(NotModifiedKey); + ZwClose(NotModifiedKey); + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + RtlInitUnicodeString(&Name, NOT_MODIFIED_VALUE_NAME); + ZwDeleteValueKey(g_RootKey, &Name); + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Pre-Notification Block Sample succeeded."); + } else { + ErrorPrint("Pre-Notification Block Sample FAILED."); + } + + return Success; + +} + + +NTSTATUS +CallbackPreNotificationBlock( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine shows hot to fail a registry operation + in the pre-notification phase. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + PREG_SET_VALUE_KEY_INFORMATION PreSetValueInfo; + UNICODE_STRING Name; + + UNREFERENCED_PARAMETER(CallbackCtx); + + switch(NotifyClass) { + case RegNtPreCreateKeyEx: + + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) Argument2; + + // + // Only intercept the operation if the key being created has the + // name KEY_NAME. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + if (RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreCreateInfo->CompleteName, + TRUE)) { + // + // By returning an error status, we block the operation. + // + + InfoPrint("\tCallback: Create key %wZ blocked.", + PreCreateInfo->CompleteName); + Status = STATUS_ACCESS_DENIED; + } + break; + + case RegNtPreSetValueKey: + + PreSetValueInfo = (PREG_SET_VALUE_KEY_INFORMATION) Argument2; + + // + // Only intercept the operation if the value being set has the + // name VALUE_NAME. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + if (RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreSetValueInfo->ValueName, + TRUE)) { + // + // By returning an error status, we block the operation. + // + + InfoPrint("\tCallback: Set value %wZ blocked.", + PreSetValueInfo->ValueName); + Status = STATUS_ACCESS_DENIED; + } + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; +} + + + +BOOLEAN +PreNotificationBypassSample( + ) +/*++ + +Routine Description: + + This sample shows how to bypass a registry operation so that the CM does + not process the operation. Unlike block, an operation that is bypassed + is still considered successful so the callback must provide the caller + with what the CM would have provided. + + A key and a value are created. However both operations are bypassed by the + callback so that the key and value actually created have different names + than would is expected. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + DWORD ValueData = 0; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Pre-Notification Bypass Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_PRE_NOTIFICATION_BYPASS, + CALLBACK_ALTITUDE); + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register the callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Create a key and set a value. Both should succeed + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwSetValueKey(g_RootKey, + &Name, + 0, + REG_DWORD, + &ValueData, + sizeof(ValueData)); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + + // + // Check that a key with the expected name KEY_NAME cannot be found + // but a key with the "modified" name can be found. + // + + if (Key != NULL) { + ZwClose(Key); + } + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwOpenKey on key returned unexpected status: 0x%x", Status); + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + Key = NULL; + } + Success = FALSE; + } + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKey on modified key path failed. Status: 0x%x", Status); + Success = FALSE; + } + + + // + // Do the same check by trying to delete a value with VALUE_NAME and + // with the "modified" name. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + Status = ZwDeleteValueKey(g_RootKey, &Name); + + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwDeleteValueKey on original value returned unexpected status: 0x%x", + Status); + Success = FALSE; + } + + RtlInitUnicodeString(&Name, MODIFIED_VALUE_NAME); + Status = ZwDeleteValueKey(g_RootKey, &Name); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwDeleteValueKey on modified value failed. Status: 0x%x", + Status); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Pre-Notification Bypass Sample succeeded."); + } else { + ErrorPrint("Pre-Notification Bypass Sample FAILED."); + } + + return Success; +} + + + +NTSTATUS +CallbackPreNotificationBypass( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 +) +/*++ + +Routine Description: + + This helper callback routine is the most complex part of the sample. + Here we actually manipulate the registry inside the callback to modify the + outcome and the behavior of the registry operation. + + In the pre-notification phase, we bypass the call but create a key or set + a value with a different name. + + In the post-notification phase we delete the key or value that was + created by the registry and tell the registry to return the bad error + status to the caller. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + + NTSTATUS Status = STATUS_SUCCESS; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + PREG_SET_VALUE_KEY_INFORMATION PreSetValueInfo; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + UNICODE_STRING LocalClass = {0}; + PUNICODE_STRING Class = NULL; + HANDLE Key = NULL; + HANDLE RootKey = NULL; + PVOID Object; + PVOID LocalData = NULL; + PVOID Data = NULL; + KPROCESSOR_MODE Mode = KernelMode; + + + UNREFERENCED_PARAMETER(CallbackCtx); + + switch(NotifyClass) { + + case RegNtPreCreateKeyEx: + + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) Argument2; + + // + // Only intercept the operation if the key being created has the + // name KEY_NAME. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + if (!RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreCreateInfo->CompleteName, + TRUE)) { + break; + } + + // + // REG_CREATE_KEY_INFORMATION is a partially structure. The class + // field's buffer is not captured. Since it is passed to + // ZwCreateKey, it needs to be captured. + // + // *Note: in Windows 8 all fields are captured. See capture.c + // for more details. + // + + Mode = ExGetPreviousMode(); + + if (!g_IsWin8OrGreater && Mode == UserMode) { + Status = CaptureUnicodeString(&LocalClass, + PreCreateInfo->Class, + REGFLTR_CAPTURE_POOL_TAG); + if (!NT_SUCCESS(Status)) { + break; + } + Class = &LocalClass; + + } else { + Class = PreCreateInfo->Class; + } + + + // + // Next we create a key with a modified name. + // + + Status = ObOpenObjectByPointer(PreCreateInfo->RootObject, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + PreCreateInfo->ObjectType, + KernelMode, + &RootKey); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + break; + } + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + RootKey, + PreCreateInfo->SecurityDescriptor); + + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + Class, + PreCreateInfo->CreateOptions, + PreCreateInfo->Disposition); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + ZwClose(RootKey); + break; + } + + ZwClose(RootKey); + + // + // The we get an object pointer from the new key's handle. + // + + Status = ObReferenceObjectByHandle(Key, + PreCreateInfo->DesiredAccess, + PreCreateInfo->ObjectType, + KernelMode, + &Object, + NULL); + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObReferenceObjectByHandle failed. Status 0x%x", Status); + ZwClose(Key); + break; + } + + ZwClose(Key); + + // + // Set the ResultObject field to the new key object. + // + + *PreCreateInfo->ResultObject = Object; + + // + // Return STATUS_CALLBACK_BYPASS to let CM know we want to bypass + // CM and return STATUS_SUCCESS back to the caller. + // + + InfoPrint("\tCallback: Create key %wZ bypassed.", PreCreateInfo->CompleteName); + Status = STATUS_CALLBACK_BYPASS; + break; + + case RegNtPreSetValueKey: + + PreSetValueInfo = (PREG_SET_VALUE_KEY_INFORMATION) Argument2; + + // + // REG_SET_VALUE_KEY_INFORMATION is a partially captured structure. + // The value name is captured but the data is not. Since we are + // passing the data to a zw* method, we need to capture it. + // + // *Note: in Windows 8 all fields are captured. See capture.c + // for more details. + // + + Mode = ExGetPreviousMode(); + + if (!g_IsWin8OrGreater && Mode == UserMode) { + Status = CaptureBuffer(&LocalData, + PreSetValueInfo->Data, + PreSetValueInfo->DataSize, + REGFLTR_CAPTURE_POOL_TAG); + if (!NT_SUCCESS(Status)) { + break; + } + Data = LocalData; + } else { + Data = PreSetValueInfo->Data; + } + + // + // Only intercept the operation if the value being set has the + // name VALUE_NAME. + // + + RtlInitUnicodeString(&Name, VALUE_NAME); + if (!RtlEqualUnicodeString((PCUNICODE_STRING) &Name, + (PCUNICODE_STRING) PreSetValueInfo->ValueName, + TRUE)) { + break; + } + + // + // Get a handle to the root key the value is being created under. + // This is in PreInfo->Object. + // + + Status = ObOpenObjectByPointer(PreSetValueInfo->Object, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + NULL, + KernelMode, + &RootKey); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + break; + } + + // + // Set a value with the "modified" name. + // + + RtlInitUnicodeString(&Name, MODIFIED_VALUE_NAME); + Status = ZwSetValueKey(RootKey, + &Name, + 0, + PreSetValueInfo->Type, + Data, + PreSetValueInfo->DataSize); + + if(!NT_SUCCESS(Status)) { + ErrorPrint("ZwSetValue failed. Status 0x%x", + Status); + ZwClose(RootKey); + break; + } + + // + // Finally return STATUS_CALLBACK_BYPASS to tell the registry + // not to proceed with the original registry operation and to return + // STATUS_SUCCESS to the caller. + // + + InfoPrint("\tCallback: Set value %wZ bypassed.", PreSetValueInfo->ValueName); + Status = STATUS_CALLBACK_BYPASS; + ZwClose(RootKey); + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + // + // Free buffers used for capturing user mode values. + // + + if (LocalClass.Buffer != NULL) { + FreeCapturedUnicodeString(&LocalClass, REGFLTR_CAPTURE_POOL_TAG); + } + + if (LocalData != NULL) { + FreeCapturedBuffer(LocalData, REGFLTR_CAPTURE_POOL_TAG); + } + + return Status; +} + + diff --git a/general/registry/regfltr/sys/regfltr.c b/general/registry/regfltr/sys/regfltr.c new file mode 100644 index 00000000..5cd85c6c --- /dev/null +++ b/general/registry/regfltr/sys/regfltr.c @@ -0,0 +1,871 @@ +/*++
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+ THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+Module Name:
+
+ regfltr.c
+
+Abstract:
+
+ Sample driver used to run the kernel mode registry callback samples.
+
+Environment:
+
+ Kernel mode only
+
+--*/
+
+#include "regfltr.h"
+
+
+//
+// The root key used in the samples
+//
+HANDLE g_RootKey;
+
+
+
+LPCWSTR
+GetTransactionNotifyClassString (
+ _In_ ULONG TransactionNotifcation
+ );
+
+LPCWSTR
+GetNotifyClassString (
+ _In_ REG_NOTIFY_CLASS NotifyClass
+ );
+
+VOID
+DeleteTestKeys(
+ );
+
+
+
+NTSTATUS
+Callback (
+ _In_ PVOID CallbackContext,
+ _In_opt_ PVOID Argument1,
+ _In_opt_ PVOID Argument2
+)
+/*++
+
+Routine Description:
+
+ This is the registry callback we'll register to intercept all registry
+ operations.
+
+Arguments:
+
+ CallbackContext - The value that the driver passed to the Context parameter
+ of CmRegisterCallbackEx when it registers this callback routine.
+
+ Argument1 - A REG_NOTIFY_CLASS typed value that identifies the type of
+ registry operation that is being performed and whether the callback
+ is being called in the pre or post phase of processing.
+
+ Argument2 - A pointer to a structure that contains information specific
+ to the type of the registry operation. The structure type depends
+ on the REG_NOTIFY_CLASS value of Argument1. Refer to MSDN for the
+ mapping from REG_NOTIFY_CLASS to REG_XXX_KEY_INFORMATION.
+
+Return Value:
+
+ Status returned from the helper callback routine or STATUS_SUCCESS if
+ the registry operation did not originate from this process.
+
+--*/
+{
+
+ NTSTATUS Status = STATUS_SUCCESS;
+ REG_NOTIFY_CLASS NotifyClass;
+ PCALLBACK_CONTEXT CallbackCtx;
+
+ CallbackCtx = (PCALLBACK_CONTEXT)CallbackContext;
+ NotifyClass = (REG_NOTIFY_CLASS)(ULONG_PTR)Argument1;
+
+ //
+ // Ignore registry activity from other processes. If this callback
+ // wasn't registered by the current process, simply return success.
+ //
+
+ if (CallbackCtx->ProcessId != PsGetCurrentProcessId()) {
+ return STATUS_SUCCESS;
+ }
+
+ InfoPrint("\tCallback: Altitude-%S, NotifyClass-%S.",
+ CallbackCtx->AltitudeBuffer,
+ GetNotifyClassString(NotifyClass));
+
+ //
+ // Invoke a helper method depending on the value of CallbackMode in
+ // CallbackCtx.
+ //
+
+ if (Argument2 == NULL) {
+
+ //
+ // This should never happen but the sal annotation on the callback
+ // function marks Argument 2 as opt and is looser than what
+ // it actually is.
+ //
+
+ ErrorPrint("\tCallback: Argument 2 unexpectedly 0. Filter will "
+ "abort and return success.");
+ return STATUS_SUCCESS;
+ }
+
+ switch (CallbackCtx->CallbackMode) {
+ case CALLBACK_MODE_PRE_NOTIFICATION_BLOCK:
+ Status = CallbackPreNotificationBlock(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_PRE_NOTIFICATION_BYPASS:
+ Status = CallbackPreNotificationBypass(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_SUCCESS:
+ Status = CallbackPostNotificationOverrideSuccess(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_POST_NOTIFICATION_OVERRIDE_ERROR:
+ Status = CallbackPostNotificationOverrideError(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_TRANSACTION_ENLIST:
+ Status = CallbackTransactionEnlist(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_TRANSACTION_REPLAY:
+ Status = CallbackTransactionReplay(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_SET_OBJECT_CONTEXT:
+ Status = CallbackSetObjectContext(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_SET_CALL_CONTEXT:
+ Status = CallbackSetCallContext(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_MULTIPLE_ALTITUDE_MONITOR:
+ Status = CallbackMonitor(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE:
+ case CALLBACK_MODE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION:
+ Status = CallbackMultipleAltitude(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_CAPTURE:
+ Status = CallbackCapture(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_VERSION_BUGCHECK:
+ Status = CallbackBugcheck(CallbackCtx, NotifyClass, Argument2);
+ break;
+ case CALLBACK_MODE_VERSION_CREATE_OPEN_V1:
+ Status = CallbackCreateOpenV1(CallbackCtx, NotifyClass, Argument2);
+ break;
+ default:
+ ErrorPrint("Unknown Callback Mode: %d", CallbackCtx->CallbackMode);
+ Status = STATUS_INVALID_PARAMETER;
+ }
+
+
+ return Status;
+
+}
+
+
+NTSTATUS
+RMCallback(
+ _In_ PKENLISTMENT EnlistmentObject,
+ _In_ PVOID RMContext,
+ _In_ PVOID TransactionContext,
+ _In_ ULONG TransactionNotification,
+ _Inout_ PLARGE_INTEGER TMVirtualClock,
+ _In_ ULONG ArgumentLength,
+ _In_ PVOID Argument
+ )
+/*++
+
+Routine Description:
+
+ This callback recieves transaction notifications.
+
+Arguments:
+
+ EnlistmentObject - Enlistment that this notification is about
+
+ RMContext - The value specified for the RMKey parameter of the
+ TmEnableCallbacks routine
+
+ TransactionContext - Value specified for the EnlistmentKey parameter
+ of the ZwCreateEnlistment routine
+
+ TransactionNotification - Type of notification
+
+ TmVirtualClock - Pointer to virtual clock value of time when KTM prepared
+ the notification.
+
+ ArgumentLength - Length in bytes of the Argument buffer.
+
+ Argument - Buffer containing notification-spcefic arguments.
+
+Return Value:
+
+ Always STATUS_SUCCESS
+
+--*/
+{
+ PRMCALLBACK_CONTEXT Context = (PRMCALLBACK_CONTEXT) TransactionContext;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ UNREFERENCED_PARAMETER(EnlistmentObject);
+ UNREFERENCED_PARAMETER(RMContext);
+ UNREFERENCED_PARAMETER(ArgumentLength);
+ UNREFERENCED_PARAMETER(Argument);
+
+ InfoPrint("\tRMCallback: NotifyClass-%S.",
+ GetTransactionNotifyClassString(TransactionNotification));
+
+ //
+ // Transaction notifications are bit masks. Record which one(s)
+ // this callback received.
+ //
+
+ Context->Notification |= TransactionNotification;
+
+ //
+ // Call the Tm*Complete methods to inform KTM that we have completed
+ // processing. (Note: It is possible to use the Zw version of
+ // these APIs as well).
+ //
+ // Make sure that all the notifications you request are handled. The
+ // type of notification this routine gets is specified when you enlist
+ // in a transaction.
+ //
+
+ switch(TransactionNotification) {
+ case TRANSACTION_NOTIFY_COMMIT:
+ Status = TmCommitComplete(EnlistmentObject,
+ TMVirtualClock);
+ break;
+ case TRANSACTION_NOTIFY_ROLLBACK:
+ Status = TmRollbackComplete(EnlistmentObject,
+ TMVirtualClock);
+ break;
+ default:
+ ErrorPrint("Unsupported Transaction Notification: %x",
+ TransactionNotification);
+ NT_ASSERT(FALSE);
+ }
+
+ //
+ // It is safe to close the enlistment handle here.
+ // Closing it before the transaction aborts or commits will abort
+ // the transaction.
+ //
+
+ if (Context->Enlistment != NULL) {
+ ZwClose(Context->Enlistment);
+ Context->Enlistment = NULL;
+ }
+
+ return Status;
+
+}
+
+
+
+NTSTATUS
+DoCallbackSamples(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ This routine creates the root test key and then invokes the sample.
+ It records the results of each sample in an array that it returns to
+ the usermode program.
+
+Arguments:
+
+ DeviceObject - The device object receiving the request.
+
+ Irp - The request packet.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS Status;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG OutputBufferLength;
+ PDO_KERNELMODE_SAMPLES_OUTPUT Output;
+ UNICODE_STRING KeyPath;
+ OBJECT_ATTRIBUTES KeyAttributes;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ //
+ // Get the output buffer from the irp and check it is as large as expected.
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (OutputBufferLength < sizeof (DO_KERNELMODE_SAMPLES_OUTPUT)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ Output = (PDO_KERNELMODE_SAMPLES_OUTPUT) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Clean up test keys in case the sample terminated uncleanly.
+ //
+
+ DeleteTestKeys();
+
+ //
+ // Create the root key and the modified root key
+ //
+
+ RtlInitUnicodeString(&KeyPath, ROOT_KEY_ABS_PATH);
+ InitializeObjectAttributes(&KeyAttributes,
+ &KeyPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ Status = ZwCreateKey(&g_RootKey,
+ KEY_ALL_ACCESS,
+ &KeyAttributes,
+ 0,
+ NULL,
+ 0,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("ZwCreateKey failed. Status 0x%x", Status);
+ return Status;
+ }
+
+ //
+ // Call each demo and record the results in the Output->SampleResults
+ // array
+ //
+
+ Output->SampleResults[KERNELMODE_SAMPLE_PRE_NOTIFICATION_BLOCK] =
+ PreNotificationBlockSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_PRE_NOTIFICATION_BYPASS] =
+ PreNotificationBypassSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_SUCCESS] =
+ PostNotificationOverrideSuccessSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_POST_NOTIFICATION_OVERRIDE_ERROR] =
+ PostNotificationOverrideErrorSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_TRANSACTION_ENLIST] =
+ TransactionEnlistSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_TRANSACTION_REPLAY] =
+ TransactionReplaySample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_SET_CALL_CONTEXT] =
+ SetObjectContextSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_SET_OBJECT_CONTEXT] =
+ SetCallContextSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_BLOCK_DURING_PRE] =
+ MultipleAltitudeBlockDuringPreSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_MULTIPLE_ALTITUDE_INTERNAL_INVOCATION] =
+ MultipleAltitudeInternalInvocationSample();
+
+ Output->SampleResults[KERNELMODE_SAMPLE_VERSION_CREATE_OPEN_V1] =
+ CreateOpenV1Sample();
+
+ Irp->IoStatus.Information = sizeof(DO_KERNELMODE_SAMPLES_OUTPUT);
+
+ Exit:
+
+ if (g_RootKey) {
+ ZwDeleteKey(g_RootKey);
+ ZwClose(g_RootKey);
+ }
+
+ InfoPrint("");
+ InfoPrint("Kernel Mode Samples End");
+ InfoPrint("");
+
+ return Status;
+}
+
+
+NTSTATUS
+RegisterCallback(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Registers a callback with the specified callback mode and altitude
+
+Arguments:
+
+ DeviceObject - The device object receiving the request.
+
+ Irp - The request packet.
+
+Return Value:
+
+ Status from CmRegisterCallbackEx
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG InputBufferLength;
+ ULONG OutputBufferLength;
+ PREGISTER_CALLBACK_INPUT RegisterCallbackInput;
+ PREGISTER_CALLBACK_OUTPUT RegisterCallbackOutput;
+ PCALLBACK_CONTEXT CallbackCtx = NULL;
+
+ //
+ // Get the input and output buffer from the irp and
+ // check they are the expected size
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
+ OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if ((InputBufferLength < sizeof(REGISTER_CALLBACK_INPUT)) ||
+ (OutputBufferLength < sizeof (REGISTER_CALLBACK_OUTPUT))) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ RegisterCallbackInput = (PREGISTER_CALLBACK_INPUT) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Create the callback context from the specified callback mode and altitude
+ //
+
+ CallbackCtx = CreateCallbackContext(RegisterCallbackInput->CallbackMode,
+ RegisterCallbackInput->Altitude);
+
+ if (CallbackCtx == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Register the callback
+ //
+
+ Status = CmRegisterCallbackEx(Callback,
+ &CallbackCtx->Altitude,
+ DeviceObject->DriverObject,
+ (PVOID) CallbackCtx,
+ &CallbackCtx->Cookie,
+ NULL);
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status);
+ goto Exit;
+ }
+
+ if (!InsertCallbackContext(CallbackCtx)) {
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ //
+ // Fill the output buffer with the Cookie received from registering the
+ // callback and the pointer to the callback context.
+ //
+
+ RegisterCallbackOutput = (PREGISTER_CALLBACK_OUTPUT)Irp->AssociatedIrp.SystemBuffer;
+ RegisterCallbackOutput->Cookie = CallbackCtx->Cookie;
+ Irp->IoStatus.Information = sizeof(REGISTER_CALLBACK_OUTPUT);
+
+ Exit:
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("RegisterCallback failed. Status 0x%x", Status);
+ if (CallbackCtx != NULL) {
+ DeleteCallbackContext(CallbackCtx);
+ }
+ } else {
+ InfoPrint("RegisterCallback succeeded");
+ }
+
+ return Status;
+}
+
+
+
+NTSTATUS
+UnRegisterCallback(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Unregisters a callback with the specified cookie and clean up the
+ callback context.
+
+Arguments:
+
+ DeviceObject - The device object receiving the request.
+
+ Irp - The request packet.
+
+Return Value:
+
+ Status from CmUnRegisterCallback
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG InputBufferLength;
+ PUNREGISTER_CALLBACK_INPUT UnRegisterCallbackInput;
+ PCALLBACK_CONTEXT CallbackCtx;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ //
+ // Get the input buffer and check its size
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
+
+ if (InputBufferLength < sizeof(UNREGISTER_CALLBACK_INPUT)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ UnRegisterCallbackInput = (PUNREGISTER_CALLBACK_INPUT) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Unregister the callback with the cookie
+ //
+
+ Status = CmUnRegisterCallback(UnRegisterCallbackInput->Cookie);
+
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status);
+ goto Exit;
+ }
+
+ //
+ // Free the callback context buffer
+ //
+ CallbackCtx = FindAndRemoveCallbackContext(UnRegisterCallbackInput->Cookie);
+ if (CallbackCtx != NULL) {
+ DeleteCallbackContext(CallbackCtx);
+ }
+
+ Exit:
+
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("UnRegisterCallback failed. Status 0x%x", Status);
+ } else {
+ InfoPrint("UnRegisterCallback succeeded");
+ }
+ InfoPrint("");
+
+ return Status;
+
+}
+
+
+NTSTATUS
+GetCallbackVersion(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _In_ PIRP Irp
+ )
+/*++
+
+Routine Description:
+
+ Calls CmGetCallbackVersion
+
+Arguments:
+
+ DeviceObject - The device object receiving the request.
+
+ Irp - The request packet.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION IrpStack;
+ ULONG OutputBufferLength;
+ PGET_CALLBACK_VERSION_OUTPUT GetCallbackVersionOutput;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ //
+ // Get the output buffer and verify its size
+ //
+
+ IrpStack = IoGetCurrentIrpStackLocation(Irp);
+
+ OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
+
+ if (OutputBufferLength < sizeof(GET_CALLBACK_VERSION_OUTPUT)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Exit;
+ }
+
+ GetCallbackVersionOutput = (PGET_CALLBACK_VERSION_OUTPUT) Irp->AssociatedIrp.SystemBuffer;
+
+ //
+ // Call CmGetCallbackVersion and store the results in the output buffer
+ //
+
+ CmGetCallbackVersion(&GetCallbackVersionOutput->MajorVersion,
+ &GetCallbackVersionOutput->MinorVersion);
+
+ Irp->IoStatus.Information = sizeof(GET_CALLBACK_VERSION_OUTPUT);
+
+ Exit:
+
+ if (!NT_SUCCESS(Status)) {
+ ErrorPrint("GetCallbackVersion failed. Status 0x%x", Status);
+ } else {
+ InfoPrint("GetCallbackVersion succeeded");
+ }
+
+ return Status;
+}
+
+
+LPCWSTR
+GetNotifyClassString (
+ _In_ REG_NOTIFY_CLASS NotifyClass
+ )
+/*++
+
+Routine Description:
+
+ Converts from NotifyClass to a string
+
+Arguments:
+
+ NotifyClass - value that identifies the type of registry operation that
+ is being performed
+
+Return Value:
+
+ Returns a string of the name of NotifyClass.
+
+--*/
+{
+ switch (NotifyClass) {
+ case RegNtPreDeleteKey: return L"RegNtPreDeleteKey";
+ case RegNtPreSetValueKey: return L"RegNtPreSetValueKey";
+ case RegNtPreDeleteValueKey: return L"RegNtPreDeleteValueKey";
+ case RegNtPreSetInformationKey: return L"RegNtPreSetInformationKey";
+ case RegNtPreRenameKey: return L"RegNtPreRenameKey";
+ case RegNtPreEnumerateKey: return L"RegNtPreEnumerateKey";
+ case RegNtPreEnumerateValueKey: return L"RegNtPreEnumerateValueKey";
+ case RegNtPreQueryKey: return L"RegNtPreQueryKey";
+ case RegNtPreQueryValueKey: return L"RegNtPreQueryValueKey";
+ case RegNtPreQueryMultipleValueKey: return L"RegNtPreQueryMultipleValueKey";
+ case RegNtPreKeyHandleClose: return L"RegNtPreKeyHandleClose";
+ case RegNtPreCreateKeyEx: return L"RegNtPreCreateKeyEx";
+ case RegNtPreOpenKeyEx: return L"RegNtPreOpenKeyEx";
+ case RegNtPreFlushKey: return L"RegNtPreFlushKey";
+ case RegNtPreLoadKey: return L"RegNtPreLoadKey";
+ case RegNtPreUnLoadKey: return L"RegNtPreUnLoadKey";
+ case RegNtPreQueryKeySecurity: return L"RegNtPreQueryKeySecurity";
+ case RegNtPreSetKeySecurity: return L"RegNtPreSetKeySecurity";
+ case RegNtPreRestoreKey: return L"RegNtPreRestoreKey";
+ case RegNtPreSaveKey: return L"RegNtPreSaveKey";
+ case RegNtPreReplaceKey: return L"RegNtPreReplaceKey";
+
+ case RegNtPostDeleteKey: return L"RegNtPostDeleteKey";
+ case RegNtPostSetValueKey: return L"RegNtPostSetValueKey";
+ case RegNtPostDeleteValueKey: return L"RegNtPostDeleteValueKey";
+ case RegNtPostSetInformationKey: return L"RegNtPostSetInformationKey";
+ case RegNtPostRenameKey: return L"RegNtPostRenameKey";
+ case RegNtPostEnumerateKey: return L"RegNtPostEnumerateKey";
+ case RegNtPostEnumerateValueKey: return L"RegNtPostEnumerateValueKey";
+ case RegNtPostQueryKey: return L"RegNtPostQueryKey";
+ case RegNtPostQueryValueKey: return L"RegNtPostQueryValueKey";
+ case RegNtPostQueryMultipleValueKey: return L"RegNtPostQueryMultipleValueKey";
+ case RegNtPostKeyHandleClose: return L"RegNtPostKeyHandleClose";
+ case RegNtPostCreateKeyEx: return L"RegNtPostCreateKeyEx";
+ case RegNtPostOpenKeyEx: return L"RegNtPostOpenKeyEx";
+ case RegNtPostFlushKey: return L"RegNtPostFlushKey";
+ case RegNtPostLoadKey: return L"RegNtPostLoadKey";
+ case RegNtPostUnLoadKey: return L"RegNtPostUnLoadKey";
+ case RegNtPostQueryKeySecurity: return L"RegNtPostQueryKeySecurity";
+ case RegNtPostSetKeySecurity: return L"RegNtPostSetKeySecurity";
+ case RegNtPostRestoreKey: return L"RegNtPostRestoreKey";
+ case RegNtPostSaveKey: return L"RegNtPostSaveKey";
+ case RegNtPostReplaceKey: return L"RegNtPostReplaceKey";
+
+ case RegNtCallbackObjectContextCleanup: return L"RegNtCallbackObjectContextCleanup";
+
+ default:
+ return L"Unsupported REG_NOTIFY_CLASS";
+ }
+}
+
+
+LPCWSTR
+GetTransactionNotifyClassString (
+ _In_ ULONG TransactionNotifcation
+ )
+/*++
+
+Routine Description:
+
+ Converts from TransactionNotification to a string
+
+Arguments:
+
+ TransactionNotification - value that identifies the type of
+ transaction notification
+
+Return Value:
+
+ Returns a string of the name of TransactionNotification
+
+--*/
+{
+ switch (TransactionNotifcation) {
+ case TRANSACTION_NOTIFY_COMMIT: return L"TRANSACTION_NOTIFY_COMMIT";
+ case TRANSACTION_NOTIFY_ROLLBACK: return L"TRANSACTION_NOTIFY_ROLLBACK";
+
+ default:
+ return L"Unsupported Transaction Notification";
+ }
+}
+
+
+
+VOID
+DeleteTestKeys(
+ )
+/*++
+
+
+--*/
+{
+ NTSTATUS Status;
+ UNICODE_STRING KeyPath;
+ OBJECT_ATTRIBUTES KeyAttributes;
+ HANDLE RootKey = NULL;
+ HANDLE ChildKey = NULL;
+
+ //
+ // Check if the root key can be opened. If it can be opened, a previous
+ // run must have not completed cleanly. Delete the key and recreate the
+ // root key.
+ //
+
+ RtlInitUnicodeString(&KeyPath, ROOT_KEY_ABS_PATH);
+ InitializeObjectAttributes(&KeyAttributes,
+ &KeyPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL);
+
+ Status = ZwOpenKey(&RootKey,
+ KEY_ALL_ACCESS,
+ &KeyAttributes);
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+ return;
+ } else if (!NT_SUCCESS(Status)) {
+ ErrorPrint("Opening root key fails with unexpected status %x.", Status);
+ }
+
+ RtlInitUnicodeString(&KeyPath, KEY_NAME);
+ InitializeObjectAttributes(&KeyAttributes,
+ &KeyPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ RootKey,
+ NULL);
+
+ Status = ZwOpenKey(&ChildKey,
+ KEY_ALL_ACCESS,
+ &KeyAttributes);
+
+ if (NT_SUCCESS(Status)) {
+ ZwDeleteKey(ChildKey);
+ ZwClose(ChildKey);
+ ChildKey = NULL;
+ } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ ErrorPrint("Opening %S key fails with unexpected status %x.",
+ KEY_NAME,
+ Status);
+ }
+
+ RtlInitUnicodeString(&KeyPath, NOT_MODIFIED_KEY_NAME);
+ InitializeObjectAttributes(&KeyAttributes,
+ &KeyPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ RootKey,
+ NULL);
+
+ Status = ZwOpenKey(&ChildKey,
+ KEY_ALL_ACCESS,
+ &KeyAttributes);
+
+ if (NT_SUCCESS(Status)) {
+ ZwDeleteKey(ChildKey);
+ ZwClose(ChildKey);
+ ChildKey = NULL;
+ } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ ErrorPrint("Opening %S key fails with unexpected status %x.",
+ NOT_MODIFIED_KEY_NAME,
+ Status);
+ }
+
+ RtlInitUnicodeString(&KeyPath, MODIFIED_KEY_NAME);
+ InitializeObjectAttributes(&KeyAttributes,
+ &KeyPath,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ RootKey,
+ NULL);
+
+ Status = ZwOpenKey(&ChildKey,
+ KEY_ALL_ACCESS,
+ &KeyAttributes);
+
+ if (NT_SUCCESS(Status)) {
+ ZwDeleteKey(ChildKey);
+ ZwClose(ChildKey);
+ ChildKey = NULL;
+ } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+ ErrorPrint("Opening %S key fails with unexpected status %x.",
+ MODIFIED_KEY_NAME,
+ Status);
+ }
+
+ ZwDeleteKey(RootKey);
+ ZwClose(RootKey);
+
+ return;
+
+}
diff --git a/general/registry/regfltr/sys/regfltr.h b/general/registry/regfltr/sys/regfltr.h new file mode 100644 index 00000000..d8787ff2 --- /dev/null +++ b/general/registry/regfltr/sys/regfltr.h @@ -0,0 +1,488 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + regfltr.h + +Abstract: + + Header file for the sample driver + +Environment: + + Kernel mode only + + +--*/ + +#pragma once + +#include <ntifs.h> +#include <ntstrsafe.h> +#include <wdmsec.h> + +#include "common.h" + + +// +// Pool tags +// + +#define REGFLTR_CONTEXT_POOL_TAG '0tfR' +#define REGFLTR_CAPTURE_POOL_TAG '1tfR' + + +// +// Logging macros +// + +#define InfoPrint(str, ...) \ + DbgPrintEx(DPFLTR_IHVDRIVER_ID, \ + DPFLTR_INFO_LEVEL, \ + "%S: "##str"\n", \ + DRIVER_NAME, \ + __VA_ARGS__) + +#define ErrorPrint(str, ...) \ + DbgPrintEx(DPFLTR_IHVDRIVER_ID, \ + DPFLTR_ERROR_LEVEL, \ + "%S: %d: "##str"\n", \ + DRIVER_NAME, \ + __LINE__, \ + __VA_ARGS__) + + +// +// The root key used in the samples +// +extern HANDLE g_RootKey; + + +// +// Pointer to the device object used to register registry callbacks +// +extern PDEVICE_OBJECT g_DeviceObj; + + +// +// Registry callback version +// +extern ULONG g_MajorVersion; +extern ULONG g_MinorVersion; + + +// +// Set to TRUE if TM and RM were successfully created and the transaction +// callback was successfully enabled. +// +extern BOOLEAN g_RMCreated; + + +// +// Flag that indicates if the system is win8 or higher. This is set on +// driver entry by calling RtlVerifyVersionInfo. +// +extern BOOLEAN g_IsWin8OrGreater; + + +// +// The following are variables used to manage callback contexts handed +// out to user mode. +// + +#define MAX_CALLBACK_CTX_ENTRIES 10 + +// +// The fast mutex guarding the callback context list +// +extern FAST_MUTEX g_CallbackCtxListLock; + +// +// The list head +// +extern LIST_ENTRY g_CallbackCtxListHead; + +// +// Count of entries in list +// +extern USHORT g_NumCallbackCtxListEntries; + +// +// Context data structure for the transaction callback RMCallback +// + +typedef struct _RMCALLBACK_CONTEXT { + + // + // A bit mask of all transaction notifications types that the RM Callback is + // notified of. + // + ULONG Notification; + + // + // The handle to an enlistment + // + HANDLE Enlistment; + +} RMCALLBACK_CONTEXT, *PRMCALLBACK_CONTEXT; + + +// +// The context data structure for the registry callback. It will be passed +// to the callback function every time it is called. +// + +typedef struct _CALLBACK_CONTEXT { + + // + // List of callback contexts currently active + // + LIST_ENTRY CallbackCtxList; + + // + // Specifies which callback helper method to use + // + CALLBACK_MODE CallbackMode; + + // + // Records the current ProcessId to filter out registry operation from + // other processes. + // + HANDLE ProcessId; + + // + // Records the altitude that the callback was registered at + // + UNICODE_STRING Altitude; + WCHAR AltitudeBuffer[MAX_ALTITUDE_BUFFER_LENGTH]; + + // + // Records the cookie returned by the registry when the callback was + // registered + // + LARGE_INTEGER Cookie; + + // + // A pointer to the context for the transaction callback. + // Used to enlist on a transaction. Only used in the transaction samples. + // + PRMCALLBACK_CONTEXT RMCallbackCtx; + + // + // These fields record information for verifying the behavior of the + // certain samples. They are not used in all samples + // + + // + // Number of times the RegNtCallbackObjectContextCleanup + // notification was received + // + LONG ContextCleanupCount; + + // + // Number of times the callback saw a notification with the call or + // object context set correctly. + // + LONG NotificationWithContextCount; + + // + // Number of times callback saw a notirication without call or without + // object context set correctly + // + LONG NotificationWithNoContextCount; + + // + // Number of pre-notifications received + // + LONG PreNotificationCount; + + // + // Number of post-notifications received + // + LONG PostNotificationCount; + +} CALLBACK_CONTEXT, *PCALLBACK_CONTEXT; + + +// +// The registry and transaction callback routines +// + +EX_CALLBACK_FUNCTION Callback; + +NTSTATUS +RMCallback( + _In_ PKENLISTMENT EnlistmentObject, + _In_ PVOID RMContext, + _In_ PVOID TransactionContext, + _In_ ULONG TransactionNotification, + _Inout_ PLARGE_INTEGER TMVirtualClock, + _In_ ULONG ArgumentLength, + _In_ PVOID Argument + ); + +// +// The samples and their corresponding callback helper methods +// + +NTSTATUS +CallbackPreNotificationBlock( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +PreNotificationBlockSample(); + +NTSTATUS +CallbackPreNotificationBlock( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +PreNotificationBypassSample(); + +NTSTATUS +CallbackPreNotificationBypass( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +PostNotificationOverrideSuccessSample(); + +NTSTATUS +CallbackPostNotificationOverrideSuccess( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +PostNotificationOverrideErrorSample(); + +NTSTATUS +CallbackPostNotificationOverrideError( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +TransactionEnlistSample(); + +NTSTATUS +CallbackTransactionEnlist( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +TransactionReplaySample(); + +NTSTATUS +CallbackTransactionReplay( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +SetObjectContextSample(); + +NTSTATUS +CallbackSetObjectContext( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +SetCallContextSample(); + +NTSTATUS +CallbackSetCallContext( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +MultipleAltitudeBlockDuringPreSample(); + +BOOLEAN +MultipleAltitudeInternalInvocationSample(); + +NTSTATUS +CallbackMonitor( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +NTSTATUS +CallbackMultipleAltitude( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +NTSTATUS +CallbackCapture( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +VOID +BugCheckSample(); + +NTSTATUS +CallbackBugcheck( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +BOOLEAN +CreateOpenV1Sample(); + +NTSTATUS +CallbackCreateOpenV1( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ); + +// +// Driver dispatch functions +// + +NTSTATUS +DoCallbackSamples( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp + ); + +NTSTATUS +RegisterCallback( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp + ); + +NTSTATUS +UnRegisterCallback( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp + ); + +NTSTATUS +GetCallbackVersion( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp + ); + +// +// Transaction related routines +// + +NTSTATUS +CreateKTMResourceManager( + _In_ PTM_RM_NOTIFICATION CallbackRoutine, + _In_opt_ PVOID RMKey + ); + +NTSTATUS +EnlistInTransaction( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PVOID Transaction, + _In_ NOTIFICATION_MASK NotificationMask, + _In_opt_ PVOID EnlistmentKey + ); + +VOID +DeleteKTMResourceManager( + ); + + +// +// Capture methods +// + +NTSTATUS +CaptureBuffer( + _Outptr_result_maybenull_ PVOID *CapturedBuffer, + _In_reads_bytes_(Length)PVOID Buffer, + _In_ SIZE_T Length, + _In_ ULONG PoolTag + ); + +VOID +FreeCapturedBuffer( + _In_ PVOID Buffer, + _In_ ULONG PoolTag + ); + +NTSTATUS +CaptureUnicodeString( + _Inout_ UNICODE_STRING * DestString, + _In_ PCUNICODE_STRING SourceString, + _In_ ULONG PoolTag + ); + +VOID +FreeCapturedUnicodeString( + _In_ UNICODE_STRING * String, + _In_ ULONG PoolTag + ); + + +// +// Utility methods +// + +PVOID +CreateCallbackContext( + _In_ CALLBACK_MODE CallbackMode, + _In_ PCWSTR AltitudeString + ); + +BOOLEAN +InsertCallbackContext( + _In_ PCALLBACK_CONTEXT CallbackCtx + ); + +PCALLBACK_CONTEXT +FindCallbackContext( + _In_ LARGE_INTEGER Cookie + ); + +PCALLBACK_CONTEXT +FindAndRemoveCallbackContext( + _In_ LARGE_INTEGER Cookie + ); + +VOID +DeleteCallbackContext( + _In_ PCALLBACK_CONTEXT CallbackCtx + ); + + +ULONG +ExceptionFilter ( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ); + + diff --git a/general/registry/regfltr/sys/regfltr.rc b/general/registry/regfltr/sys/regfltr.rc new file mode 100644 index 00000000..67bc9a4b --- /dev/null +++ b/general/registry/regfltr/sys/regfltr.rc @@ -0,0 +1,11 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Registry Filter System Driver" +#define VER_INTERNALNAME_STR "regfltr.sys" +#define VER_ORIGINALFILENAME_STR "RegFltr.sys" + +#include "common.ver"
\ No newline at end of file diff --git a/general/registry/regfltr/sys/regfltr.vcxproj b/general/registry/regfltr/sys/regfltr.vcxproj new file mode 100644 index 00000000..6bddb5e4 --- /dev/null +++ b/general/registry/regfltr/sys/regfltr.vcxproj @@ -0,0 +1,214 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{12666DFF-2CD6-4000-AFE6-0796D9B6D330}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{3973A2A5-EFFD-4997-985D-51731D2A58CA}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>regfltr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>regfltr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>regfltr</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>regfltr</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + <Optimization>Disabled</Optimization> + <IntrinsicFunctions>true</IntrinsicFunctions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(IFSKIT_INC_PATH);..\exe</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntoskrnl.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Capture.c" /> + <ClCompile Include="Context.c" /> + <ClCompile Include="driver.c" /> + <ClCompile Include="MultiAlt.c" /> + <ClCompile Include="Post.c" /> + <ClCompile Include="Pre.c" /> + <ClCompile Include="regfltr.c" /> + <ClCompile Include="TxR.c" /> + <ClCompile Include="TxRUtil.c" /> + <ClCompile Include="Util.c" /> + <ClCompile Include="Version.c" /> + <ResourceCompile Include="regfltr.rc" /> + </ItemGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/registry/regfltr/sys/regfltr.vcxproj.Filters b/general/registry/regfltr/sys/regfltr.vcxproj.Filters new file mode 100644 index 00000000..22722767 --- /dev/null +++ b/general/registry/regfltr/sys/regfltr.vcxproj.Filters @@ -0,0 +1,61 @@ +<?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>{2B50099F-1EBF-480D-9136-448FBDF31F1F}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{1001336B-4543-45F1-A020-C5E84A980E24}</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>{9EEC1AF7-63F4-44AB-81FA-A0DAC270B821}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{AE93F2E1-863E-4BAE-BC5D-09810656976E}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Capture.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Context.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MultiAlt.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Post.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Pre.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="regfltr.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="TxR.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="TxRUtil.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Util.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Version.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="regfltr.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/registry/regfltr/sys/txr.c b/general/registry/regfltr/sys/txr.c new file mode 100644 index 00000000..6fd3c8a6 --- /dev/null +++ b/general/registry/regfltr/sys/txr.c @@ -0,0 +1,784 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TxR.c + +Abstract: + + Samples that show how to deal with transactional registry operations. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +BOOLEAN +TransactionEnlistSample( + ) +/*++ + +Routine Description: + + This sample shows how to enlist to a transaction that a registry operation + is part of inorder to get notifications when it commits or aborts. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ + +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + PRMCALLBACK_CONTEXT RMCallbackCtx = NULL; + NTSTATUS Status; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES KeyAttributes; + OBJECT_ATTRIBUTES TxAttributes; + HANDLE Key = NULL; + HANDLE Transaction = NULL; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Transaction Enlist Sample ===="); + + if (!g_RMCreated) { + ErrorPrint("Sample can't run because KTM data structures were not successfully created."); + goto Exit; + } + + // + // Create the registry callback context and the transaction callback context. + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_TRANSACTION_ENLIST, + CALLBACK_ALTITUDE); + if (CallbackCtx == NULL) { + goto Exit; + } + + RMCallbackCtx = (PRMCALLBACK_CONTEXT) ExAllocatePoolWithTag ( + PagedPool, + sizeof(RMCALLBACK_CONTEXT), + REGFLTR_CONTEXT_POOL_TAG); + if (RMCallbackCtx == NULL) { + goto Exit; + } + RtlZeroMemory(RMCallbackCtx, sizeof(RMCALLBACK_CONTEXT)); + CallbackCtx->RMCallbackCtx = RMCallbackCtx; + + // + // Create a transaction + // + + InitializeObjectAttributes(&TxAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwCreateTransaction(&Transaction, + TRANSACTION_ALL_ACCESS, + &TxAttributes, + NULL, + NULL, + 0, + 0, + 0, + NULL, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CreateTransaction failed. Status 0x%x", Status); + goto Exit; + } + + // + // Register the callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Success = TRUE; + + // + // Create a key + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwCreateKeyTransacted(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + Transaction, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKeyTransacted failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Commit the transaction + // + + Status = ZwCommitTransaction(Transaction, TRUE); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCommitTransaction failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + // + // Check that the transaction callback context records a commit notification + // + + if (RMCallbackCtx->Notification != TRANSACTION_NOTIFY_COMMIT) { + ErrorPrint("RMContext notification mask is 0x%x instead of 0x%x.", + RMCallbackCtx->Notification, + TRANSACTION_NOTIFY_COMMIT); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Transaction != NULL) { + ZwClose(Transaction); + } + + // + // Need to reopen the key to delete it because the previous + // handle was part of a transaction that is now gone. + // + + if (Key != NULL) { + ZwClose(Key); + Key = NULL; + } + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + ZwOpenKey(&Key, KEY_ALL_ACCESS, &KeyAttributes); + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (RMCallbackCtx != NULL) { + ExFreePoolWithTag(RMCallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Transaction Enlist Demo succeeded."); + } else { + ErrorPrint("Transaction Enlist Demo FAILED."); + } + + return Success; +} + + +NTSTATUS +CallbackTransactionEnlist( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 +) +/*++ + +Routine Description: + + This helper callback routine shows hot to enlist on a transaction. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + PVOID Transaction = NULL; + + switch(NotifyClass) { + + case RegNtPreCreateKeyEx: + + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) Argument2; + + // + // Get the transaction object + // + + Transaction = PreCreateInfo->Transaction; + if (Transaction == NULL) { + + // + // Even if the transaction is not provided in the + // REG_Xxx_INFORMATION, we need to call CmGetBoundTransaction + // on the RootObject to check that it isn't associated with + // a transaction. + // + + Transaction = CmGetBoundTransaction(&CallbackCtx->Cookie, + PreCreateInfo->RootObject); + + if (Transaction == NULL) { + ErrorPrint("CreateKey is unexpectedly not transacted."); + break; + } + } + + // + // Use the volatile RM created in CreateKTMResourceManager() + // to enlist in the transaction. We want notifications for + // when the transaction commits or rolls back. + // + // Note: Make sure the callback routine handles all the + // notifications requested here. Look at RMCallback() to see + // how to handle notifications. + // + + Status = EnlistInTransaction(&CallbackCtx->RMCallbackCtx->Enlistment, + ENLISTMENT_SUBORDINATE_RIGHTS, + Transaction, + TRANSACTION_NOTIFY_COMMIT | + TRANSACTION_NOTIFY_ROLLBACK, + CallbackCtx->RMCallbackCtx); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("EnlistInTransaction failed. Status 0x%x.", Status); + } + + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + return Status; +} + + + +BOOLEAN +TransactionReplaySample( + ) +/*++ + +Routine Description: + + This sample shows how to copy a transactional create key operation. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ + +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + UNICODE_STRING Name; + OBJECT_ATTRIBUTES KeyAttributes; + OBJECT_ATTRIBUTES TxAttributes; + HANDLE Key = NULL; + HANDLE Transaction = NULL; + HANDLE TransactedRoot = NULL; + BOOLEAN bSuccess = FALSE; + + InfoPrint(""); + InfoPrint("=== Transaction Replay Sample ===="); + + if (!g_RMCreated) { + ErrorPrint("Sample can't run because KTM data structures were not successfully created."); + goto Exit; + } + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_TRANSACTION_REPLAY, + CALLBACK_ALTITUDE); + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Create a transaction + // + + InitializeObjectAttributes(&TxAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwCreateTransaction(&Transaction, + TRANSACTION_ALL_ACCESS, + &TxAttributes, + NULL, + NULL, + 0, + 0, + 0, + NULL, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CreateTransaction failed. Status 0x%x", Status); + goto Exit; + } + + // + // Open a transacted handle to the root key + // + + RtlInitUnicodeString(&Name, ROOT_KEY_ABS_PATH); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwOpenKeyTransacted(&TransactedRoot, + KEY_ALL_ACCESS, + &KeyAttributes, + Transaction); + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKeyTransacted failed. Status 0x%x",Status); + goto Exit; + } + + // + // Register callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + bSuccess = TRUE; + + // + // Create a key using the transacted root key handle. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + TransactedRoot, + NULL); + Status = ZwCreateKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + NULL, + 0, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + bSuccess = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + bSuccess = FALSE; + } + + + // + // Verify that the key created exists and that a key with the + // "modified" name is also exists. + // + + if (Key != NULL) { + ZwClose(Key); + Key = NULL; + } + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + bSuccess = FALSE; + } else { + ZwClose(Key); + Key = NULL; + } + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + TransactedRoot, + NULL); + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKey failed. Status 0x%x", Status); + bSuccess = FALSE; + } else { + ZwClose(Key); + Key = NULL; + } + + // + // Roll back transaction + // + + Status = ZwRollbackTransaction(Transaction, TRUE); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwRollbackTransaction failed. Status 0x%x", Status); + bSuccess = FALSE; + goto Exit; + } + + // + // Check that both keys no longer exist. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwOpenKey returned unexpected status 0x%x. Expected 0x%x", + Status, + STATUS_OBJECT_NAME_NOT_FOUND); + bSuccess = FALSE; + } + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + Key = NULL; + } + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwOpenKey returned unexpected status 0x%x. Expected 0x%x", + Status, + STATUS_OBJECT_NAME_NOT_FOUND); + bSuccess = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (TransactedRoot!= NULL) { + ZwDeleteKey(TransactedRoot); + ZwClose(TransactedRoot); + } + + if (Transaction != NULL) { + ZwClose(Transaction); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (bSuccess) { + InfoPrint("Transaction Replay Sample succeeded."); + } else { + ErrorPrint("Transaction Replay Sample FAILED."); + } + + return bSuccess; + +} + + + +NTSTATUS +CallbackTransactionReplay( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine shows how to get the transaction associated + with a registry operation and shows how to do another operation in the + same transaction. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PREG_CREATE_KEY_INFORMATION PreCreateInfo; + HANDLE TransactionHandle = NULL; + PVOID Transaction = NULL; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + UNICODE_STRING LocalClass = {0}; + PUNICODE_STRING Class = NULL; + HANDLE Key = NULL; + HANDLE RootKey = NULL; + KPROCESSOR_MODE Mode = KernelMode; + + switch(NotifyClass) { + + case RegNtPreCreateKeyEx: + + PreCreateInfo = (PREG_CREATE_KEY_INFORMATION) Argument2; + + // + // Get the transaction object + // + + Transaction = PreCreateInfo->Transaction; + if (Transaction == NULL) { + + // + // Even if the transaction is not provided in the + // REG_Xxx_INFORMATION, we need to call CmGetBoundTransaction + // on the RootObject to check that it isn't associated with + // a transaction. + // + + Transaction = CmGetBoundTransaction(&CallbackCtx->Cookie, + PreCreateInfo->RootObject); + if (Transaction == NULL) { + ErrorPrint("CreateKey is unexpectedly not transacted."); + break; + } + } + + // + // Get a handle to the transaction object + // + + Status = ObOpenObjectByPointer(Transaction, + OBJ_KERNEL_HANDLE, + NULL, + TRANSACTION_ALL_ACCESS, + *TmTransactionObjectType, + KernelMode, + &TransactionHandle); + + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObReferenceObjectByPointer failed. Status 0x%x", Status); + break; + } + + // + // Next replay the create key using the transacted version of the + // API and the transaction handle. + // + + Status = ObOpenObjectByPointer(PreCreateInfo->RootObject, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, // Getting handle with all access + PreCreateInfo->ObjectType, + KernelMode, + &RootKey); + if (!NT_SUCCESS (Status)) { + ErrorPrint("ObReferenceObjectByPointer failed. Status 0x%x", Status); + break; + } + + + // + // REG_CREATE_KEY_INFORMATION is a partially structure. The class + // field's buffer is not captured. Since it is passed to + // ZwCreateKeyTransacted, it needs to be captured. + // + // *Note: in Windows 8 all fields are captured. See capture.c + // for more details. + // + + Mode = ExGetPreviousMode(); + + if (!g_IsWin8OrGreater && Mode == UserMode) { + Status = CaptureUnicodeString(&LocalClass, + PreCreateInfo->Class, + REGFLTR_CAPTURE_POOL_TAG); + if (!NT_SUCCESS(Status)) { + break; + } + Class = &LocalClass; + + } else { + Class = PreCreateInfo->Class; + } + + + RtlInitUnicodeString(&Name, MODIFIED_KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + RootKey, + PreCreateInfo->SecurityDescriptor); + + Status = ZwCreateKeyTransacted(&Key, + KEY_ALL_ACCESS, + &KeyAttributes, + 0, + Class, + PreCreateInfo->CreateOptions, + TransactionHandle, + PreCreateInfo->Disposition); + + ZwClose(RootKey); + ZwClose(TransactionHandle); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateKeyTransacted failed. Status 0x%x.", Status); + break; + } + + ZwClose(Key); + InfoPrint("\tCallback: Create key %wZ replayed in same transaction context.", + PreCreateInfo->CompleteName); + Status = STATUS_SUCCESS; + break; + + default: + // + // Do nothing for other notifications + // + break; + } + + // + // Free buffers used for capturing user mode values. + // + + if (LocalClass.Buffer != NULL) { + FreeCapturedUnicodeString(&LocalClass, REGFLTR_CAPTURE_POOL_TAG); + } + + return Status; +} + diff --git a/general/registry/regfltr/sys/txrutil.c b/general/registry/regfltr/sys/txrutil.c new file mode 100644 index 00000000..337e5cc4 --- /dev/null +++ b/general/registry/regfltr/sys/txrutil.c @@ -0,0 +1,283 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + txrutil.c + +Abstract: + + Utility functions for working with transaction registry operations + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +static HANDLE ResourceManager = NULL; +static HANDLE TransactionManager = NULL; + + +NTSTATUS +CreateKTMResourceManager( + _In_ PTM_RM_NOTIFICATION CallbackRoutine, + _In_opt_ PVOID RMKey + ) +/*++ + +Routine Description: + + This method will create a volatile Transaction Manager (TM) and a volatile + Resource Manager (RM) and enable callback notification through them. + The RM created here is used to enlist onto a transaction so that the + RMCallback routine will be called when the transaction commits or aborts. + +Arguments: + + CallbackRoutine - Pointer to a ResourceManagerNotification Routine + + RMKey - A caller-defined context value that uniquely identifies the + resource manager. The callback routine receives this value as + input. + Note: When you are enlisting to a transaction, you can pass in a + context that is specific to that particular enlistment. + +Return Value: + + NTSTATUS + +--*/ +{ + OBJECT_ATTRIBUTES ObjAttributes; + PKRESOURCEMANAGER RMObject; + NTSTATUS Status = STATUS_SUCCESS; + HANDLE TMHandle = NULL; + HANDLE RMHandle = NULL; + GUID RMGuid; + + InfoPrint("Creating KTM Resource Manager"); + + // + // Create the volatile TM + // + + InitializeObjectAttributes(&ObjAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwCreateTransactionManager(&TMHandle, + TRANSACTIONMANAGER_ALL_ACCESS, + &ObjAttributes, + NULL, + TRANSACTION_MANAGER_VOLATILE, + 0); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CreateTransactionManager failed. Status 0x%x", Status); + goto Exit; + } + + // + // Create the volatile RM + // + + Status = ExUuidCreate(&RMGuid); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ExUuidCreate failed. Status 0x%x", Status); + goto Exit; + } + + InitializeObjectAttributes(&ObjAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwCreateResourceManager(&RMHandle, + RESOURCEMANAGER_ALL_ACCESS, + TMHandle, + &RMGuid, + &ObjAttributes, + + RESOURCE_MANAGER_VOLATILE, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CreateResourceManager failed. Status 0x%x", Status); + goto Exit; + } + + // + // Grab the RM object from the handle + // + + Status = ObReferenceObjectByHandle(RMHandle, + 0, + NULL, + KernelMode, + (PVOID *) &RMObject, + NULL); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ObReferenceObjectbyHandle failed. Status 0x%x", Status); + goto Exit; + } + + // + // Enable callbacks and pass in our notification routine + // + + Status = TmEnableCallbacks(RMObject, + CallbackRoutine, + RMKey); + + ObDereferenceObject(RMObject); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("TmEnableCallbacks failed. Status 0x%x", Status); + goto Exit; + } + + Exit: + + if (!NT_SUCCESS(Status)) { + if (RMHandle != NULL) { + ZwClose(RMHandle); + } + if (TMHandle!= NULL) { + ZwClose(TMHandle); + } + } else { + ResourceManager = RMHandle; + TransactionManager = TMHandle; + } + + return Status; +} + + + +NTSTATUS +EnlistInTransaction( + _Out_ PHANDLE EnlistmentHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ PVOID Transaction, + _In_ NOTIFICATION_MASK NotificationMask, + _In_opt_ PVOID EnlistmentKey + ) +/*++ + +Routine Description: + + This method is a wrapper around ZwCreateEnlistment. It outputs a handle + to the enlistment object which represent's a resource manager's + enlistment to a transaction. Enlisting to a transaction allows the + resource manager to receive notifications about a transaction's events. + +Arguments: + + EnlistmentHandle - Pointer to variable that receives the handle to the + new enlistment object. + + DesiredAccess - Specifies the requested access to the enlistment object. + + Transaction - Transaction object + + NotificationMask - A bitwise OR of TRANSACTION_NOTIFY_Xxx values defined + in Ktmtypes.h. It specifies the types of transaction + notifications that KTM will send to the caller. + + EnlistmentKey - A caller-defined context value that uniquely identifies the + enlistment. The callback routine registered when callbacks + were enabled in the resource manager receives this value. + +Return Value: + + NTSTATUS + +--*/ +{ + + NTSTATUS Status; + HANDLE TransactionHandle = NULL; + OBJECT_ATTRIBUTES ObjAttributes; + + // + // Get a handle to the transaction object + // + + Status = ObOpenObjectByPointer(Transaction, + OBJ_KERNEL_HANDLE, + NULL, + TRANSACTION_ALL_ACCESS, + *TmTransactionObjectType, + KernelMode, + &TransactionHandle); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ObOpenObjectByPointer failed. Status 0x%x.", Status); + return Status; + } + + // + // Use the transaction handle and the volatile RM created in + // CreateKTMResourceManager() to enlist to the transaction. + // + + InitializeObjectAttributes(&ObjAttributes, + NULL, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + Status = ZwCreateEnlistment(EnlistmentHandle, + DesiredAccess, + ResourceManager, + TransactionHandle, + &ObjAttributes, + 0, + NotificationMask, + EnlistmentKey); + + ZwClose(TransactionHandle); + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwCreateEnlistment failed. Status 0x%x", Status); + } + + return Status; + +} + + +VOID +DeleteKTMResourceManager( + ) +/*++ + +Routine Description: + + Clean up any resources associated wtih the resource manager. + +--*/ +{ + if (ResourceManager != NULL) { + ZwClose(ResourceManager); + ResourceManager = NULL; + } + if (TransactionManager != NULL) { + ZwClose(TransactionManager); + TransactionManager = NULL; + } +} diff --git a/general/registry/regfltr/sys/util.c b/general/registry/regfltr/sys/util.c new file mode 100644 index 00000000..068416c8 --- /dev/null +++ b/general/registry/regfltr/sys/util.c @@ -0,0 +1,304 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + util.c + +Abstract: + + Utility routines for the sample driver. + +Environment: + + Kernel mode only + +--*/ + + +#include "regfltr.h" + + +FAST_MUTEX g_CallbackCtxListLock; +LIST_ENTRY g_CallbackCtxListHead; +USHORT g_NumCallbackCtxListEntries; + + +ULONG +ExceptionFilter ( + _In_ PEXCEPTION_POINTERS ExceptionPointers + ) +/*++ + +Routine Description: + + ExceptionFilter breaks into the debugger if an exception happens + inside the callback. + +Arguments: + + ExceptionPointers - unused + +Return Value: + + Always returns EXCEPTION_CONTINUE_SEARCH + +--*/ +{ + + ErrorPrint("Exception %lx, ExceptionPointers = %p", + ExceptionPointers->ExceptionRecord->ExceptionCode, + ExceptionPointers); + + DbgBreakPoint(); + + return EXCEPTION_EXECUTE_HANDLER; + +} + + +PVOID +CreateCallbackContext( + _In_ CALLBACK_MODE CallbackMode, + _In_ PCWSTR AltitudeString + ) +/*++ + +Routine Description: + + Utility method to create a callback context. Callback context + should be freed using DeleteCallbackContext. + +Arguments: + + CallbackMode - the callback mode value + + AltitudeString - a string with the altitude the callback will be + registered at + +Return Value: + + Pointer to the allocated and initialized callback context + +--*/ +{ + + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + BOOLEAN Success = FALSE; + + CallbackCtx = (PCALLBACK_CONTEXT) ExAllocatePoolWithTag ( + PagedPool, + sizeof(CALLBACK_CONTEXT), + REGFLTR_CONTEXT_POOL_TAG); + + if (CallbackCtx == NULL) { + ErrorPrint("CreateCallbackContext failed due to insufficient resources."); + goto Exit; + } + + RtlZeroMemory(CallbackCtx, sizeof(CALLBACK_CONTEXT)); + + CallbackCtx->CallbackMode = CallbackMode; + CallbackCtx->ProcessId = PsGetCurrentProcessId(); + + Status = RtlStringCbPrintfW(CallbackCtx->AltitudeBuffer, + MAX_ALTITUDE_BUFFER_LENGTH * sizeof(WCHAR), + L"%s", + AltitudeString); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("RtlStringCbPrintfW in CreateCallbackContext failed. Status 0x%x", Status); + goto Exit; + } + + RtlInitUnicodeString (&CallbackCtx->Altitude, CallbackCtx->AltitudeBuffer); + + Success = TRUE; + + Exit: + + if (Success == FALSE) { + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + CallbackCtx = NULL; + } + } + + return CallbackCtx; + +} + + +BOOLEAN +InsertCallbackContext( + _In_ PCALLBACK_CONTEXT CallbackCtx + ) +/*++ + +Routine Description: + + Utility method to insert the callback context into a list. + +Arguments: + + CallbackCtx - the callback context to insert + +Return Value: + + TRUE if successful, FALSE otherwise + +--*/ +{ + + BOOLEAN Success = FALSE; + + ExAcquireFastMutex(&g_CallbackCtxListLock); + + if (g_NumCallbackCtxListEntries < MAX_CALLBACK_CTX_ENTRIES) { + g_NumCallbackCtxListEntries++; + InsertHeadList(&g_CallbackCtxListHead, &CallbackCtx->CallbackCtxList); + Success = TRUE; + } else { + ErrorPrint("Insert Callback Ctx failed: Max CallbackCtx entries reached."); + } + + ExReleaseFastMutex(&g_CallbackCtxListLock); + + return Success; + +} + + +PCALLBACK_CONTEXT +FindCallbackContext( + _In_ LARGE_INTEGER Cookie + ) +/*++ + +Routine Description: + + Utility method to find a callback context using the cookie value. + +Arguments: + + Cookie - the cookie value associated with the callback context. The + cookie is returned when CmRegisterCallbackEx is called. + +Return Value: + + Pointer to the found callback context + +--*/ +{ + + PCALLBACK_CONTEXT CallbackCtx = NULL; + PLIST_ENTRY Entry; + + ExAcquireFastMutex(&g_CallbackCtxListLock); + + Entry = g_CallbackCtxListHead.Flink; + while (Entry != &g_CallbackCtxListHead) { + + CallbackCtx = CONTAINING_RECORD(Entry, + CALLBACK_CONTEXT, + CallbackCtxList); + if (CallbackCtx->Cookie.QuadPart == Cookie.QuadPart) { + break; + } + + Entry = Entry->Flink; + } + + ExReleaseFastMutex(&g_CallbackCtxListLock); + + if (CallbackCtx == NULL) { + ErrorPrint("FindCallbackContext failed: No context with specified cookied was found."); + } + + return CallbackCtx; + +} + +PCALLBACK_CONTEXT +FindAndRemoveCallbackContext( + _In_ LARGE_INTEGER Cookie + ) +/*++ + +Routine Description: + + Utility method to find a callback context using the cookie value and then + remove it. + +Arguments: + + Cookie - the cookie value associated with the callback context. The + cookie is returned when CmRegisterCallbackEx is called. + +Return Value: + + Pointer to the found callback context + +--*/ +{ + + PCALLBACK_CONTEXT CallbackCtx = NULL; + PLIST_ENTRY Entry; + + ExAcquireFastMutex(&g_CallbackCtxListLock); + + Entry = g_CallbackCtxListHead.Flink; + while (Entry != &g_CallbackCtxListHead) { + + CallbackCtx = CONTAINING_RECORD(Entry, + CALLBACK_CONTEXT, + CallbackCtxList); + if (CallbackCtx->Cookie.QuadPart == Cookie.QuadPart) { + RemoveEntryList(&CallbackCtx->CallbackCtxList); + g_NumCallbackCtxListEntries--; + break; + } + } + + ExReleaseFastMutex(&g_CallbackCtxListLock); + + if (CallbackCtx == NULL) { + ErrorPrint("FindAndRemoveCallbackContext failed: No context with specified cookied was found."); + } + + return CallbackCtx; +} + + +VOID +DeleteCallbackContext( + _In_ PCALLBACK_CONTEXT CallbackCtx + ) +/*++ + +Routine Description: + + Utility method to delete a callback context. + +Arguments: + + CallbackCtx - the callback context to insert + +Return Value: + + None + +--*/ +{ + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + +} diff --git a/general/registry/regfltr/sys/version.c b/general/registry/regfltr/sys/version.c new file mode 100644 index 00000000..11edc9a3 --- /dev/null +++ b/general/registry/regfltr/sys/version.c @@ -0,0 +1,611 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Version.c + +Abstract: + + Information and samples that describe: + 1. Changes in registry callback version 1.1 + 2. How to use the version 1 REG_OPEN_KEY_INFORMATION and + REG_CREATE_KEY_INFORMATION structures + 3. Work arounds for issues in callback version 1.0. + +Environment: + + Kernel mode only + +--*/ + +#include "regfltr.h" + + +/*++ + + Callback Version 1.1 is available in Windows 7 and Windows Server 2008 R2. + It is NOT available on Vista or Windows Server 2008 as of Service Pack 2. + + + Issues in callback version 1.0 that have been fixed in version 1.1: + + 1. In the post-notification phase for a create or open key operation, + the PostInfo->Object field might not be NULL even if the operation was + unsuccessful as indicated by PostInfo->ReturnStatus. + + This problem happens when there are multiple registry filter drivers + registered and one of the drivers blocks the operation in the + pre-notification phase by returning a nonsuccess status. Filter drivers + that are at higher altitudes will receive a post-notification where + PostInfo->ReturnStatus is the nonsuccess status value but + PostInfo->Object will not be NULL. PostInfo->Object in this case will + be equal to PostInfo->PreInfo->RootObject. + + 2. In version 1.0, an uncatched exception in a registry callback + routine will be swallowed by the system. In version 1.1 this has been + changed so an uncatched exception will cause the machine to bugcheck. + We provide a sample in this file (BugCheckSample) but obviously it is not + run. + + NOTE: While bugchecking the system is not a good thing to do, we do not + recommend putting your entire callback routine in one big try-except block + and swallow legitimate exceptions like possible pool corruptions. Please + keep what you wrap with a try-except block to the bare minimum. + +--*/ + +/*++ + + Version 1 of the create and open key REG_Xxx_INFORMATION structure is + available in Windows 7 and Windows Server 2008 R2. It is NOT available on + Vista or Windows Server 2008 as of Service Pack 2. + + NOTE: While Version 1 of the create and open key data structures will + likely be available on systems that have callback version 1.1, this + relationship is not guaranteed. You must check the create and open key + data structure to see its version rather than depending on the + callback version. See CreateOpenV1Sample on how to check the version. + + + Issues addressed by version 1 of the create and open key data structures: + + 1. Without the Attributes field provided in the V1 create and open + REG_Xxx_INFORMATION structure, there is no way to exactly replicate + certain create and open operations. See CreateOpenV1Sample for a + demonstration. Unfortunately there is no work around for this issue. + + 2. The PreInfo->CompleteName and PreInfo->RootObject fields in a + create or open key operation do not behave as expected when the key to be + opened or created is represented as an absolute path. + REG_CREATE_KEY_INFORMATION_V1 and REG_OPEN_KEY_INFORMATION_V1 contain a + field PreInfoV1->RemainingName which addresses this issue. + + Example: + + Open operation on this key: \REGISTRY\MACHINE\Software\_RegFltrRoot + + One way of relatively opening the key is to open "Software\_RegFltrRoot" + relative to \REGISTRY\MACHINE. + + RegOpenKeyEx(HKEY_LOCAL_MACHINE, + "Software\\_RegFltrRoot", + 0, + KEY_ALL_ACCESS, + &Key); + + In this case the value of the fields in REG_OPEN_KEY_INFORMATION_V1 + would be: + + RootObject - Handle to the key \REGISTRY\MACHINE + CompleteName - "Software\\_RegFltrRoot" + RemainingName - "Software\\_RegFltrRoot" + + + If the open uses an absolute path, + + RtlInitUnicodeString(&Name, L"\\REGISTRY\\MACHINE\\Software\\_RegFltrRoot") + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL); + + ZwOpenKey(&Key, KEY_ALL_ACCESS, &KeyAttributes); + + the value of the fields in REG_OPEN_KEY_INFORMATION_V1 would be: + + RootObject - Handle to the key \REGISTRY + CompleteName - "\\REGISTRY\\MACHINE\\Software\\_RegFltrRoot" + RemainingName - "MACHINE\\Software\\_RegFltrRoot" + + Note that RootObject is not NULL even though CompleteName holds the + absolute path to the key. + + + The work around for this on systems without REG_OPEN_KEY_INFORMATION_V1 is + to check if the first character of CompleteName is a '\'. If that is the + case you can be sure that CompleteName is holding an absolute path to the + key. + +--*/ + + + +VOID +BugCheckSample( + ) +/*++ + +Routine Description: + + In version 1.1, if a registry filter driver's callback routine throws + an exception the registry will bugcheck the machine: + + REGISTRY_FILTER_DRIVER_EXCEPTION (0x135) + This bugcheck is caused by an unhandled exception in a registry + filtering driver. + + PARAMETERS + 1 - ExceptionCode + 2 - Address of the context record for the exception that caused + the bugcheck + 3 - The driver's callback routine address + 4 - Internal + + DESCRIPTION + This bugcheck indicates that a registry filtering driver didn't handle + exception inside its notification routine. One can identify the driver + by the 3rd parameter. + + In version 1.0, an exception in the callback routine is simply swallowed and + ignored. + + This sample uses a simple callback routine that will access NULL to throw + an exception. The sample is not normally run and is only here for + demonstration purposes. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + HANDLE Key = NULL; + + InfoPrint(""); + InfoPrint("=== Bugcheck Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_VERSION_BUGCHECK, + CALLBACK_ALTITUDE); + + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + // + // Do an open key just to invoke the callback. + // In version 1.1 this will bugcheck and nothing else will run. + // In version 1.0 the open will simply fail as expected. + // + + RtlInitUnicodeString(&Name, KEY_NAME); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + g_RootKey, + NULL); + + Status = ZwOpenKey(&Key, + KEY_ALL_ACCESS, + &KeyAttributes); + + if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { + ErrorPrint("ZwOpenKey returned unexpected status 0x%x", Status); + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwDeleteKey(Key); + ZwClose(Key); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + return; + +} + + +NTSTATUS +CallbackBugcheck( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine throws an exception by dereferencing a + null pointer. + + NOTE: While bugchecking the system is not a good thing to do, we do not + recommend putting your entire callback routine in one big try-except block + and swallow legitimate exceptions like possible pool corruptions. Please + keep what you wrap with a try-except block to the bare minimum. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + Always STATUS_SUCCESS; + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PULONG NullPointer = NULL; + + UNREFERENCED_PARAMETER(CallbackCtx); + UNREFERENCED_PARAMETER(NotifyClass); + UNREFERENCED_PARAMETER(Argument2); + + + InfoPrint("\tCallback is about to throw an exception."); + if (g_MajorVersion == 1 && g_MinorVersion == 0) { + InfoPrint("\tException will be swallowed by registry"); + } else { + ErrorPrint("Exception will cause machine to bugcheck"); + } + + + #pragma prefast(suppress: 6011, "Sample is purposefully dereferencing a null pointer."); + *NullPointer = 0; + + return Status; +} + + +BOOLEAN +CreateOpenV1Sample( + ) +/*++ + +Routine Description: + + This sample shows how the information in the Attributes field of + the REG_OPEN_KEY_INFORMATION_V1 data structure can change the outcome of + a registry operation. Without the Attributes field, it is impossible for + the callback routine to accuratel replay certain registry operations. + + A special key is used in this sample which has security set on it to + protect it from being deleted: + + \REGISTRY\MACHINE\SYSTEM\CurrentControlSet\Enum + + In the sample we try to open this key with DELETE access. Normally this + will work if we do it in kernel mode since the system bypasses all + access checks on handles created in kernel mode. However here we set the + OBJ_FORCE_ACCESS_CHECK flag which tells the system to perform all access + checks on the handle. + + In the callback routine associated with this sample, we will replay the + open operation with and without the flag to show how the presence of + the attributes information can change the outcome of the operation. + +Return Value: + + TRUE if the sample completed successfully. + +--*/ +{ + PCALLBACK_CONTEXT CallbackCtx = NULL; + NTSTATUS Status; + OBJECT_ATTRIBUTES KeyAttributes; + UNICODE_STRING Name; + WCHAR NameBuffer[] = L"\\registry\\machine\\system\\currentcontrolset\\enum"; + HANDLE Key = NULL; + BOOLEAN Success = FALSE; + + InfoPrint(""); + InfoPrint("=== Create/Open V1 Sample ===="); + + // + // Create the callback context + // + + CallbackCtx = CreateCallbackContext(CALLBACK_MODE_VERSION_CREATE_OPEN_V1, + CALLBACK_ALTITUDE); + + if (CallbackCtx == NULL) { + goto Exit; + } + + // + // Register callback + // + + Status = CmRegisterCallbackEx(Callback, + &CallbackCtx->Altitude, + g_DeviceObj->DriverObject, + (PVOID) CallbackCtx, + &CallbackCtx->Cookie, + NULL); + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmRegisterCallback failed. Status 0x%x", Status); + goto Exit; + } + + Success = TRUE; + + // + // Try to open the special key with delete access but have the + // OBJ_FORCE_ACCESS_CHECK flag in object attributes. This operation + // should fail with access denied. + // + + RtlInitUnicodeString(&Name, NameBuffer); + InitializeObjectAttributes(&KeyAttributes, + &Name, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | + OBJ_FORCE_ACCESS_CHECK, + NULL, + NULL); + + Status = ZwOpenKey(&Key, + DELETE, + &KeyAttributes); + + if (Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwOpenKey returned unexpected status 0x%x", Status); + Success = FALSE; + } + + // + // Unregister the callback + // + + Status = CmUnRegisterCallback(CallbackCtx->Cookie); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("CmUnRegisterCallback failed. Status 0x%x", Status); + Success = FALSE; + } + + Exit: + + // + // Clean up + // + + if (Key != NULL) { + ZwClose(Key); + } + + if (CallbackCtx != NULL) { + ExFreePoolWithTag(CallbackCtx, REGFLTR_CONTEXT_POOL_TAG); + } + + if (Success) { + InfoPrint("Create/Open V1 sample succeeded."); + } else { + ErrorPrint("Create/Open V1 sample failed."); + } + + return Success; + +} + + +NTSTATUS +CallbackCreateOpenV1( + _In_ PCALLBACK_CONTEXT CallbackCtx, + _In_ REG_NOTIFY_CLASS NotifyClass, + _Inout_ PVOID Argument2 + ) +/*++ + +Routine Description: + + This helper callback routine will show how to check whether the system + supports version 1 of the REG_OPEN_KEY_INFORMATION structure. + + If version 1 is supported, the callback routine will replay the open + operation during the pre-notification phase with and without the + Attributes field found in REG_OPEN_KEY_INFORMATION_V1 to show how the + outcome is different. + +Arguments: + + CallbackContext - The value that the driver passed to the Context parameter + of CmRegisterCallbackEx when it registers this callback routine. + + NotifyClass - A REG_NOTIFY_CLASS typed value that identifies the type of + registry operation that is being performed and whether the callback + is being called in the pre or post phase of processing. + + Argument2 - A pointer to a structure that contains information specific + to the type of the registry operation. The structure type depends + on the REG_NOTIFY_CLASS value of Argument1. + +Return Value: + + Always STATUS_SUCCESS; + +--*/ +{ + + NTSTATUS Status = STATUS_SUCCESS; + PREG_OPEN_KEY_INFORMATION_V1 PreOpenInfo; + OBJECT_ATTRIBUTES KeyAttributes; + HANDLE Key = NULL; + HANDLE RootKey = NULL; + + + UNREFERENCED_PARAMETER(CallbackCtx); + + // + // Check for the pre-notification phase of a create operation + // + + if (NotifyClass != RegNtPreOpenKeyEx) { + goto Exit; + } + + PreOpenInfo = (PREG_OPEN_KEY_INFORMATION_V1) Argument2; + + // + // Check if version 1 is available on this system. If not, + // simply return success. + // + + InfoPrint("\tREG_OPEN_KEY_INFORMATION structure's version is 0x%p", + (PVOID)PreOpenInfo->Version); + + if ((ULONG_PTR) PreOpenInfo->Version != 1) { + InfoPrint("Create/Open v1 sample is only for version 1"); + goto Exit; + } + + // + // Open a handle to the root object + // + + Status = ObOpenObjectByPointer(PreOpenInfo->RootObject, + OBJ_KERNEL_HANDLE, + NULL, + KEY_ALL_ACCESS, + PreOpenInfo->ObjectType, + KernelMode, + &RootKey); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ObObjectByPointer failed. Status 0x%x", Status); + goto Exit; + } + + // + // Do the open with the same attributes as in the original call. This + // includes the OBJ_FORCE_ACCESS_CHECK flag which will cause the open + // operation to fail. + // + // Note: The openkey operation might have originated from user mode so the + // OBJ_KERNEL_HANDLE flag needs to be explicitly added to the attributes + // to prevent user mode handle spoofing attacks. + // + + + InitializeObjectAttributes(&KeyAttributes, + PreOpenInfo->RemainingName, + PreOpenInfo->Attributes | OBJ_KERNEL_HANDLE, + RootKey, + PreOpenInfo->SecurityDescriptor); + + Status = ZwOpenKey(&Key, + PreOpenInfo->DesiredAccess, + &KeyAttributes); + + if (NT_SUCCESS(Status)) { + ZwClose(Key); + Key = NULL; + } + + if (Status != STATUS_ACCESS_DENIED) { + ErrorPrint("ZwOpenKey with attributes returned unexpected status 0x%x", Status); + Status = STATUS_UNSUCCESSFUL; + goto Exit; + } + + // + // Do the open without the attributes in the original call. The open + // operation will succeed now because the access checks will not be + // performed. + // + + InitializeObjectAttributes(&KeyAttributes, + PreOpenInfo->RemainingName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + RootKey, + PreOpenInfo->SecurityDescriptor); + + Status = ZwOpenKey(&Key, + PreOpenInfo->DesiredAccess, + &KeyAttributes); + + if (!NT_SUCCESS(Status)) { + ErrorPrint("ZwOpenKey without attributes returned unexpected status 0x%x", Status); + goto Exit; + } + + Status = STATUS_SUCCESS; + + + Exit: + + if (Key != NULL) { + ZwClose(Key); + } + + if (RootKey != NULL) { + ZwClose(RootKey); + } + + return Status; +} + diff --git a/general/toaster/toastpkg/ReadMe.md b/general/toaster/toastpkg/ReadMe.md new file mode 100644 index 00000000..7a5b7855 --- /dev/null +++ b/general/toaster/toastpkg/ReadMe.md @@ -0,0 +1,21 @@ +Toaster Package Sample +====================== + +The Toastpkg sample simulates hardware-first and software-first installation of the toaster sample driver. + +The Toaster Installation Package comprises driver projects (.vcxproj files) that are contained in the toastpkg.sln solution file (in general/toaster/toastpkg). + +This document discusses the different approaches that end users take when adding new hardware to their computer, and describes an approach that addresses these scenarios in a consistent, robust manner. It also outlines the mechanisms provided to facilitate additional vendor requirements such as the installation of value-added software. + +**Introduction** + +The installation of software to support an instance of a given device (known as "device installation" or "driver installation") is done in a device-centric fashion in Windows operating systems. A device INF that matches up with one of the device's hardware or compatible IDs is used to identify the required driver file(s), registry modifications, etc., that are needed to make the device fully operational. This INF, along with the files copied thereby and a catalog that contains the digital signatures of the INF and these other files, constitute what is known as a "driver package". + +Because device installation is done for a specific instance of a device, the "natural" method of adding devices to a computer running a Plug and Play operating system is by plugging in the device first, letting Plug and Play find the device and automatically initiate an installation for that device. The device installation may then proceed using a driver package supplied with the OS, or a "3rd-party" driver package (supplied via CD-ROM, the Internet, or some other distribution mechanism). When the device installation is initiated by the addition of hardware, this is termed a "hardware-first" device installation. + +Users may, however, take an alternate approach to adding hardware to their computer. In this scenario, they first run a setup program (perhaps launched as an autorun application when the vendor-supplied CD-ROM is inserted). This setup program may perform installation activities, and then prompt the user to insert their hardware. Upon the hardware's insertion, the vendor-supplied driver package (which was "pre-installed" by the setup program) is then found by Plug and Play, and the installation proceeds as in the hardware-first scenario. When the device installation is initiated by running a setup program, this is termed a "software-first" device installation. This approach to adding new hardware is just as valid as the hardware-first scenario, and some vendors may even instruct their users (via documentation that ships with the hardware) that this is the preferred method. + +Vendors must support the hardware-first scenario (by providing a driver package that may be supplied to the "Found New Hardware" wizard with no "pre-configuration" performed by a setup program or other mechanism). Vendors may optionally support the software-first scenario as well, but the actual installation of the device instance is done by Plug and Play upon the device's arrival, as described above. + +Vendors may also wish to perform additional activities as part of the device installation. For example, the vendor may want to allow the user to optionally install one or more applications that ship with the device (e.g., a scanner that ships with an image processing application). Such software is termed "value-added software". Value-added software is distinct from the files that comprise the driver package because, unlike the core driver files, the device does not require value-added software to function properly. In the previous example of a scanner, for instance, perhaps the user already has an image processing application that they prefer. The user should be given the option of whether or not they want to install any value-added software. Additional activities (such as allowing the user to select value-added software offerings) may be accomplished by using a vendor-supplied device-specific co-installer. + diff --git a/general/toaster/toastpkg/inf/autorun.inf b/general/toaster/toastpkg/inf/autorun.inf new file mode 100644 index 00000000..4c582d7b --- /dev/null +++ b/general/toaster/toastpkg/inf/autorun.inf @@ -0,0 +1,15 @@ +[AutoRun] +open=i386\toastva.exe +icon=i386\toastva.exe,0 + +[AutoRun.i386] +open=i386\toastva.exe + +[AutoRun.ia64] +open=ia64\toastva.exe + +[AutoRun.amd64] +open=amd64\toastva.exe + +[DeviceInstall] +DriverPath=\ diff --git a/general/toaster/toastpkg/inf/toastpkg.inf b/general/toaster/toastpkg/inf/toastpkg.inf new file mode 100644 index 00000000..f427ae87 --- /dev/null +++ b/general/toaster/toastpkg/inf/toastpkg.inf @@ -0,0 +1,137 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; +; TOASTPKG.INF +; +;Abstract: +; +; INF file for installing toaster device drivers (and, optionally, value- +; added software) via device-specific coinstaller. +; This is a mutlios INF file. Same INF file cab be used on +; x86, ia64 and amd64 platforms. +; +;--*/ +[Version] +Signature="$WINDOWS NT$" +Class=TOASTER +ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} +Provider=%ToastRUs% +DriverVer=09/21/2006,6.0.5736.1 +CatalogFile.NTx86 = tostx86.cat +CatalogFile.NTIA64 = tostia64.cat +CatalogFile.NTAMD64 = tstamd64.cat + +[DestinationDirs] +DefaultDestDir = 12 +CoInstaller_CopyFiles = 11 +ToasterClassInstallerCopyFiles = 11 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=ToasterClassReg +CopyFiles=ToasterClassInstallerCopyFiles + +[ToasterClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,100 +HKR,,Installer32,,"tostrcls.dll,ToasterClassInstaller" +HKR,,DeviceCharacteristics,0x10001,0x100 ; Use same security checks on relative opens + +[ToasterClassInstallerCopyFiles] +tostrcls.dll + +;***************************************** +; Toaster Device Install Section +;***************************************** + +[Manufacturer] +%ToastRUs%=ToastRUs,NTx86, NTia64, NTamd64 + +; For Win2K +[ToastRUs] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +; For XP and later +[ToastRUs.NTx86] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +[ToastRUs.NTia64] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +[ToastRUs.NTamd64] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + + +[Toaster_Device.NT] +CopyFiles=Toaster_Device.NT.Copy +FriendlyNameFormat=%FriendlyNameFormat% + +[Toaster_Device.NT.Copy] +toaster.sys + +[Toaster_Device.NT.HW] +AddReg=Toaster_Device.NT.HW.AddReg + +[Toaster_Device.NT.HW.AddReg] +HKR,,"BeepCount",0x00010003,4 + +;-------------- Service installation + +[Toaster_Device.NT.Services] +AddService = toaster, %SPSVCINST_ASSOCSERVICE%, toaster_Service_Inst + +[toaster_Service_Inst] +DisplayName = %toaster.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\toaster.sys + +;-------------- Coinstaller installation + +[Toaster_Device.NT.CoInstallers] +AddReg=CoInstaller_AddReg +CopyFiles=CoInstaller_CopyFiles + +[CoInstaller_CopyFiles] +tostrco2.dll + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000,"tostrco2.dll,ToasterCoInstaller" + +[ToastCoInfo] +; Used by the toaster co-installer to figure out where the original media is +; located (so it can launch value-added setup programs). +OriginalInfSourcePath = %1% + +[SourceDisksNames.x86] +1 = %DiskId1%, toastpkg.tag,,\i386 + +[SourceDisksNames.ia64] +1 = %DiskId1%, toastpkg.tag,,\ia64 + +[SourceDisksNames.amd64] +1 = %DiskId1%, toastpkg.tag,,\amd64 + +[SourceDisksFiles] +toaster.sys = 1,, +tostrco2.dll = 1,, +tostrcls.dll = 1,, + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +ToastRUs = "Toast'R'Us" +ClassName = "Toaster" +DiskId1 = "Toaster Device Installation Disk #1" +ToasterDevice.DeviceDesc = "Toaster Package Sample Toaster" +toaster.SVCDESC = "Microsoft Toaster Device Driver" +FriendlyNameFormat = "ToasterDevice%1!u!" diff --git a/general/toaster/toastpkg/toastapp/precomp.h b/general/toaster/toastpkg/toastapp/precomp.h new file mode 100644 index 00000000..c71537ea --- /dev/null +++ b/general/toaster/toastpkg/toastapp/precomp.h @@ -0,0 +1,21 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + precomp.h + +Abstract: + + Single container to facilitate use of precompiled headers. + +--*/ + +#include "toastapp.h" +#include <strsafe.h>
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastapp/precompsrc.c b/general/toaster/toastpkg/toastapp/precompsrc.c new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/precompsrc.c @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastapp/rc_ids.h b/general/toaster/toastpkg/toastapp/rc_ids.h new file mode 100644 index 00000000..fd47a4c0 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/rc_ids.h @@ -0,0 +1,22 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + rc_ids.h + +Abstract: + + Resource IDs used by the TOASTAPP sample application. + +--*/ + +#define IDD_DEVICE_INTERFACES 1 +#define IDC_DEVICE_INTERFACE_LIST 2 + diff --git a/general/toaster/toastpkg/toastapp/toastapp.c b/general/toaster/toastpkg/toastapp/toastapp.c new file mode 100644 index 00000000..d7eaebf3 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.c @@ -0,0 +1,813 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastapp.c + +Abstract: + + TOASTAPP is an application that provides an automatically updated list of + all currently available "toaster" devices (as enumerated by the toaster + sample in the Windows 2000 and Windows XP DDKs). + + The toasters' friendly names, along with their pathnames (i.e., for use + with CreateFile) are displayed in the dialog box. + +Notes: + + For a complete description of device interfaces and PnP event notification, + please see the Microsoft Windows 2000/Windows XP DDK and SDK Documentation. + +--*/ + +#include "precomp.h" +#pragma hdrstop + +// +// Instantiate toaster device interface class GUID (from DDK toaster sample, +// src\general\toaster\bus\common.h) +// +// {781EF630-72B2-11d2-B852-00C04FAD5171} +// + +#include <initguid.h> + +DEFINE_GUID (GUID_TOASTER_INTERFACE, 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); + +// +// Declare a global string buffer to be used when retrieving error text via +// FormatMessage. +// +TCHAR ErrorStringBuffer[1024]; + +// +// Define structure used to store device interface dialogbox data. +// +typedef struct _DIDLG_DATA { + HDEVINFO DeviceInfoSet; + HDEVNOTIFY hDevNotify; + GUID InterfaceClassGuid; +} DIDLG_DATA, *PDIDLG_DATA; + +// +// Function prototypes +// +INT_PTR +CALLBACK +DeviceInterfaceDlgProc( + _In_ HWND hwnd, + _In_ UINT msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOL +FillInDeviceInterfaceListBox( + _In_ HWND hWnd, + _In_ HDEVINFO DeviceInfoSet, + _In_ CONST GUID *InterfaceClassGuid + ); + +BOOL +GetDeviceInterfaceFriendlyName( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + _Out_writes_all_(FriendlyNameSize) PTSTR FriendlyName, + _In_ DWORD FriendlyNameSize + ); + +// +// Implementation +// + +int +__cdecl +_tmain( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + INT_PTR DlgResult; + DIDLG_DATA DIDlgData; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + // + // Initialize our dialogbox data structure. + // + ZeroMemory(&DIDlgData, sizeof(DIDlgData)); + + CopyMemory(&(DIDlgData.InterfaceClassGuid), + &GUID_TOASTER_INTERFACE, + sizeof(GUID) + ); + + // + // Now fire off the dialog that will present the automatically-updated list + // of active device interfaces. + // + DlgResult = DialogBoxParam(GetModuleHandle(NULL), + MAKEINTRESOURCE(IDD_DEVICE_INTERFACES), + NULL, + DeviceInterfaceDlgProc, + (LPARAM)&DIDlgData + ); + if(!DlgResult) { + if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + GetLastError(), + 0, + ErrorStringBuffer, + sizeof(ErrorStringBuffer) / sizeof(TCHAR), + NULL)) { + + _tprintf(TEXT("%s"), ErrorStringBuffer); + } + return -1; + + } else { + return 0; + } +} + + +INT_PTR +CALLBACK +DeviceInterfaceDlgProc( + _In_ HWND hWnd, + _In_ UINT msg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + This is the dialog procedure for the device interface dialog box that + presents an automatically-updated list of active device interfaces. + + It expects to get an lParam during WM_INITDIALOG that is a pointer to a + DIDLGDATA structure where the InterfaceClassGuid field is initialized to + the interface class GUID for which the device interface list is to be + displayed. (The other fields in this structure are initialized, used, and + destroyed during the lifetime of the dialogbox.) + +--*/ + +{ + PDIDLG_DATA DIDlgData; + DWORD Err; + PDEV_BROADCAST_DEVICEINTERFACE DevBroadcastDeviceInterface; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + + if(msg == WM_INITDIALOG) { + + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter; + HDEVINFO NewDeviceInfoSet; + + DIDlgData = (PDIDLG_DATA)lParam; + + // + // Create a device information set that will be the container for our + // device interfaces. + // + DIDlgData->DeviceInfoSet = SetupDiCreateDeviceInfoList(NULL, NULL); + + if(DIDlgData->DeviceInfoSet == INVALID_HANDLE_VALUE) { + Err = GetLastError(); + _tprintf(TEXT("SetupDiCreateDeviceInfoList failed with %lx\n"), Err); + goto clean0; + } + + // + // Now register to begin receiving notifications for the comings + // and goings of device interfaces which are members of the + // interface class whose GUID was passed in as the lParam to this + // dialog procedure. + // + ZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + CopyMemory(&(NotificationFilter.dbcc_classguid), &(DIDlgData->InterfaceClassGuid), sizeof(GUID)); + + DIDlgData->hDevNotify = RegisterDeviceNotification(hWnd, + &NotificationFilter, + DEVICE_NOTIFY_WINDOW_HANDLE + ); + if(!DIDlgData->hDevNotify) { + Err = GetLastError(); + _tprintf(TEXT("RegisterDeviceNotification failed with %lx\n"), Err); + goto clean1; + } + + // + // OK, now we can retrieve the existing list of active device + // interfaces into the device information set we created above. + // + NewDeviceInfoSet = SetupDiGetClassDevsEx(&(DIDlgData->InterfaceClassGuid), + NULL, + NULL, + DIGCF_PRESENT | DIGCF_DEVICEINTERFACE, + DIDlgData->DeviceInfoSet, + NULL, + NULL + ); + + if(NewDeviceInfoSet == INVALID_HANDLE_VALUE) { + Err = GetLastError(); + _tprintf(TEXT("SetupDiGetClassDevsEx failed with %lx\n"), Err); + goto clean2; + } + + // + // If SetupDiGetClassDevsEx succeeds and it was passed in an + // existing device information set to be used, then the HDEVINFO + // it returns is the same as the one it was passed in. Thus, we + // can just use the original DeviceInfoSet handle from here on. + // + + // + // Now fill in our listbox with the current device interface list. + // + if(!FillInDeviceInterfaceListBox(hWnd, + DIDlgData->DeviceInfoSet, + &(DIDlgData->InterfaceClassGuid))) { + Err = GetLastError(); + goto clean2; + } + + // + // Success! Store away a pointer to our device interface dialog data + // structure. + // + SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)DIDlgData); + return TRUE; + + // + // Clean-up code for error path... + // +clean2: + UnregisterDeviceNotification(DIDlgData->hDevNotify); +clean1: + SetupDiDestroyDeviceInfoList(DIDlgData->DeviceInfoSet); +clean0: + if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + HRESULT_FROM_SETUPAPI(Err), + 0, + ErrorStringBuffer, + sizeof(ErrorStringBuffer) / sizeof(TCHAR), + NULL)) { + + _tprintf(TEXT("%s"), ErrorStringBuffer); + } + + EndDialog(hWnd, 0); + SetLastError(Err); + return TRUE; + } else { + // + // For the small set of messages that we get before WM_INITDIALOG, we + // won't have a devwizdata pointer! + // + DIDlgData = (PDIDLG_DATA)GetWindowLongPtr(hWnd, DWLP_USER); + if(DIDlgData == NULL) { + // + // If we haven't gotten a WM_INITDIALOG message yet, or if for some + // reason we weren't able to retrieve the DIDlgData pointer when we + // did, then we simply return FALSE. + // + return FALSE; + } + } + + switch(msg) { + + case WM_COMMAND: + if(LOWORD(wParam) == IDOK) { + // + // Clean up and return. + // + UnregisterDeviceNotification(DIDlgData->hDevNotify); + SetupDiDestroyDeviceInfoList(DIDlgData->DeviceInfoSet); + SetWindowLongPtr(hWnd, DWLP_USER, 0); + EndDialog(hWnd, 1); + return TRUE; + } + + // + // All other WM_COMMAND messages unhandled. + // + break; + + case WM_DEVICECHANGE: + // + // All the events we're interested in come with lParam pointing to + // a structure headed by a DEV_BROADCAST_HDR. This is denoted by + // bit 15 of wParam being set, and bit 14 being clear. + // + if((wParam & 0xC000) == 0x8000) { + // + // Make sure that this is a device interface notification... + // + if(((PDEV_BROADCAST_HDR)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { + DevBroadcastDeviceInterface = (PDEV_BROADCAST_DEVICEINTERFACE)lParam; + } else { + // + // This isn't a device interface notification. Instead, + // it's a broadcasted notification sent for backwards- + // compatibility (e.g., DBT_DEVTYP_VOLUME). + // + break; + } + + if(wParam == DBT_DEVICEARRIVAL) { + _tprintf(TEXT("Received DBT_DEVICEARRIVAL for %s\n"), DevBroadcastDeviceInterface->dbcc_name); + } else if(wParam == DBT_DEVICEREMOVEPENDING) { + _tprintf(TEXT("Received DBT_DEVICEREMOVEPENDING for %s\n"), DevBroadcastDeviceInterface->dbcc_name); + } else if(wParam == DBT_DEVICEREMOVECOMPLETE) { + _tprintf(TEXT("Received DBT_DEVICEREMOVECOMPLETE for %s\n"), DevBroadcastDeviceInterface->dbcc_name); + } else { + // + // Presently, there are no other events that are sent for + // device interface notification, thus we should never get + // here. + // + break; + } + + } else { + // + // We received some broadcasted system message we don't care + // about (e.g., DBT_QUERYCHANGECONFIG). + // + break; + } + + if(wParam == DBT_DEVICEARRIVAL) { + // + // Open this new device interface into our device information + // set. + // + if(!SetupDiOpenDeviceInterface(DIDlgData->DeviceInfoSet, + DevBroadcastDeviceInterface->dbcc_name, + 0, + NULL)) { + Err = GetLastError(); + _tprintf(TEXT("SetupDiOpenDeviceInterface failed with %lx\n"), Err); + return TRUE; + } + + } else { + // + // First, locate this device interface in our device information + // set. + // + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + if(SetupDiOpenDeviceInterface(DIDlgData->DeviceInfoSet, + DevBroadcastDeviceInterface->dbcc_name, + DIODI_NO_ADD, + &DeviceInterfaceData)) { + + if(!SetupDiDeleteDeviceInterfaceData(DIDlgData->DeviceInfoSet, + &DeviceInterfaceData)) { + + Err = GetLastError(); + _tprintf(TEXT("SetupDiDeleteDeviceInterfaceData failed with %lx\n"), Err); + return TRUE; + } + } + } + + // + // If we get to here, we've successfully added or deleted a + // device interface in our device information set. Now go update + // our listbox with the new list. (Ignore any errors.) + // + FillInDeviceInterfaceListBox(hWnd, + DIDlgData->DeviceInfoSet, + &(DIDlgData->InterfaceClassGuid) + ); + + return TRUE; + + default: + break; + } + + return FALSE; +} + + +BOOL +FillInDeviceInterfaceListBox( + _In_ HWND hWnd, + _In_ HDEVINFO DeviceInfoSet, + _In_ CONST GUID *InterfaceClassGuid + ) + +/*++ + +Routine Description: + + This routine fills in the listbox of currently-active device interfaces + with their corresponding friendly names and pathnames. + +Arguments: + + hWnd - Supplies the window handle of the dialog box containing the device + interface listbox to be updated. + + DeviceInfoSet - Supplies a handle to the device information set containing + device interfaces to be used in updating the listbox. + + InterfaceClassGuid - Supplies the address of the interface class GUID for + the device interfaces to be placed into the listbox. + +Return Value: + + If the function succeeds, the return value is non-zero. + If the function fails, the return value is FALSE. To find out what the + cause of failure was, call GetLastError(). + +--*/ + +{ + DWORD i, Err; + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData; + PTSTR FriendlyName; + PSP_DEVICE_INTERFACE_DETAIL_DATA DeviceInterfaceDetailData; + PBYTE Buffer; + DWORD BufferSize = 0; + DWORD RequiredSize; + LRESULT ListBoxReturn; + size_t FriendlyNameLen; + size_t devicePathLen; + + // + // Reset the listbox in preparation for adding the current list of device + // interfaces. + // + SendDlgItemMessage(hWnd, + IDC_DEVICE_INTERFACE_LIST, + LB_RESETCONTENT, + 0, + 0 + ); + + DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + Err = NO_ERROR; + + // + // Start out with a buffer that should be large enough to hold the friendly + // name plus the device interface detail data for a "reasonably-sized" + // device interface pathname. Note that device interface paths aren't + // confined to MAX_PATH length on Windows 2000, so we deal with the case + // where we may need a larger buffer. + // + // Note that we add a space and an open paren between the friendly name and + // the pathname. We have space for this (even in Unicode), because the + // device interface detail data buffer always begins with a DWORD cbSize + // field, that we can overwrite, without touching the character DevicePath + // buffer. + // + BufferSize = (LINE_LEN * sizeof(TCHAR)) + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + + (MAX_PATH * sizeof(TCHAR)); + + Buffer = malloc(BufferSize); + + if(Buffer) { + // + // Leave the first LINE_LEN characters to retrieve the friendly name + // into... + // + FriendlyName = (PTSTR)Buffer; + DeviceInterfaceDetailData = + (PSP_DEVICE_INTERFACE_DETAIL_DATA)(Buffer + (LINE_LEN * sizeof(TCHAR))); + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + } else { + // + // Failure! + // + _tprintf(TEXT("Couldn't allocate %d bytes for device interface detail buffer\n"), + BufferSize + ); + + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + for(i = 0; + SetupDiEnumDeviceInterfaces(DeviceInfoSet, + NULL, + InterfaceClassGuid, + i, + &DeviceInterfaceData); + i++) { + + // + // To retrieve the device interface name (e.g., that you can call + // CreateFile() on... + // + while(!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, + &DeviceInterfaceData, + DeviceInterfaceDetailData, + BufferSize - (LINE_LEN * sizeof(TCHAR)), + &RequiredSize, + NULL)) { + // + // We failed to get the device interface detail data--was it because + // our buffer was too small? (Hopefully so!) + // + Err = GetLastError(); + + // + // We can get rid of our current buffer regardless of what the + // error was... + // + free(Buffer); + Buffer = NULL; + + if(Err != ERROR_INSUFFICIENT_BUFFER) { + // + // Failure! + // + _tprintf(TEXT("SetupDiGetDeviceInterfaceDetail failed with %lx\n"), Err); + break; + } + + // + // We failed due to insufficient buffer. Allocate one that's + // sufficiently large and try again. + // + BufferSize = RequiredSize + (LINE_LEN * sizeof(TCHAR)); + + Buffer = malloc(BufferSize); + + if(Buffer) { + // + // Leave the first LINE_LEN characters to retrieve the friendly + // name into... + // + FriendlyName = (PTSTR)Buffer; + DeviceInterfaceDetailData = + (PSP_DEVICE_INTERFACE_DETAIL_DATA)(Buffer + (LINE_LEN * sizeof(TCHAR))); + + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + + Err = NO_ERROR; + + } else { + // + // Failure! + // + Err = ERROR_NOT_ENOUGH_MEMORY; + _tprintf(TEXT("Couldn't allocate %d bytes for device interface detail buffer\n"), RequiredSize); + break; + } + } + + if(!Buffer) { + // + // We encountered a failure above--abort. + // + break; + } + + // + // Now that we've successfully retrieved the device interface pathname, + // we can retrieve the friendly name. We left enough space at the + // start of the buffer for this, so we'll now retrieve this string, + // then move the pathname down next to it for display (the pathname + // will be enclosed in parentheses). + // + if(!GetDeviceInterfaceFriendlyName(DeviceInfoSet, + &DeviceInterfaceData, + FriendlyName, + LINE_LEN)) { + // + // This generally won't happen, but it _is_ possible. We'll just + // use two double-quotes to indicate an empty string. + // + if(FAILED(StringCchCopy(FriendlyName, LINE_LEN, TEXT("\"\"")))) { + break; + } + } + + // + // Add a space and the opening paren (see previous comment on why we're + // safe in doing this without fear of overwriting the DevicePath string. + // + if(FAILED(StringCchCat(FriendlyName, LINE_LEN, TEXT(" (")))) { + break; + } + + if(FAILED(StringCchLength(FriendlyName, LINE_LEN, &FriendlyNameLen))) { + break; + } + + // + // Now move the pathname down to the character immediately following + // the open paren. (Note: since source and destination blocks may + // overlap, we must use MoveMemory.) + // + if(FAILED(StringCbLength(DeviceInterfaceDetailData->DevicePath, + MAX_PATH, + &devicePathLen))) { + break; + } + + devicePathLen += sizeof(TCHAR); + + MoveMemory((PBYTE)(FriendlyName + FriendlyNameLen), + DeviceInterfaceDetailData->DevicePath, + devicePathLen + ); + + // + // Now add close paren + // + if (FAILED(StringCchCat(FriendlyName, LINE_LEN, TEXT(")")))) { + break; + } + + // + // Add this device interface to our listbox. + // + ListBoxReturn = SendDlgItemMessage(hWnd, + IDC_DEVICE_INTERFACE_LIST, + LB_ADDSTRING, + 0, + (LPARAM)FriendlyName + ); + + if((ListBoxReturn == LB_ERR) || (ListBoxReturn == LB_ERRSPACE)) { + // + // Set Err to some generic failure + // + Err = ERROR_INVALID_DATA; + + _tprintf(TEXT("Failed to add %s to listbox (%s)\n"), + DeviceInterfaceDetailData->DevicePath, + (ListBoxReturn == LB_ERR) ? TEXT("LB_ERR") : TEXT("LB_ERRSPACE") + ); + break; + } + + // + // Since we may have overwritten the device interface detail data + // 'cbSize' field, restore it now. + // + DeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + } + + if(Buffer) { + free(Buffer); + } + + SetLastError(Err); + + return (Err == NO_ERROR); +} + + +BOOL +GetDeviceInterfaceFriendlyName( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + _Out_writes_all_(FriendlyNameSize) PTSTR FriendlyName, + _In_ DWORD FriendlyNameSize + ) + +/*++ + +Routine Description: + + This routine retrieves the friendly name associated with the specified + device interface. It first looks for a "FriendlyName" value entry in the + device interface's registry key. If not found, it then tries to use the + "FriendlyName" property for the underlying devnode. If that isn't present, + it uses the devnode's device description (and if there isnt one of those, + it returns FALSE). + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set containing + the device interface whose friendly name is to be retrieved. + + DeviceInterfaceData - Supplies a context structure indicating which device + interface we're retrieving a friendly name for. + + FriendlyName - Supplies a character buffer that is filled in, upon + successful return, with the friendly name for the device interface. + + FriendlyNameSize - Supplies the size, in characters, of the FriendlyName + buffer. + +Return Value: + + If the function succeeds, the return value is non-zero. + If no FriendlyName is found (or buffer is too small), the return value is + FALSE. + +--*/ + +{ + HKEY hkey; + DWORD Err; + SP_DEVINFO_DATA DeviceInfoData; + DWORD RegDataType, RegDataLength; + + // + // First, open up the device interface registry key to see if the interface + // has its own friendly name. + // + hkey = SetupDiOpenDeviceInterfaceRegKey(DeviceInfoSet, + DeviceInterfaceData, + 0, + KEY_READ + ); + + if(hkey != INVALID_HANDLE_VALUE) { + + RegDataLength = FriendlyNameSize * sizeof(TCHAR); + + Err = RegQueryValueEx(hkey, + TEXT("FriendlyName"), + NULL, + &RegDataType, + (PBYTE)FriendlyName, + &RegDataLength + ); + + RegCloseKey(hkey); + + if((Err == ERROR_SUCCESS) && (RegDataType == REG_SZ)) { + return TRUE; + } + } + + // + // Find out what device instance is exposing this interface. + // + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + if(!SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, + DeviceInterfaceData, + NULL, + 0, + NULL, + &DeviceInfoData)) { + // + // We should always get here (i.e., SetupDiGetDeviceInterfaceDetail + // should always fail) since we didn't pass in a buffer to retrieve + // the device interface detail data. Of course, all we really care + // about is getting at the underlying device info data. + // + + // + // Now check the underlying device for a FriendlyName property. + // + if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + &DeviceInfoData, + SPDRP_FRIENDLYNAME, + &RegDataType, + (PBYTE)FriendlyName, + FriendlyNameSize * sizeof(TCHAR), + NULL)) { + if(RegDataType == REG_SZ) { + return TRUE; + } + } + + // + // Fall back to device description + // + if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + &DeviceInfoData, + SPDRP_DEVICEDESC, + &RegDataType, + (PBYTE)FriendlyName, + FriendlyNameSize * sizeof(TCHAR), + NULL)) { + if(RegDataType == REG_SZ) { + return TRUE; + } + } + } + + // + // Couldn't find anything usable as a friendly name--return failure. + // + return FALSE; +} + diff --git a/general/toaster/toastpkg/toastapp/toastapp.dlg b/general/toaster/toastpkg/toastapp/toastapp.dlg new file mode 100644 index 00000000..d3cc1e53 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.dlg @@ -0,0 +1,12 @@ +1 DLGINCLUDE "rc_ids.h" + +IDD_DEVICE_INTERFACES DIALOG 82, 80, 412, 215 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Currently Available Toasters" +FONT 8, "MS Shell Dlg" +BEGIN + LISTBOX IDC_DEVICE_INTERFACE_LIST, 8, 9, 396, 177, LBS_SORT | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "OK", IDD_DEVICE_INTERFACES, 181, 195, 50, 14 +END diff --git a/general/toaster/toastpkg/toastapp/toastapp.h b/general/toaster/toastpkg/toastapp/toastapp.h new file mode 100644 index 00000000..bf34ba76 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastapp.h + +Abstract: + + Header files used by the TOASTAPP sample application. + +--*/ + +#include <windows.h> +#include <objbase.h> +#include <setupapi.h> +#include <dbt.h> + +#include <stdlib.h> +#include <stdio.h> +#include <tchar.h> + +#include "rc_ids.h" diff --git a/general/toaster/toastpkg/toastapp/toastapp.ico b/general/toaster/toastpkg/toastapp/toastapp.ico Binary files differnew file mode 100644 index 00000000..55ab969e --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.ico diff --git a/general/toaster/toastpkg/toastapp/toastapp.rc b/general/toaster/toastpkg/toastapp/toastapp.rc new file mode 100644 index 00000000..857a81b3 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.rc @@ -0,0 +1,69 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastapp.rc + +Abstract: + + Resources used by the TOASTAPP sample application. + +--*/ + +#include <windows.h> +#include <commctrl.h> +#include "rc_ids.h" + +// +// Version resources +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Microsoft Corporation\0" + VALUE "FileDescription", "Toaster Interface Notification Test Application\0" + VALUE "FileVersion", "1.00.0000.0\0" + VALUE "InternalName", "TOASTAPP.EXE\0" + VALUE "LegalCopyright", "� Microsoft Corporation. All rights reserved.\0" + VALUE "OriginalFilename", "TOASTAPP.EXE\0" + VALUE "ProductName", "Toaster DDK Sample\0" + VALUE "ProductVersion", "1.0.0000.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +// +// Icon resources +// +1 ICON DISCARDABLE "toastapp.ico" + +// +// Dialog resources +// +#include "toastapp.dlg" + diff --git a/general/toaster/toastpkg/toastapp/toastapp.vcxproj b/general/toaster/toastpkg/toastapp/toastapp.vcxproj new file mode 100644 index 00000000..9e71f3da --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.vcxproj @@ -0,0 +1,209 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{1C818755-28B2-4C84-8623-FF84F3326B64}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{42007D8E-51B7-469B-B5D0-45C7674BFFEF}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>toastapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>toastapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>toastapp</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>toastapp</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="toastapp.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="toastapp.rc" /> + </ItemGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters b/general/toaster/toastpkg/toastapp/toastapp.vcxproj.Filters new file mode 100644 index 00000000..bcbb10b1 --- /dev/null +++ b/general/toaster/toastpkg/toastapp/toastapp.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>{5B7E141F-3C1C-446C-B423-22D8F13BD05C}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{21C18B76-71F9-4B0C-B377-B15E4821D9CD}</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>{67F5F556-F3BD-4452-88F3-806BDB94EB5F}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="toastapp.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="toastapp.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastcd/ToastApp/setup.ini b/general/toaster/toastpkg/toastcd/ToastApp/setup.ini Binary files differnew file mode 100644 index 00000000..81d61154 --- /dev/null +++ b/general/toaster/toastpkg/toastcd/ToastApp/setup.ini diff --git a/general/toaster/toastpkg/toastcd/ToastApp/toastapp.msi b/general/toaster/toastpkg/toastcd/ToastApp/toastapp.msi Binary files differnew file mode 100644 index 00000000..0bdfaa65 --- /dev/null +++ b/general/toaster/toastpkg/toastcd/ToastApp/toastapp.msi diff --git a/general/toaster/toastpkg/toastcd/amd64/toaster.sys b/general/toaster/toastpkg/toastcd/amd64/toaster.sys Binary files differnew file mode 100644 index 00000000..d51da6c4 --- /dev/null +++ b/general/toaster/toastpkg/toastcd/amd64/toaster.sys diff --git a/general/toaster/toastpkg/toastcd/autorun.inf b/general/toaster/toastpkg/toastcd/autorun.inf new file mode 100644 index 00000000..4c582d7b --- /dev/null +++ b/general/toaster/toastpkg/toastcd/autorun.inf @@ -0,0 +1,15 @@ +[AutoRun] +open=i386\toastva.exe +icon=i386\toastva.exe,0 + +[AutoRun.i386] +open=i386\toastva.exe + +[AutoRun.ia64] +open=ia64\toastva.exe + +[AutoRun.amd64] +open=amd64\toastva.exe + +[DeviceInstall] +DriverPath=\ diff --git a/general/toaster/toastpkg/toastcd/i386/toaster.sys b/general/toaster/toastpkg/toastcd/i386/toaster.sys Binary files differnew file mode 100644 index 00000000..19184dc9 --- /dev/null +++ b/general/toaster/toastpkg/toastcd/i386/toaster.sys diff --git a/general/toaster/toastpkg/toastcd/toastpkg.inf b/general/toaster/toastpkg/toastcd/toastpkg.inf new file mode 100644 index 00000000..f427ae87 --- /dev/null +++ b/general/toaster/toastpkg/toastcd/toastpkg.inf @@ -0,0 +1,137 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; +; TOASTPKG.INF +; +;Abstract: +; +; INF file for installing toaster device drivers (and, optionally, value- +; added software) via device-specific coinstaller. +; This is a mutlios INF file. Same INF file cab be used on +; x86, ia64 and amd64 platforms. +; +;--*/ +[Version] +Signature="$WINDOWS NT$" +Class=TOASTER +ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} +Provider=%ToastRUs% +DriverVer=09/21/2006,6.0.5736.1 +CatalogFile.NTx86 = tostx86.cat +CatalogFile.NTIA64 = tostia64.cat +CatalogFile.NTAMD64 = tstamd64.cat + +[DestinationDirs] +DefaultDestDir = 12 +CoInstaller_CopyFiles = 11 +ToasterClassInstallerCopyFiles = 11 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=ToasterClassReg +CopyFiles=ToasterClassInstallerCopyFiles + +[ToasterClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,100 +HKR,,Installer32,,"tostrcls.dll,ToasterClassInstaller" +HKR,,DeviceCharacteristics,0x10001,0x100 ; Use same security checks on relative opens + +[ToasterClassInstallerCopyFiles] +tostrcls.dll + +;***************************************** +; Toaster Device Install Section +;***************************************** + +[Manufacturer] +%ToastRUs%=ToastRUs,NTx86, NTia64, NTamd64 + +; For Win2K +[ToastRUs] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +; For XP and later +[ToastRUs.NTx86] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +[ToastRUs.NTia64] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + +[ToastRUs.NTamd64] +%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster + + +[Toaster_Device.NT] +CopyFiles=Toaster_Device.NT.Copy +FriendlyNameFormat=%FriendlyNameFormat% + +[Toaster_Device.NT.Copy] +toaster.sys + +[Toaster_Device.NT.HW] +AddReg=Toaster_Device.NT.HW.AddReg + +[Toaster_Device.NT.HW.AddReg] +HKR,,"BeepCount",0x00010003,4 + +;-------------- Service installation + +[Toaster_Device.NT.Services] +AddService = toaster, %SPSVCINST_ASSOCSERVICE%, toaster_Service_Inst + +[toaster_Service_Inst] +DisplayName = %toaster.SVCDESC% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL +ServiceBinary = %12%\toaster.sys + +;-------------- Coinstaller installation + +[Toaster_Device.NT.CoInstallers] +AddReg=CoInstaller_AddReg +CopyFiles=CoInstaller_CopyFiles + +[CoInstaller_CopyFiles] +tostrco2.dll + +[CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000,"tostrco2.dll,ToasterCoInstaller" + +[ToastCoInfo] +; Used by the toaster co-installer to figure out where the original media is +; located (so it can launch value-added setup programs). +OriginalInfSourcePath = %1% + +[SourceDisksNames.x86] +1 = %DiskId1%, toastpkg.tag,,\i386 + +[SourceDisksNames.ia64] +1 = %DiskId1%, toastpkg.tag,,\ia64 + +[SourceDisksNames.amd64] +1 = %DiskId1%, toastpkg.tag,,\amd64 + +[SourceDisksFiles] +toaster.sys = 1,, +tostrco2.dll = 1,, +tostrcls.dll = 1,, + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +ToastRUs = "Toast'R'Us" +ClassName = "Toaster" +DiskId1 = "Toaster Device Installation Disk #1" +ToasterDevice.DeviceDesc = "Toaster Package Sample Toaster" +toaster.SVCDESC = "Microsoft Toaster Device Driver" +FriendlyNameFormat = "ToasterDevice%1!u!" diff --git a/general/toaster/toastpkg/toastcd/toastpkg.tag b/general/toaster/toastpkg/toastcd/toastpkg.tag new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/general/toaster/toastpkg/toastcd/toastpkg.tag diff --git a/general/toaster/toastpkg/toastcd/tostx86.cat b/general/toaster/toastpkg/toastcd/tostx86.cat Binary files differnew file mode 100644 index 00000000..31450f2f --- /dev/null +++ b/general/toaster/toastpkg/toastcd/tostx86.cat diff --git a/general/toaster/toastpkg/toastcd/tstamd64.cat b/general/toaster/toastpkg/toastcd/tstamd64.cat Binary files differnew file mode 100644 index 00000000..f91fe53f --- /dev/null +++ b/general/toaster/toastpkg/toastcd/tstamd64.cat diff --git a/general/toaster/toastpkg/toastco/precomp.h b/general/toaster/toastpkg/toastco/precomp.h new file mode 100644 index 00000000..2b688022 --- /dev/null +++ b/general/toaster/toastpkg/toastco/precomp.h @@ -0,0 +1,21 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + precomp.h + +Abstract: + + Single container to facilitate use of precompiled headers. + +--*/ + +#include "toastco.h" +#include <strsafe.h> diff --git a/general/toaster/toastpkg/toastco/precompsrc.c b/general/toaster/toastpkg/toastco/precompsrc.c new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/general/toaster/toastpkg/toastco/precompsrc.c @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastco/toastco.c b/general/toaster/toastpkg/toastco/toastco.c new file mode 100644 index 00000000..a66b07ac --- /dev/null +++ b/general/toaster/toastpkg/toastco/toastco.c @@ -0,0 +1,1312 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastco.c + +Abstract: + + Device-specific co-installer for the Toaster Package sample. + +--*/ + +#include "precomp.h" +#pragma hdrstop + +// +// Constants +// +#define TOASTAPP_SETUP_SUBDIR L"ToastApp" +#define TOASTAPP_SETUP_EXE L"\\setup.exe" +#define TOASTAPP_SETUP_PATH (TOASTAPP_SETUP_SUBDIR TOASTAPP_SETUP_EXE) + +#define TOASTER_MEDIA_SOURCE_ID 1 + +// +// Globals +// +HMODULE g_hInstance; +WCHAR SetupExeName[] = TOASTAPP_SETUP_EXE; + +// +// Structures +// +typedef struct _VALUEADDWIZDATA { + BOOL AppInstallAttempted; // Have we previously attempted to install app? + WCHAR MediaRootDirectory[MAX_PATH]; // Fully-qualified path to root of install media + WCHAR MediaDiskName[LINE_LEN]; // Name of media to prompt for (or empty string) + WCHAR MediaTagFile[MAX_PATH]; // Tagfile identifying removable media (or empty string) +} VALUEADDWIZDATA, *LPVALUEADDWIZDATA; + +// +// Function prototypes +// +INT_PTR +CALLBACK +ValueAddDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +BOOL +InstallToastApp( + _In_ HWND hwndDlg, + _In_ LPCWSTR MediaRootDirectory + ); + +UINT +ValueAddPropSheetPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ); + +_Success_(return == TRUE) +BOOL +GetMediaRootDirectory( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _Out_ LPWSTR *MediaRootDirectory, + _Outptr_result_maybenull_ LPWSTR *MediaDiskName, + _Outptr_result_maybenull_ LPWSTR *MediaTagFile + ); + +HPROPSHEETPAGE +GetValueAddSoftwareWizPage( + _In_ LPCWSTR MediaRootDirectory, + _In_opt_ LPCWSTR MediaDiskName, + _In_opt_ LPCWSTR MediaTagFile + ); + +VOID +SetDeviceFriendlyName( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData + ); + +// +// Implementation +// + +BOOL WINAPI +DllMain( + _In_ HINSTANCE hInstDll, + _In_ DWORD Reason, + _In_ LPVOID Reserved + ) + +/*++ + +Routine Description: + + Initialization/de-initialization entry point for toastco.dll + +Arguments: + + hInstDll - Supplies handle to the DLL module + + Reason - Supplies the reason for calling the function + + pctx - Reserved + +Return Value: + + This function always returns TRUE. + +--*/ + +{ + UNREFERENCED_PARAMETER(Reserved); + + switch(Reason) { + + case DLL_PROCESS_ATTACH: + g_hInstance = hInstDll; + break; + + case DLL_PROCESS_DETACH: + g_hInstance = NULL; + break; + + default: + break; + } + + return TRUE; +} + + +DWORD CALLBACK +ToasterCoInstaller( + _In_ DI_FUNCTION InstallFunction, + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, + _Inout_ PCOINSTALLER_CONTEXT_DATA Context + ) + +/*++ + +Routine Description: + + This function acts as a device-specific co-installer for "toaster" devices. + +Arguments: + + InstallFunction - Specifies the device installer function code indicating + the action being performed. + + DeviceInfoSet - Supplies a handle to the device information set being + acted upon by this install action. + + DeviceInfoData - Optionally, supplies the address of a device information + element being acted upon by this install action. + + Context - Supplies the installation context that is per-install request/ + per-coinstaller. + +Return Value: + + If this function successfully completed the requested action (or did + nothing) and wishes for the installation to continue, the return value + is NO_ERROR. + + If this function successfully completed the requested action (or did + nothing) and would like to be called back once installation has + completed, the return value is ERROR_DI_POSTPROCESSING_REQUIRED. + + If an error occurred while attempting to perform the requested action, a + Win32 error code is returned. The install action will be aborted. + +--*/ + +{ + SP_NEWDEVICEWIZARD_DATA NewDeviceWizardData; + HKEY hKey; + DWORD Err; + DWORD RegDataType; + DWORD RequiredSize; + DWORD UserPrompted; + PWSTR MediaRootDirectory, MediaDiskName, MediaTagFile; + + UNREFERENCED_PARAMETER( Context ); + + switch(InstallFunction) { + + case DIF_INSTALLDEVICE: + // + // In version 1 of our coinstaller, we had a hard-coded format + // for the device's FriendlyName. This wasn't a localizable + // solution. Now, we retrieve a (localized) format string from + // the device INF. + // + // We should always get called with a valid DeviceInfoData, but + // just to be sure... + // + if(DeviceInfoData != NULL) { + SetDeviceFriendlyName(DeviceInfoSet, DeviceInfoData); + } + + break; + + case DIF_NEWDEVICEWIZARD_FINISHINSTALL: + // + // We should always get called with a valid DeviceInfoData, but + // just in case we don't we will bail out right away. + // + if(DeviceInfoData == NULL) { + break; + } + + // + // Only supply a finish-install wizard page the first time... + // + if(ERROR_SUCCESS != RegOpenKeyEx( + HKEY_LOCAL_MACHINE, + TEXT("SOFTWARE\\Microsoft\\Toaster"), + 0, + KEY_READ, + &hKey)) { + // + // If we can't open this key, then we can't ascertain whether + // or not the user was previously prompted to select value-add + // software. Assume they haven't been (i.e., this is the first + // time, so the key doesn't exist yet). + // + UserPrompted = 0; + + } else { + // + // Look for non-zero "User Prompted" value entry to indicate + // that the user has previously responded to question about + // installation of value-add software. + // + RequiredSize = sizeof(UserPrompted); + + Err = RegQueryValueEx(hKey, + TEXT("User Prompted"), + NULL, + &RegDataType, + (PBYTE)&UserPrompted, + &RequiredSize + ); + + if(Err != ERROR_SUCCESS) { + UserPrompted = 0; + } + + RegCloseKey(hKey); + } + + if(UserPrompted) { + // + // We asked the user this question before--don't bother them + // again. + // + break; + } + + // + // It's possible that we could return the handle of our finish + // install wizard page, yet it might never be used (e.g., if we're + // in a server-side installation). Thus, we won't set our + // "User Prompted" registry flag just yet. We'll wait until the + // user actually sees this page before setting the flag. + // + + ZeroMemory(&NewDeviceWizardData, sizeof(NewDeviceWizardData)); + NewDeviceWizardData.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER); + + if(SetupDiGetClassInstallParams(DeviceInfoSet, + DeviceInfoData, + (PSP_CLASSINSTALL_HEADER)&NewDeviceWizardData, + sizeof(SP_NEWDEVICEWIZARD_DATA), + NULL)) { + // + // First, make sure there's room for us to add a page... + // + if(NewDeviceWizardData.NumDynamicPages >= MAX_INSTALLWIZARD_DYNAPAGES) { + break; + } + + // + // Retrieve the location of the source media based on the INF + // we're installing from. + // + if(!GetMediaRootDirectory(DeviceInfoSet, + DeviceInfoData, + &MediaRootDirectory, + &MediaDiskName, + &MediaTagFile)) { + // + // We couldn't figure out where the source media is, so we + // can't offer any value-added software to the user. + // + break; + } + + NewDeviceWizardData.DynamicPages[NewDeviceWizardData.NumDynamicPages] = + GetValueAddSoftwareWizPage(MediaRootDirectory, + MediaDiskName, + MediaTagFile + ); + + // + // We don't need the media strings any more. + // + GlobalFree(MediaRootDirectory); + + if(MediaDiskName) { + GlobalFree(MediaDiskName); + } + + if(MediaTagFile) { + GlobalFree(MediaTagFile); + } + + if(NewDeviceWizardData.DynamicPages[NewDeviceWizardData.NumDynamicPages] != NULL) { + NewDeviceWizardData.NumDynamicPages++; + } + + SetupDiSetClassInstallParams(DeviceInfoSet, + DeviceInfoData, + (PSP_CLASSINSTALL_HEADER)&NewDeviceWizardData, + sizeof(SP_NEWDEVICEWIZARD_DATA) + ); + } + + break; + + default: + break; + } + + return NO_ERROR; +} + + +BOOL +InstallToastApp( + _In_ HWND hwndWizard, + _In_ LPCWSTR FullSetupPath + ) + +/*++ + +Routine Description: + + This routine hides the wizard, kicks off the ToastApp setup program, then + unhides the wizard when the ToastApp setup process terminates. + +Arguments: + + hwndWizard - Handle to the wizard window to be hidden. + + FullSetupPath - Supplies the path to the setup program to be launched. + +Return Value: + + If the setup app was successfully launched, the return value is TRUE. + Otherwise, it is FALSE. + +--*/ + +{ + BOOL b; + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInformation; + + // + // Hide our wizard for the duration of the Toaster app's installation... + // + ShowWindow(hwndWizard, SW_HIDE); + GetStartupInfo(&StartupInfo); + + b = CreateProcess(FullSetupPath, + NULL, + NULL, + NULL, + FALSE, + DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, + NULL, + NULL, + &StartupInfo, + &ProcessInformation + ); + + if(b) { + // + // Don't need a handle to the thread... + // + CloseHandle(ProcessInformation.hThread); + + // + // ...but we _do_ want to wait on the process handle. + // + WaitForMultipleObjects(1, &ProcessInformation.hProcess, FALSE, INFINITE); + + CloseHandle(ProcessInformation.hProcess); + } + + // + // Now show our wizard once again... + // + ShowWindow(hwndWizard, SW_SHOW); + + return b; +} + + +UINT +ValueAddPropSheetPageProc( + _In_ HWND hwnd, + _In_ UINT uMsg, + _In_ LPPROPSHEETPAGE ppsp + ) + +/*++ + +Routine Description: + + This function is the property sheet page procedure, used to free the + context data associated with the page when it is released. + +Arguments: + + hwnd - Supplies a handle to the property page window + + uMsg - Supplies the message identifying the action being taken + + ppsp - Supplies the PROPSHEETPAGE structure for our page + +Return Value: + + This routine always return non-zero (1). + +--*/ + +{ + UNREFERENCED_PARAMETER(hwnd); + + switch(uMsg) { + + case PSPCB_RELEASE : + GlobalFree((LPVALUEADDWIZDATA)(ppsp->lParam)); + break; + + default : + break; + } + + return 1; // let the page be created (return ignored on page release) +} + + +INT_PTR +CALLBACK +ValueAddDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + This function is the dialog procedure for the value-add software selection + wizard page. If the user selects any software on this page, the software + will be automatically installed when the user presses "Next". + +Arguments: + + hwndDlg - Supplies a handle to the dialog box window + + uMsg - Supplies the message + + wParam - Supplies the first message parameter + + lParam - Supplies the second message parameter + +Return Value: + + This dialog procedure always returns zero. + +--*/ + +{ + LPVALUEADDWIZDATA pdata; + LPNMHDR lpnm; + HKEY hKey; + + UNREFERENCED_PARAMETER( wParam ); + + // + // Retrieve the shared user data from GWL_USERDATA + // + pdata = (LPVALUEADDWIZDATA) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(uMsg) { + + case WM_INITDIALOG : + // + // Get the PROPSHEETPAGE lParam value and load it into GWL_USERDATA + // + pdata = (LPVALUEADDWIZDATA) ((LPPROPSHEETPAGE)lParam)->lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)pdata); + break; + + case WM_NOTIFY : + + lpnm = (LPNMHDR)lParam; + + switch(lpnm->code) { + + case PSN_SETACTIVE : + // + // Enable the Next and Back buttons + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT); + break; + + case PSN_WIZNEXT : + // + // Install any applications the user selected. + // + if(IsDlgButtonChecked(hwndDlg, IDC_CHECK1) && !pdata->AppInstallAttempted) { + + BOOL MediaPresent = FALSE; + WCHAR PathToSetupExe[MAX_PATH]; + PWSTR LastChar; + + // + // If we need to prompt the user for media, do so now. + // + if(*(pdata->MediaDiskName)) { + + WCHAR TempString[64]; + size_t PathLength; + + if(!LoadString(g_hInstance, + IDS_MEDIA_PROMPT_TITLE, + TempString, + sizeof(TempString) / sizeof(WCHAR))) { + + *TempString = TEXT('\0'); + } + + // + // Append subdirectory where toastapp's setup.exe + // is located, so we can prompt user for media. + // + if (FAILED(StringCchLength(pdata->MediaRootDirectory, + MAX_PATH, + &PathLength))) { + break; + } + + LastChar = pdata->MediaRootDirectory + PathLength; + + if(FAILED(StringCchCopy(LastChar, + MAX_PATH - PathLength, + TOASTAPP_SETUP_SUBDIR))) { + break; + } + + // + // (Note, we skip the first character in + // SetupExeName for our "FileSought" argument + // below, because we don't want to include the + // first character, which is a path separator.) + // + if(DPROMPT_SUCCESS == SetupPromptForDisk( + GetParent(hwndDlg), + TempString, + pdata->MediaDiskName, + pdata->MediaRootDirectory, + SetupExeName+1, + pdata->MediaTagFile, + IDF_CHECKFIRST | IDF_NOBEEP, + PathToSetupExe, + MAX_PATH, + (PDWORD)&PathLength)) + { + MediaPresent = TRUE; + } + + // + // Strip the ToastApp subdir off media root path + // + *LastChar = L'\0'; + + if(MediaPresent) { + // + // SetupPromptForDisk gives us the directory + // where our setup program is located--now we + // need to append the setup program onto the + // end of that path. + // + PathLength--; // Don't include terminating null + + if((PathToSetupExe[PathLength-1] != L'\\') && + (PathToSetupExe[PathLength-1] != L'/')) { + // + // We need the path separator char... + // + if(FAILED(StringCchCopy(PathToSetupExe+PathLength, + MAX_PATH - PathLength, + SetupExeName))) { + break; + } + + } else { + // + // We don't need the path separator char... + // + if(FAILED(StringCchCopy(PathToSetupExe+PathLength, + MAX_PATH - PathLength, + SetupExeName+1))) { + break; + } + + } + } + + } else { + + // + // Assume media is already present (i.e., because + // we're in our auto-launch setup program running + // off the media. + // + MediaPresent = TRUE; + + // + // Construct the fully-qualified path to the setup + // executable. + // + if(FAILED(StringCchCopy(PathToSetupExe, + MAX_PATH, + pdata->MediaRootDirectory))) { + break; + } + + if(FAILED(StringCchCat(PathToSetupExe, + MAX_PATH, + TOASTAPP_SETUP_PATH))) { + break; + } + + } + + if(MediaPresent) { + // + // We're attempting app install. Success or + // failure, we don't want to try again. + // + pdata->AppInstallAttempted = TRUE; + + if(!InstallToastApp(GetParent(hwndDlg), PathToSetupExe)) { + // + // We failed to install the toast app. Un-check + // the checkbox before we disable it. + // + CheckDlgButton(hwndDlg, IDC_CHECK1, BST_UNCHECKED); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHECK1), FALSE); + } + } + + break; + + case PSN_KILLACTIVE : + // + // If we get to this point, we know that our wizard page + // has been displayed. We can now set the "User Prompted" + // registry flag, certain that the user has been given the + // opportunity to select the value-added software they wish + // to install. + // + if(ERROR_SUCCESS == RegCreateKeyEx( + HKEY_LOCAL_MACHINE, + TEXT("SOFTWARE\\Microsoft\\Toaster"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hKey, + NULL)) { + + DWORD UserPrompted = 1; + + RegSetValueEx(hKey, + TEXT("User Prompted"), + 0, + REG_DWORD, + (PBYTE)&UserPrompted, + sizeof(UserPrompted) + ); + + RegCloseKey(hKey); + } + + break; + + case PSN_WIZBACK : + //Handle a Back button click, if necessary + break; + + case PSN_RESET : + //Handle a Cancel button click, if necessary + break; + + default : + break; + } + + break; + + default: + break; + } + + return 0; +} + +_Success_(return == TRUE) +BOOL +GetMediaRootDirectory( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _Out_ LPWSTR *MediaRootDirectory, + _Outptr_result_maybenull_ LPWSTR *MediaDiskName, + _Outptr_result_maybenull_ LPWSTR *MediaTagFile + ) + +/*++ + +Routine Description: + + This function retrieves the root of the installation media for the INF + selected in the specified device information element. + + There are two possibilities here: + + 1. INF is on source media. If so, then just use that path. + + 2. INF is already in %windir%\Inf. This is less likely, because we + should've previously prompted the user to install software at the + time the INF was installed. However, perhaps someone called + SetupCopyOEMInf to install the INF without prompting the user for + value-add software selection. Another way you could get into this + state is if the user previously elected to install the application, + then subsequently uninstalled it via "Add/Remove Programs". The MSI + package is configured to delete the UserPrompted value from the + registry during uninstall, so if a new toaster is subsequently + inserted, the user will be prompted once again. + + When the INF is in %windir%\Inf, we need to retrieve the original + source location from which the INF was installed. Plug&Play stores + this information for 3rd-party INF files, but it is not directly + accessible. Fortunately, there is an INF DIRID that corresponds to + this path, so we retrieve the value of that DIRID from the INF in + order to ascertain the media root directory. + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set containing + the element for which an INF driver node is currently selected. + + DeviceInfoData - Supplies the address of a device information element for + which an INF driver node is currently selected. + + MediaRootDirectory - Supplies the address of a string pointer that, upon + successful return, will be set to point to a newly-allocated string + containing the root directory of the setup media. The caller must free + this buffer via GlobalFree. + + This pointer will be set to NULL upon error. + + MediaDiskName - Supplies the address of a string pointer that, upon + successful return will be set to either: + + 1. A newly-allocated string containing the disk name to be used + when prompting for the setup media (when INF is in %windir%\Inf) + 2. NULL (when INF isn't in %windir%\Inf it is presumed to be on + source media, hence no prompting is necessary) + + This pointer will be set to NULL upon error. + + MediaTagFile - Supplies the address of a string pointer that, upon + successful return will be set to either: + + 1. A newly-allocated string containing the disk tagfile to be used + when prompting for the setup media (when INF is in %windir%\Inf) + 2. NULL (when INF isn't in %windir%\Inf it is presumed to be on + source media, hence no prompting is necessary) + + This pointer will be set to NULL upon error. + +Return Value: + + If this function succeeds, the return value is non-zero (TRUE). + + If this function fails, the return value is FALSE. + +--*/ + +{ + SP_DRVINFO_DATA DriverInfoData; + PSP_DRVINFO_DETAIL_DATA DriverInfoDetailData = NULL; + LPWSTR FileNamePart; + WCHAR InfDirPath[MAX_PATH]; + BOOL b = FALSE; + HINF hInf = INVALID_HANDLE_VALUE; + INFCONTEXT InfContext; + DWORD PathLength; + + *MediaRootDirectory = NULL; + *MediaDiskName = NULL; + *MediaTagFile = NULL; + + // + // First, retrieve the full path of the INF being used to install this + // device. + // + DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + + if(!SetupDiGetSelectedDriver(DeviceInfoSet, DeviceInfoData, &DriverInfoData)) { + // + // This shouldn't fail, but if it does, just bail. + // + goto clean0; + } + + // + // Retrieve the driver info details. We don't care about the id list at + // the end, so we can just allocate a buffer for the fixed-size part... + // + DriverInfoDetailData = GlobalAlloc(0, sizeof(SP_DRVINFO_DETAIL_DATA)); + if(!DriverInfoDetailData) { + goto clean0; + } + DriverInfoDetailData->cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + + if(!SetupDiGetDriverInfoDetail(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData, + DriverInfoDetailData, + sizeof(SP_DRVINFO_DETAIL_DATA), + NULL) + && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + // + // Again, this should never fail, but if it does we're outta here. + // + goto clean0; + } + + *MediaRootDirectory = GlobalAlloc(0, MAX_PATH * sizeof(WCHAR)); + if(!*MediaRootDirectory) { + goto clean0; + } + + // + // Strip the INF name off of the path. (Resultant path will always end + // with a path separator char ('\\').) + // + PathLength = GetFullPathName(DriverInfoDetailData->InfFileName, + MAX_PATH, + *MediaRootDirectory, + &FileNamePart + ); + + if(!PathLength || (PathLength >= MAX_PATH)) { + goto clean0; + } + + *FileNamePart = L'\0'; + + // + // Check to see this INF is already in %windir%\Inf. + // + PathLength = GetSystemWindowsDirectory(InfDirPath, MAX_PATH); + + if(!PathLength || (PathLength >= MAX_PATH)) { + goto clean0; + } + + // + // Append INF directory to path (making sure we don't end up with two path + // separator chars). + // + if((InfDirPath[PathLength-1] != L'\\') && (InfDirPath[PathLength-1] != L'/')) { + if(FAILED(StringCchCopy(&(InfDirPath[PathLength]), + MAX_PATH - PathLength, + L"\\Inf\\"))) { + goto clean0; + } + } else { + + if(FAILED(StringCchCopy(&(InfDirPath[PathLength]), + MAX_PATH - PathLength, + L"Inf\\"))) { + goto clean0; + } + } + + if(lstrcmpi(*MediaRootDirectory, InfDirPath)) { + // + // The INF isn't in %windir%\Inf, so assume its location is the root of + // the installation media. (We don't bother to retrieve the disk name + // or tagfile name in this case.) + // + b = TRUE; + goto clean0; + } + + // + // Since the INF is already in %windir%\Inf, we need to find out where it + // originally came from. There is no direct way to ascertain an INF's + // path of origin, but we can indirectly determine it by retrieving a field + // from our INF that uses a string substitution of %1% (DIRID_SRCPATH). + // + hInf = SetupOpenInfFile(DriverInfoDetailData->InfFileName, + NULL, + INF_STYLE_WIN4, + NULL + ); + + if(hInf == INVALID_HANDLE_VALUE) { + goto clean0; + } + + // + // Contained within our INF should be a [ToastCoInfo] section with the + // following entry: + // + // OriginalInfSourcePath = %1% + // + // If we retrieve the value (i.e., field 1) of this line, we'll get the + // full path where the INF originally came from. + // + if(!SetupFindFirstLine(hInf, L"ToastCoInfo", L"OriginalInfSourcePath", &InfContext)) { + goto clean0; + } + + if(!SetupGetStringField(&InfContext, 1, *MediaRootDirectory, MAX_PATH, &PathLength) || + (PathLength <= 1)) { + goto clean0; + } + + // + // PathLength we get back includes the terminating null character. Subtract + // one to get actual length of string. + // + PathLength--; + + // + // Ensure the path we retrieved has a path separator character at the end. + // + if(((*MediaRootDirectory)[PathLength-1] != L'\\') && + ((*MediaRootDirectory)[PathLength-1] != L'/')) + { + if(FAILED(StringCchCopy(*MediaRootDirectory+PathLength, + MAX_PATH - PathLength, + L"\\"))) { + goto clean0; + } + } + + // + // Now retrieve the disk name and tagfile for our setup media. + // + *MediaDiskName = GlobalAlloc(0, LINE_LEN * sizeof(WCHAR)); + *MediaTagFile = GlobalAlloc(0, MAX_PATH * sizeof(WCHAR)); + + if(!(*MediaDiskName && *MediaTagFile)) { + goto clean0; + } + + if(!SetupGetSourceInfo(hInf, + TOASTER_MEDIA_SOURCE_ID, + SRCINFO_DESCRIPTION, + *MediaDiskName, + LINE_LEN, + NULL)) { + goto clean0; + } + + if(!SetupGetSourceInfo(hInf, + TOASTER_MEDIA_SOURCE_ID, + SRCINFO_TAGFILE, + *MediaTagFile, + MAX_PATH, + NULL)) { + goto clean0; + } + + b = TRUE; + +clean0: + + if(hInf != INVALID_HANDLE_VALUE) { + SetupCloseInfFile(hInf); + } + + if(DriverInfoDetailData) { + GlobalFree(DriverInfoDetailData); + } + + if(!b) { + if(*MediaRootDirectory) { + GlobalFree(*MediaRootDirectory); + *MediaRootDirectory = NULL; + } + if(*MediaDiskName) { + GlobalFree(*MediaDiskName); + *MediaDiskName = NULL; + } + if(*MediaTagFile) { + GlobalFree(*MediaTagFile); + *MediaTagFile = NULL; + } + } + + return b; +} + + +HPROPSHEETPAGE +GetValueAddSoftwareWizPage( + _In_ LPCWSTR MediaRootDirectory, + _In_opt_ LPCWSTR MediaDiskName, + _In_opt_ LPCWSTR MediaTagFile + ) + +/*++ + +Routine Description: + + This function returns a newly-created property sheet page handle that may + be used in a wizard to allow user-selection of value-added software. + + This wizard page is used by both the toaster co-installer (as a finish- + install wizard page), as well as by the toastva installation application. + +Arguments: + + MediaRootDirectory - Supplies the fully-qualified path to the root of the + installation media. + + MediaDiskName - Optionally, supplies the name of the disk to be used when + prompting the user for source media. If this parameter is not + supplied, the media is assumed to already be present, and no prompting + occurs + + MediaTagFile - Optionally, supplies the tagfile for the disk to be used + when prompting the user for source media. If MediaDiskName is not + specified, this parameter is ignored. + +Return Value: + + If this function succeeds, the return value is a newly-created property + sheet page handle. + + If this function fails, the return value is NULL. + +--*/ + +{ + HPROPSHEETPAGE hpsp; + LPVALUEADDWIZDATA ValueAddWizData; //data for the value-add sw chooser page + PROPSHEETPAGE page; + + ValueAddWizData = GlobalAlloc(0, sizeof(VALUEADDWIZDATA)); + + if(ValueAddWizData) { + ZeroMemory(ValueAddWizData, sizeof(VALUEADDWIZDATA)); + } else { + return NULL; + } + + if(FAILED(StringCchCopy(ValueAddWizData->MediaRootDirectory, + MAX_PATH, + MediaRootDirectory))) { + return NULL; + } + + if(MediaDiskName && MediaTagFile) { + // + // The caller wants us to prompt user for media (e.g., installation + // occurring from %windir%\Inf\OEM<n>.INF, and we want to ensure that + // our CD is in the drive before launching setup.exe from it). + // + if(FAILED(StringCchCopy(ValueAddWizData->MediaDiskName, + LINE_LEN, + MediaDiskName))) { + return NULL; + } + + if(FAILED(StringCchCopy(ValueAddWizData->MediaTagFile, + MAX_PATH, + MediaTagFile))) { + return NULL; + } + } + + ZeroMemory(&page, sizeof(PROPSHEETPAGE)); + + // + // Create the sample Wizard Page + // + page.dwSize = sizeof(PROPSHEETPAGE); + page.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE|PSP_USETITLE|PSP_USECALLBACK; + page.hInstance = g_hInstance; + page.pszHeaderTitle = MAKEINTRESOURCE(IDS_TITLE); + page.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE); + page.pszTemplate = MAKEINTRESOURCE(IDD_SAMPLE_INSTALLAPP); + page.pfnDlgProc = ValueAddDlgProc; + page.lParam = (LPARAM)ValueAddWizData; + page.pfnCallback = (LPFNPSPCALLBACKW) ValueAddPropSheetPageProc; + + hpsp = CreatePropertySheetPage(&page); + + if(!hpsp) { + GlobalFree(ValueAddWizData); + } + + return hpsp; +} + + +VOID +SetDeviceFriendlyName( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData + ) + +/*++ + +Routine Description: + + This function retrieves the (localized) string format (suitable for use + with FormatMessage) to be used in generating the device's friendly name, + then constructs the name using that format in concert with the device's UI + number. + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set containing + the element for which an INF driver node is currently selected. + + DeviceInfoData - Supplies the address of a device information element for + which an INF driver node is currently selected. + +Return Value: + + none + +--*/ + +{ + SP_DRVINFO_DATA DriverInfoData; + SP_DRVINFO_DETAIL_DATA DriverInfoDetailData; + HINF hInf; + WCHAR InfSectionWithExt[255]; + WCHAR FormatString[LINE_LEN]; + INFCONTEXT InfContext; + DWORD UINumber; + PVOID FriendlyNameBuffer; + DWORD FriendlyNameBufferSize; + + // + // First, retrieve the format string from the driver's [DDInstall] section. + // + DriverInfoData.cbSize = sizeof(SP_DRVINFO_DATA); + if(!SetupDiGetSelectedDriver(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData)) { + // + // NULL driver install + // + goto clean0; + } + + DriverInfoDetailData.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA); + if(!SetupDiGetDriverInfoDetail(DeviceInfoSet, + DeviceInfoData, + &DriverInfoData, + &DriverInfoDetailData, + sizeof(DriverInfoDetailData), + NULL) && + (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) + { + // + // Unable to retrieve detail info about selected driver node + // + goto clean0; + } + + hInf = SetupOpenInfFile(DriverInfoDetailData.InfFileName, + NULL, + INF_STYLE_WIN4, + NULL + ); + + if(hInf == INVALID_HANDLE_VALUE) { + // + // Couldn't open the INF + // + goto clean0; + } + + // + // Figure out actual (potentially decorated) DDInstall section being used + // for this install. + // + *FormatString = L'\0'; // default to empty string in case error occurs. + + if(SetupDiGetActualSectionToInstall(hInf, + DriverInfoDetailData.SectionName, + InfSectionWithExt, + sizeof(InfSectionWithExt) / sizeof(WCHAR), + NULL, + NULL)) { + + if(SetupFindFirstLine(hInf, + InfSectionWithExt, + L"FriendlyNameFormat", + &InfContext)) { + + if(!SetupGetStringField(&InfContext, + 1, + FormatString, + sizeof(FormatString) / sizeof(WCHAR), + NULL)) { + // + // Failed to retrieve format string into our buffer. Make sure + // our buffer still contains an empty string. + // + *FormatString = L'\0'; + } + } + } + + SetupCloseInfFile(hInf); + + if(!(*FormatString)) { + goto clean0; + } + + // + // Now retrieve the device's UI number, which is actually the serial number + // used by the bus driver. + // + if(SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + SPDRP_UI_NUMBER, + NULL, + (PBYTE)&UINumber, + sizeof(UINumber), + NULL)) { + + FriendlyNameBufferSize = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_STRING + | FORMAT_MESSAGE_ARGUMENT_ARRAY, + FormatString, + 0, + 0, + (LPWSTR)&FriendlyNameBuffer, + 0, + (va_list *)&UINumber + ); + + if(FriendlyNameBufferSize) { + + SetupDiSetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + SPDRP_FRIENDLYNAME, + (PBYTE)FriendlyNameBuffer, + (FriendlyNameBufferSize + 1) * sizeof(WCHAR) + ); + + LocalFree(FriendlyNameBuffer); + } + } + +clean0: + ; // nothing to do +} + diff --git a/general/toaster/toastpkg/toastco/toastco.h b/general/toaster/toastpkg/toastco/toastco.h new file mode 100644 index 00000000..ab1d4f9b --- /dev/null +++ b/general/toaster/toastpkg/toastco/toastco.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastco.h + +Abstract: + + Header files and resource IDs used by the Toaster sample co-installer. + +--*/ + + +#include <windows.h> +#include <setupapi.h> + + +#define IDD_SAMPLE_INSTALLAPP 900 +#define IDC_CHECK1 1000 +#define IDC_CHECK2 1001 +#define IDC_CHECK3 1002 +#define IDC_STATIC -1 +#define IDS_TITLE 1 +#define IDS_SUBTITLE 2 +#define IDS_MEDIA_PROMPT_TITLE 3 + diff --git a/general/toaster/toastpkg/toastco/toastco.rc b/general/toaster/toastpkg/toastco/toastco.rc new file mode 100644 index 00000000..384181ef --- /dev/null +++ b/general/toaster/toastpkg/toastco/toastco.rc @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastco.rc + +Abstract: + + Resources used by the Toaster sample co-installer + +--*/ + +#include "toastco.h" +#include <windows.h> + +// +// Version resources +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Microsoft Corporation\0" + VALUE "FileDescription", "Toaster CoInstaller Sample\0" + VALUE "FileVersion", "2.00.0000.0\0" + VALUE "InternalName", "TOSTRCO2.DLL\0" + VALUE "LegalCopyright", "� Microsoft Corporation. All rights reserved.\0" + VALUE "OriginalFilename", "TOSTRCO2.DLL\0" + VALUE "ProductName", "Toaster DDK Sample\0" + VALUE "ProductVersion", "2.0.0000.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +// +// Dialog resources +// +IDD_SAMPLE_INSTALLAPP DIALOG DISCARDABLE 0, 0, 317, 143 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Please select the applications that you would like to install:", + IDC_STATIC,11,0,304,8 + CONTROL "Toaster Device Interface Watcher",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,21,20,296,10 + CONTROL "Toaster Diagnostic Utility",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,21,34,296,10 + CONTROL "Toast-Made-Easy Recipe Program",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | + WS_DISABLED | WS_TABSTOP,21,48,296,10 +END + +// +// String Table resources +// +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE "Choose Additional Applications" + IDS_SUBTITLE "These applications make it quick and easy to make great toast!" + IDS_MEDIA_PROMPT_TITLE "Toaster" +END + diff --git a/general/toaster/toastpkg/toastco/tostrco2.def b/general/toaster/toastpkg/toastco/tostrco2.def new file mode 100644 index 00000000..5ee4e35b --- /dev/null +++ b/general/toaster/toastpkg/toastco/tostrco2.def @@ -0,0 +1,24 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +; KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +; PURPOSE. +; +;Module Name: +; +; tostrco2.def +; +;Abstract: +; +; Specifies exports for the Toaster Package sample co-installer (version 2) +; +;--*/ + +LIBRARY tostrco2 + +EXPORTS + ToasterCoInstaller + GetValueAddSoftwareWizPage diff --git a/general/toaster/toastpkg/toastco/tostrco2.vcxproj b/general/toaster/toastpkg/toastco/tostrco2.vcxproj new file mode 100644 index 00000000..ee1a266f --- /dev/null +++ b/general/toaster/toastpkg/toastco/tostrco2.vcxproj @@ -0,0 +1,243 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{F4010EA2-CDEF-4E68-AF56-C0240162D712}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</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|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>tostrco2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>tostrco2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>tostrco2</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>tostrco2</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;kernel32.lib;comctl32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;kernel32.lib;comctl32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;kernel32.lib;comctl32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;kernel32.lib;comctl32.lib;advapi32.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <ModuleDefinitionFile>tostrco2.def</ModuleDefinitionFile> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <ModuleDefinitionFile>tostrco2.def</ModuleDefinitionFile> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <ModuleDefinitionFile>tostrco2.def</ModuleDefinitionFile> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <ModuleDefinitionFile>tostrco2.def</ModuleDefinitionFile> + </Link> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="toastco.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="toastco.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters b/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters new file mode 100644 index 00000000..5639c710 --- /dev/null +++ b/general/toaster/toastpkg/toastco/tostrco2.vcxproj.Filters @@ -0,0 +1,33 @@ +<?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>{FF79EB36-D2F2-497B-9B3B-1F5D4BA911D4}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{A4BFE1CB-F5FD-4F98-8EA6-6B0F543535C6}</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>{F4E6AFB3-5EF2-4D35-92BF-D0DAD16E87B5}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="toastco.c"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="tostrco2.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="toastco.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastpkg.sln b/general/toaster/toastpkg/toastpkg.sln new file mode 100644 index 00000000..13fee6ef --- /dev/null +++ b/general/toaster/toastpkg/toastpkg.sln @@ -0,0 +1,62 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastapp", "Toastapp", "{BFAE4A6A-CD41-4052-AC38-EAC4DB8494DF}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastco", "Toastco", "{4C142C9D-56A8-44C0-84F1-D4ABBFA3E9F8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toastva", "Toastva", "{47FE1DB3-FA82-4F24-96B1-C6798AA08C61}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastapp", "toastapp\toastapp.vcxproj", "{1C818755-28B2-4C84-8623-FF84F3326B64}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tostrco2", "toastco\tostrco2.vcxproj", "{84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toastva", "toastva\toastva.vcxproj", "{7A49D840-4E82-477B-8105-CF546E4FD034}" + ProjectSection(ProjectDependencies) = postProject + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} = {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|Win32.ActiveCfg = Debug|Win32 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|Win32.Build.0 = Debug|Win32 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|Win32.ActiveCfg = Release|Win32 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|Win32.Build.0 = Release|Win32 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|x64.ActiveCfg = Debug|x64 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Debug|x64.Build.0 = Debug|x64 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|x64.ActiveCfg = Release|x64 + {1C818755-28B2-4C84-8623-FF84F3326B64}.Release|x64.Build.0 = Release|x64 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|Win32.ActiveCfg = Debug|Win32 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|Win32.Build.0 = Debug|Win32 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|Win32.ActiveCfg = Release|Win32 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|Win32.Build.0 = Release|Win32 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|x64.ActiveCfg = Debug|x64 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Debug|x64.Build.0 = Debug|x64 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|x64.ActiveCfg = Release|x64 + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22}.Release|x64.Build.0 = Release|x64 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|Win32.ActiveCfg = Debug|Win32 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|Win32.Build.0 = Debug|Win32 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|Win32.ActiveCfg = Release|Win32 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|Win32.Build.0 = Release|Win32 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|x64.ActiveCfg = Debug|x64 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Debug|x64.Build.0 = Debug|x64 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|x64.ActiveCfg = Release|x64 + {7A49D840-4E82-477B-8105-CF546E4FD034}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {1C818755-28B2-4C84-8623-FF84F3326B64} = {BFAE4A6A-CD41-4052-AC38-EAC4DB8494DF} + {84F11D30-54EE-479A-8F8A-7FBFA8E6BE22} = {4C142C9D-56A8-44C0-84F1-D4ABBFA3E9F8} + {7A49D840-4E82-477B-8105-CF546E4FD034} = {47FE1DB3-FA82-4F24-96B1-C6798AA08C61} + EndGlobalSection +EndGlobal diff --git a/general/toaster/toastpkg/toastva/header.bmp b/general/toaster/toastpkg/toastva/header.bmp Binary files differnew file mode 100644 index 00000000..49a4cb45 --- /dev/null +++ b/general/toaster/toastpkg/toastva/header.bmp diff --git a/general/toaster/toastpkg/toastva/precomp.h b/general/toaster/toastpkg/toastva/precomp.h new file mode 100644 index 00000000..de91c9b6 --- /dev/null +++ b/general/toaster/toastpkg/toastva/precomp.h @@ -0,0 +1,21 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + precomp.h + +Abstract: + + Single container to facilitate use of precompiled headers. + +--*/ + +#include "toastva.h" +#include "strsafe.h" diff --git a/general/toaster/toastpkg/toastva/precompsrc.c b/general/toaster/toastpkg/toastva/precompsrc.c new file mode 100644 index 00000000..5944cf51 --- /dev/null +++ b/general/toaster/toastpkg/toastva/precompsrc.c @@ -0,0 +1 @@ +#include "precomp.h"
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastva/resource.h b/general/toaster/toastpkg/toastva/resource.h new file mode 100644 index 00000000..f5ab4bb0 --- /dev/null +++ b/general/toaster/toastpkg/toastva/resource.h @@ -0,0 +1,61 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + resource.h + +Abstract: + + Resource IDs used by the TOASTVA sample. + +--*/ + +#define IDS_TITLE1 1 +#define IDS_SUBTITLE1 2 +#define IDS_TITLE2 3 +#define IDS_SUBTITLE2 4 +#define IDS_CAPTION 5 +#define IDS_PROMPT_FOR_HW 6 +#define IDB_BANNER 102 +#define IDB_WATERMARK 103 +#define IDI_ICON1 104 +#define IDD_INTRO 107 +#define IDD_INTERIOR1 108 +#define IDD_INTERIOR2 109 +#define IDD_END 110 +#define IDC_TITLE 1000 +#define IDC_INTRO_TEXT 1001 +#define IDC_RADIO1 1002 +#define IDC_RADIO2 1003 +#define IDC_RADIO3 1004 +#define IDC_EDIT2 1006 +#define IDC_EDIT3 1007 +#define IDC_EDIT4 1008 +#define IDC_CHECK1 1010 +#define IDC_GROUP1 1011 +#define IDC_CHECK3 1013 +#define IDC_CHECK4 1014 +#define IDC_CHECK5 1015 +#define IDC_ANIMATE1 1016 +#define IDC_FINISH_TEXT 1017 +#define IDC_STATIC -1 +#define IDA_SEARCHING 300 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1018 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif + diff --git a/general/toaster/toastpkg/toastva/search.avi b/general/toaster/toastpkg/toastva/search.avi Binary files differnew file mode 100644 index 00000000..24850baa --- /dev/null +++ b/general/toaster/toastpkg/toastva/search.avi diff --git a/general/toaster/toastpkg/toastva/toastapp.ico b/general/toaster/toastpkg/toastva/toastapp.ico Binary files differnew file mode 100644 index 00000000..55ab969e --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastapp.ico diff --git a/general/toaster/toastpkg/toastva/toastva.c b/general/toaster/toastpkg/toastva/toastva.c new file mode 100644 index 00000000..be842667 --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastva.c @@ -0,0 +1,209 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastva.c + +Abstract: + + The TOASTVA application illustrates installation techniques that can be + used to seamlessly integrate PnP device installation with installation of + value-added software, regardless of whether the software installation + preceeded the hardware installation, or vice versa. + +--*/ + +#include "precomp.h" +#pragma hdrstop + + +// +// Constants +// +#if defined(_IA64_) + #define TOASTVA_PLATFORM_SUBDIRECTORY L"ia64" +#elif defined(_X86_) + #define TOASTVA_PLATFORM_SUBDIRECTORY L"i386" +#elif defined(_AMD64_) + #define TOASTVA_PLATFORM_SUBDIRECTORY L"amd64" +#elif defined(_ARM_) + #define TOASTVA_PLATFORM_SUBDIRECTORY L"arm" +#elif defined(_ARM64_) + #define TOASTVA_PLATFORM_SUBDIRECTORY L"arm64" +#else +#error Unsupported platform +#endif + +#define TOASTVA_PLATFORM_SUBDIRECTORY_SIZE (sizeof(TOASTVA_PLATFORM_SUBDIRECTORY) / sizeof(WCHAR)) + +// +// Globals +// +HINSTANCE g_hInstance; + + +// +// Implementation +// + +INT +WINAPI +WinMain( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPSTR lpCmdLine, + _In_ int nShowCmd + ) +{ + LPWSTR *ArgList; + INT NumArgs; + WCHAR MediaRootDirectory[MAX_PATH]; + LPWSTR FileNamePart; + DWORD DirPathLength; + + g_hInstance = hInstance; + + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + UNREFERENCED_PARAMETER(nShowCmd); + + // + // Windows 2000 doesn't suppress auto-run applications when media (e.g., + // a CD) is inserted while a "Found New Hardware" popup is onscreen. This + // means that, by default, inserting a CD in order to supply PnP with the + // necessary INF and driver files will result in the autorun app launching, + // and obscuring the wizard, causing user confusion, etc. + // + // To avoid this, we retrieve an entrypoint to a Windows 2000 (and later) + // Configuration Manager (CM) API that allows us to detect when a device + // installation is in-progress, and suppress our own application from + // starting. + // + if(IsDeviceInstallInProgress()) { + // + // We don't want to startup right now. Don't worry--the value-added + // software part of the device installation will be invoked (if + // necessary) by our device co-installer during finish-install + // processing. + // + return 0; + } + + // + // Retrieve the full directory path from which our setup program was + // invoked. + // + ArgList = CommandLineToArgvW(GetCommandLine(), &NumArgs); + + if(ArgList && (NumArgs >= 1)) { + + DirPathLength = GetFullPathName(ArgList[0], + MAX_PATH, + MediaRootDirectory, + &FileNamePart + ); + + if(DirPathLength >= MAX_PATH) { + // + // The directory is too large for our buffer. Set our directory + // path length to zero so we'll simply bail out in this rare case. + // + DirPathLength = 0; + } + + if(DirPathLength) { + // + // Strip the filename off the path. + // + *FileNamePart = L'\0'; + + DirPathLength = (DWORD)(FileNamePart - MediaRootDirectory); + } + + } else { + // + // For some reason, we couldn't get the command line arguments that + // were used when invoking our setup app. Assume current directory + // instead. + // + DirPathLength = GetCurrentDirectory(MAX_PATH, MediaRootDirectory); + + if(DirPathLength >= MAX_PATH) { + // + // The current directory is too large for our buffer. Set our + // directory path length to zero so we'll simply bail out in this + // rare case. + // + DirPathLength = 0; + } + + if(DirPathLength) { + // + // Ensure that path ends in a path separator character. + // + if((MediaRootDirectory[DirPathLength-1] != L'\\') && + (MediaRootDirectory[DirPathLength-1] != L'/')) + { + MediaRootDirectory[DirPathLength++] = L'\\'; + + if(DirPathLength < MAX_PATH) { + MediaRootDirectory[DirPathLength] = L'\0'; + } else { + // + // Not enough room in buffer to add path separator char + // + DirPathLength = 0; + } + } + } + } + + if(ArgList) { + GlobalFree(ArgList); + } + + if(!DirPathLength) { + // + // Couldn't figure out what the root directory of our installation + // media was. Bail out. + // + return 0; + } + + // + // If we're being invoked from a platform-specific subdirectory (i.e., + // \i386 or \ia64), then strip off that subdirectory to get the true media + // root path. + // + if(DirPathLength > TOASTVA_PLATFORM_SUBDIRECTORY_SIZE) { + // + // We know that the last character in our MediaRootDirectory string is + // a path separator character. Check to see if the preceding + // characters match our platform-specific subdirectory. + // + if(!_wcsnicmp(&(MediaRootDirectory[DirPathLength - TOASTVA_PLATFORM_SUBDIRECTORY_SIZE]), + TOASTVA_PLATFORM_SUBDIRECTORY, + TOASTVA_PLATFORM_SUBDIRECTORY_SIZE - 1)) { + // + // Platform-specific part matches, just make sure preceding char + // is a path separator char. + // + if((MediaRootDirectory[DirPathLength - TOASTVA_PLATFORM_SUBDIRECTORY_SIZE - 1] == L'\\') || + (MediaRootDirectory[DirPathLength - TOASTVA_PLATFORM_SUBDIRECTORY_SIZE - 1] == L'/')) { + + MediaRootDirectory[DirPathLength - TOASTVA_PLATFORM_SUBDIRECTORY_SIZE] = L'\0'; + } + } + } + + DoValueAddWizard(MediaRootDirectory); + + return 0; +} diff --git a/general/toaster/toastpkg/toastva/toastva.h b/general/toaster/toastpkg/toastva/toastva.h new file mode 100644 index 00000000..10ccb508 --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastva.h @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastva.h + +Abstract: + + Header files and resource IDs used by the TOASTVA sample. + +--*/ + +#include <windows.h> +#include <windowsx.h> +#include <string.h> +#include <shellapi.h> +#include <prsht.h> +#include <windef.h> +#include <regstr.h> +#include <cfgmgr32.h> +#include <setupapi.h> +#include <newdev.h> +#include "resource.h" + +// +// String constants +// +#define ENUMERATOR_NAME L"{b85b7c50-6a01-11d2-b841-00c04fad5171}" +#define HW_ID_TO_UPDATE L"{b85b7c50-6a01-11d2-b841-00c04fad5171}\\MsToaster" +#define DEVICE_INF_NAME L"toastpkg.inf" +#define TOASTAPP_SETUP_PATH L"ToastApp\\setup.exe" + +// +// global variables +// +extern HINSTANCE g_hInstance; + +// +// utility routines +// +BOOL +IsDeviceInstallInProgress(VOID); + +VOID +MarkDevicesAsNeedReinstall( + _In_ HDEVINFO DeviceInfoSet + ); + +DWORD +GetDeviceConfigFlags( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData + ); + +VOID +SetDeviceConfigFlags( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD ConfigFlags + ); + +HDEVINFO +GetNonPresentDevices( + _In_ LPCWSTR Enumerator OPTIONAL, + _In_ LPCWSTR HardwareID + ); + +VOID +DoValueAddWizard( + _In_ LPCWSTR MediaRootDirectory + ); + diff --git a/general/toaster/toastpkg/toastva/toastva.rc b/general/toaster/toastpkg/toastva/toastva.rc new file mode 100644 index 00000000..4868ed3b --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastva.rc @@ -0,0 +1,221 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + toastva.rc + +Abstract: + + Resources used by the TOASTVA sample. + +--*/ + +#include <windows.h> +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Microsoft Corporation\0" + VALUE "FileDescription", "Toaster Value-Add Installer Sample\0" + VALUE "FileVersion", "1.00.0000.0\0" + VALUE "InternalName", "TOASTVA.EXE\0" + VALUE "LegalCopyright", "� Microsoft Corporation. All rights reserved.\0" + VALUE "OriginalFilename", "TOASTVA.EXE\0" + VALUE "ProductName", "Toaster DDK Sample\0" + VALUE "ProductVersion", "1.0.0000.0\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_INTRO DIALOG DISCARDABLE 0, 0, 317, 193 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Toaster" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Welcome to Toasting Made Simple!",IDC_TITLE,115,9,189, + 31,NOT WS_GROUP + LTEXT "This wizard will help you install supporting software for your toaster, and allow you to choose additional applications that will help you get the most from your new toaster.", + IDC_INTRO_TEXT,115,40,189,53 +END + +IDD_INTERIOR1 DIALOG DISCARDABLE 0, 0, 317, 143 +STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "Animate1",IDC_ANIMATE1,"SysAnimate32", + ACS_TRANSPARENT,148,50,20,20,WS_EX_TRANSPARENT +END + +IDD_END DIALOG DISCARDABLE 0, 0, 317, 193 +STYLE WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "Toaster" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Congratulations! You've successfully installed your new toaster's software.", + IDC_TITLE,115,8,195,37 + LTEXT "Enjoy the toast!",IDC_FINISH_TEXT,115,58,195,128 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_INTRO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + VERTGUIDE, 115 + VERTGUIDE, 304 + TOPMARGIN, 7 + BOTTOMMARGIN, 186 + HORZGUIDE, 8 + HORZGUIDE, 40 + END + + IDD_INTERIOR1, DIALOG + BEGIN + LEFTMARGIN, 28 + RIGHTMARGIN, 310 + VERTGUIDE, 28 + BOTTOMMARGIN, 136 + END + + IDD_END, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 310 + VERTGUIDE, 115 + TOPMARGIN, 7 + BOTTOMMARGIN, 186 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDB_BANNER BITMAP DISCARDABLE "header.bmp" +IDB_WATERMARK BITMAP DISCARDABLE "watermrk.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// AVIs +// + +IDA_SEARCHING AVI "SEARCH.AVI" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "toastapp.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE1 "Installing Toaster Support Software" + IDS_SUBTITLE1 "Please wait while we install the software that makes your toaster work." + IDS_TITLE2 "Choose Additional Applications" + IDS_SUBTITLE2 "These applications make it quick and easy to make great toast!" + IDS_PROMPT_FOR_HW "You may now plug in your toaster. It will automatically be discovered and configured for you. Enjoy the toast!" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/general/toaster/toastpkg/toastva/toastva.vcxproj b/general/toaster/toastpkg/toastva/toastva.vcxproj new file mode 100644 index 00000000..1a25ac8c --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastva.vcxproj @@ -0,0 +1,221 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{7A49D840-4E82-477B-8105-CF546E4FD034}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{2DF87D9A-363B-4C6B-9E31-BE2BF60898DF}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>toastva</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>toastva</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>toastva</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>toastva</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;shell32.lib;comctl32.lib;newdev.lib;.\..\toastco\$(IntDir)\tostrco2.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;shell32.lib;comctl32.lib;newdev.lib;.\..\toastco\$(IntDir)\tostrco2.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;shell32.lib;comctl32.lib;newdev.lib;.\..\toastco\$(IntDir)\tostrco2.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + </ResourceCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib;user32.lib;shell32.lib;comctl32.lib;newdev.lib;.\..\toastco\$(IntDir)\tostrco2.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="toastva.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="util.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ClCompile Include="wizard.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Use</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + <ResourceCompile Include="toastva.rc" /> + </ItemGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <PreCompiledHeaderFile>precomp.h</PreCompiledHeaderFile> + <PreCompiledHeader>Create</PreCompiledHeader> + <PreCompiledHeaderOutputFile>$(IntDir)\precomp.pch</PreCompiledHeaderOutputFile> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/toastpkg/toastva/toastva.vcxproj.Filters b/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters new file mode 100644 index 00000000..8ae9e8e3 --- /dev/null +++ b/general/toaster/toastpkg/toastva/toastva.vcxproj.Filters @@ -0,0 +1,36 @@ +<?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>{C874EFAD-3886-466E-97CC-4A852797DC29}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{4A7A3632-2660-49C4-9B04-6BD51BEA6316}</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>{CDCE6E71-5F53-4E60-99F1-ABD1D5819475}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="precompsrc.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="toastva.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="util.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="wizard.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="toastva.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/toastpkg/toastva/util.c b/general/toaster/toastpkg/toastva/util.c new file mode 100644 index 00000000..e2f68c5b --- /dev/null +++ b/general/toaster/toastpkg/toastva/util.c @@ -0,0 +1,517 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + util.c + +Abstract: + + Utility routines used by the TOASTVA sample. + +--*/ + +#include "precomp.h" +#pragma hdrstop + +/*++ + + Here's the description for the CMP_WaitNoPendingInstallEvents API used to + suppress execution of this app (e.g., via autorun upon CD insertion) while + device installation is underway... + + DWORD + CMP_WaitNoPendingInstallEvents( + _In_ DWORD dwTimeout + ); + + Routine Description: + + This routine waits until there are no pending device install events. + If a timeout value is specified then it will return either when no + install events are pending or when the timeout period has expired, + whichever comes first. This routine is intended to be called after + user-logon, only. + + NOTE: New install events can occur at anytime, this routine just + indicates that there are no install events at this moment. + + Parameters: + + dwTimeout - Specifies the time-out interval, in milliseconds. The + function returns if the interval elapses, even if there are still + pending install events. If dwTimeout is zero, the function just + tests whether there are pending install events and returns + immediately. If dwTimeout is INFINITE, the function's time-out + interval never elapses. + + Return Value: + + If the function succeeds, the return value indicates the event that + caused the function to return. If the function fails, the return value + is WAIT_FAILED. To get extended error information, call GetLastError. + The return value on success is one of the following values: + + WAIT_ABANDONED The specified object is a mutex object that was not + released by the thread that owned the mutex object + before the owning thread terminated. Ownership of the + mutex object is granted to the calling thread, and the + mutex is set to nonsignaled. + WAIT_OBJECT_0 The state of the specified object is signaled. + WAIT_TIMEOUT The time-out interval elapsed, and the object's state is + nonsignaled. + +--*/ + +typedef DWORD (WINAPI *CMP_WAITNOPENDINGINSTALLEVENTS_PROC)( + _In_ DWORD dwTimeout + ); + + +BOOL +IsDeviceInstallInProgress(VOID) + +/*++ + +Routine Description: + + This routine dynamically retrieves the entrypoint to a Windows 2000 (and + later) Configuration Manager (CM) API that can be used to detect whether + there are presently any device installations in-progress. If this API is + not available (it may be obsoleted on future releases of the OS), then the + API assumes there are no device installations in progress. This is OK, + because future versions of the OS will suppress auto-run when "Found New + Hardware" wizard is up, thus eliminating the need for apps to do their own + checking. + +Arguments: + + none + +Return Value: + + If there is presently a device installation in progress, the return value + is TRUE. + + If there is not presently a device installation in progress, or we were + unsuccessful in retrieving the necessary Configuration Manager API, then + the return value is FALSE. + +--*/ + +{ + HMODULE hModule; + CMP_WAITNOPENDINGINSTALLEVENTS_PROC pCMP_WaitNoPendingInstallEvents; + + hModule = GetModuleHandle(L"setupapi.dll"); + + if(!hModule) { + // + // Should never happen since we're linked to setupapi, but... + // + return FALSE; + } + + pCMP_WaitNoPendingInstallEvents = + (CMP_WAITNOPENDINGINSTALLEVENTS_PROC)GetProcAddress( + hModule, + "CMP_WaitNoPendingInstallEvents" + ); + if(!pCMP_WaitNoPendingInstallEvents) { + // + // We're running on a release of the OS that doesn't supply this API. + // Trust the OS to suppress autorun when appropriate. + // + return FALSE; + } + + return (pCMP_WaitNoPendingInstallEvents(0) == WAIT_TIMEOUT); +} + + +VOID +MarkDevicesAsNeedReinstall( + _In_ HDEVINFO DeviceInfoSet + ) + +/*++ + +Routine Description: + + This routine enumerates every device information element in the specified + list and sets the CONFIGFLAG_REINSTALL registry flag for each one. + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set whose + members are to be marked as need-reinstall. + +Return Value: + + none + +--*/ + +{ + SP_DEVINFO_DATA DeviceInfoData; + DWORD i, ConfigFlags; + + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + for(i = 0; + SetupDiEnumDeviceInfo(DeviceInfoSet, i, &DeviceInfoData); + i++) + { + ConfigFlags = GetDeviceConfigFlags(DeviceInfoSet, &DeviceInfoData); + ConfigFlags |= CONFIGFLAG_REINSTALL; + SetDeviceConfigFlags(DeviceInfoSet, &DeviceInfoData, ConfigFlags); + } +} + + +DWORD +GetDeviceConfigFlags( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData + ) + +/*++ + +Routine Description: + + This routine retrieves the ConfigFlags registry property for the specified + device info element, or zero if the property cannot be retrieved (e.g., + because ConfigFlags haven't yet been set by Found New Hardware process). + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set containing + the device of interest. + + DeviceInfoData - Supplies context of a device info element for which + ConfigFlags is to be retrieved. + +Return Value: + + If device's REG_DWORD ConfigFlags property can be retrieved, it is returned. + Otherwise, zero is returned. + +--*/ + +{ + DWORD ConfigFlags, RegDataType; + + if(!SetupDiGetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + SPDRP_CONFIGFLAGS, + &RegDataType, + (PBYTE)&ConfigFlags, + sizeof(ConfigFlags), + NULL) + || (RegDataType != REG_DWORD)) + { + // + // It's possible that this property isn't there, although we should + // never enounter other problems like wrong datatype or data length + // longer than sizeof(DWORD). In any event, just return zero. + // + ConfigFlags = 0; + } + + return ConfigFlags; +} + + +VOID +SetDeviceConfigFlags( + _In_ HDEVINFO DeviceInfoSet, + _In_ PSP_DEVINFO_DATA DeviceInfoData, + _In_ DWORD ConfigFlags + ) + +/*++ + +Routine Description: + + This routine sets a device's ConfigFlags property to the specified value. + +Arguments: + + DeviceInfoSet - Supplies a handle to the device information set containing + the device of interest. + + DeviceInfoData - Supplies context of a device info element for which + ConfigFlags is to be set. + + ConfigFlags - Specifies the value to be stored to the device's ConfigFlags + property. + +Return Value: + + none + +--*/ + +{ + SetupDiSetDeviceRegistryProperty(DeviceInfoSet, + DeviceInfoData, + SPDRP_CONFIGFLAGS, + (PBYTE)&ConfigFlags, + sizeof(ConfigFlags) + ); +} + + +HDEVINFO +GetNonPresentDevices( + _In_ LPCWSTR Enumerator OPTIONAL, + _In_ LPCWSTR HardwareID + ) + +/*++ + +Routine Description: + + This routine retrieves any non-present devices matching the specified + criteria, and returns them in a device information set. + +Arguments: + + Enumerator - Optionally, supplies the name of the Enumerator under which + this device may be found. If the device may show up under more than + one enumerator, the routine can be called with Enumerator specified as + NULL, in which case all device instances in the registry are examined. + + HardwareID - Supplies the hardware ID to be searched for. This will be + compared against each of the hardware IDs for all device instances in + the system (potentially filtered based on Enumerator), present or not. + +Return Value: + + If any non-present devices are discovered, this routine returns a device + information set containing those devices. This set must be freed via + SetupDiDestroyDeviceInfoList by the caller. + + If no such devices are encountered (or if an error occurs), the return + value is INVALID_HANDLE_VALUE. GetLastError will indicate the cause of + failure. + +--*/ + +{ + HDEVINFO AllDevs, ExistingNonPresentDevices; + DWORD i, Err; + SP_DEVINFO_DATA DeviceInfoData; + LPWSTR HwIdBuffer, CurId; + DWORD HwIdBufferLen, RegDataType, RequiredSize; + BOOL bRet; + ULONG Status, Problem; + TCHAR DeviceInstanceId[MAX_DEVNODE_ID_LEN]; + + ExistingNonPresentDevices = INVALID_HANDLE_VALUE; + + AllDevs = SetupDiGetClassDevs(NULL, + Enumerator, + NULL, + DIGCF_ALLCLASSES + ); + + if(AllDevs == INVALID_HANDLE_VALUE) { + // + // last error has already been set during the above call. + // + return INVALID_HANDLE_VALUE; + } + + // + // Iterate through each device we found, comparing its hardware ID(s) + // against the one we were passed in. + // + DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); + + HwIdBuffer = NULL; + HwIdBufferLen = 0; + Err = NO_ERROR; + bRet = FALSE; + + i = 0; + + while(SetupDiEnumDeviceInfo(AllDevs, i, &DeviceInfoData)) { + // + // Retrieve the HardwareID property for this device info element + // + if(!SetupDiGetDeviceRegistryProperty(AllDevs, + &DeviceInfoData, + SPDRP_HARDWAREID, + &RegDataType, + (PBYTE)HwIdBuffer, + HwIdBufferLen, + &RequiredSize)) { + // + // If the failure was due to buffer-too-small, we can resize and + // try again. + // + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { + + if(HwIdBuffer) { + GlobalFree(HwIdBuffer); + } + + HwIdBuffer = GlobalAlloc(0, RequiredSize); + if(HwIdBuffer) { + HwIdBufferLen = RequiredSize; + // + // try again + // + continue; + } else { + // + // We failed to allocate the buffer we needed. This is + // considered a critical failure that should cause us to + // bail. + // + Err = ERROR_NOT_ENOUGH_MEMORY; + break; + } + + } else { + // + // We failed to retrieve the property for some other reason. + // Skip this device and move on to the next. + // + i++; + continue; + } + } + + if((RegDataType != REG_MULTI_SZ) || (RequiredSize < sizeof(TCHAR))) { + // + // Data is invalid--this should never happen, but we'll skip the + // device in this case... + // + i++; + continue; + } + + // + // If we get to here, then we successfully retrieved the multi-sz + // hardware id list for this device. Compare each of those IDs with + // the caller-supplied one. + // + for(CurId = HwIdBuffer; CurId && *CurId; CurId += (lstrlen(CurId) + 1)) { + + if(!lstrcmpi(CurId, HardwareID)) { + // + // We found a match! + // + bRet = TRUE; + + // + // If the device isn't currently present (as indicated by + // failure to retrieve its status), then add it to the list of + // such devices to be returned to the caller. + // + if(CR_SUCCESS != CM_Get_DevNode_Status(&Status, + &Problem, + (DEVNODE)DeviceInfoData.DevInst, + 0)) + { + if(ExistingNonPresentDevices == INVALID_HANDLE_VALUE) { + // + // This is the first non-present device we've + // encountered--we need to create the HDEVINFO set. + // + ExistingNonPresentDevices = + SetupDiCreateDeviceInfoList(NULL, NULL); + + if(ExistingNonPresentDevices == INVALID_HANDLE_VALUE) { + // + // Failure to create this set is a critical error! + // + Err = GetLastError(); + bRet = FALSE; + break; + } + } + + // + // We need to get the device instance's name so we can + // open it up into our "non-present devices" list + // + if(!SetupDiGetDeviceInstanceId(AllDevs, + &DeviceInfoData, + DeviceInstanceId, + sizeof(DeviceInstanceId) / sizeof(TCHAR), + NULL)) { + // + // Should never fail, but considered critical if it + // does... + // + Err = GetLastError(); + bRet = FALSE; + break; + } + + // + // Now open up the non-present device into our list. + // + if(!SetupDiOpenDeviceInfo(ExistingNonPresentDevices, + DeviceInstanceId, + NULL, + 0, + NULL)) { + // + // This failure is also considered critical! + // + Err = GetLastError(); + bRet = FALSE; + } + + break; + } + } + } + + if(Err != NO_ERROR) { + // + // Critical error encountered--bail! + // + break; + } + + // + // Move onto the next device instance + // + i++; + } + + if(HwIdBuffer) { + GlobalFree(HwIdBuffer); + } + + // + // We can now destroy our temporary list of all devices under consideration + // + SetupDiDestroyDeviceInfoList(AllDevs); + + if((Err != NO_ERROR) && + (ExistingNonPresentDevices != INVALID_HANDLE_VALUE)) { + // + // We encountered a critical error, so we need to destroy the (partial) + // list of non-present devices we'd built. + // + SetupDiDestroyDeviceInfoList(ExistingNonPresentDevices); + ExistingNonPresentDevices = INVALID_HANDLE_VALUE; + } + + SetLastError(Err); + + return ExistingNonPresentDevices; +} + diff --git a/general/toaster/toastpkg/toastva/watermrk.bmp b/general/toaster/toastpkg/toastva/watermrk.bmp Binary files differnew file mode 100644 index 00000000..5749637d --- /dev/null +++ b/general/toaster/toastpkg/toastva/watermrk.bmp diff --git a/general/toaster/toastpkg/toastva/wizard.c b/general/toaster/toastpkg/toastva/wizard.c new file mode 100644 index 00000000..5f876a3f --- /dev/null +++ b/general/toaster/toastpkg/toastva/wizard.c @@ -0,0 +1,883 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + wizard.c + +Abstract: + + This module implements the TOASTVA wizard that installs/updates toaster + drivers and allows the user to select additional value-added software. + +--*/ + +#include "precomp.h" +#pragma hdrstop + +// +// Constants +// +#define WMX_UPDATE_DRIVER_DONE (WM_USER + 500) + +// +// Structures +// +typedef struct _SHAREDWIZDATA { + HFONT hTitleFont; // Title font for the Welcome and Completion pages + BOOL HwInsertedFirst; // Is the hardware already present? + LPCWSTR MediaRootDirectory; // Fully-qualified path to root of install media + BOOL DoDriverUpdatePage; // Should Update Driver page do anything? + BOOL RebootRequired; // Did we do anything that requires a reboot? + HWND hwndDlg; // Handle to dialog notified by drv update thread +} SHAREDWIZDATA, *LPSHAREDWIZDATA; + +// +// Function prototypes +// +INT_PTR +CALLBACK +IntroDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR +CALLBACK +IntPage1DlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +INT_PTR +CALLBACK +EndDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + +DWORD +WINAPI +UpdateDriverThreadProc( + _In_ LPVOID ThreadData + ); + +INT +CALLBACK +WizardCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ); + +// +// Prototype for a routine exported from toastco.dll +// +HPROPSHEETPAGE +GetValueAddSoftwareWizPage( + _In_ LPCWSTR MediaRootDirectory, + _In_opt_ LPCWSTR MediaDiskName, + _In_opt_ LPCWSTR MediaTagFile + ); + +// +// Implementation +// + +VOID +DoValueAddWizard( + _In_ LPCWSTR MediaRootDirectory + ) + +/*++ + +Routine Description: + + This routine displays a wizard that steps the user through the following + actions: + + (a) Performs a "driver update" for any currently-present toasters + (b) Installs the INF and CAT in case no toasters presently exist + (c) Optionally, installs value-add software selected by the user (this + wizard page is retrieved from the toaster co-installer, and is the same + page the user gets if they do a "hardware-first" installation using our + driver). + +Arguments: + + MediaRootDirectory - Supplies the fully-qualified path to the root + directory where the installation media is located. + +Return Value: + + none + +--*/ + +{ + PROPSHEETPAGE psp = {0}; //defines the property sheet pages + HPROPSHEETPAGE ahpsp[4] = {0}; //an array to hold the page's HPROPSHEETPAGE handles + PROPSHEETHEADER psh = {0}; //defines the property sheet + SHAREDWIZDATA wizdata = {0}; //the shared data structure + + NONCLIENTMETRICS ncm = {0}; + LOGFONT TitleLogFont; + HDC hdc; + INT FontSize; + INT index = 0; + HRESULT hr; + + // + //Create the Wizard pages + // + // Intro page... + // + psp.dwSize = sizeof(psp); + psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; + psp.hInstance = g_hInstance; + psp.lParam = (LPARAM) &wizdata; //The shared data structure + psp.pfnDlgProc = IntroDlgProc; + psp.pszTemplate = MAKEINTRESOURCE(IDD_INTRO); + + ahpsp[index++] = CreatePropertySheetPage(&psp); + + // + // Updating drivers page... + // + psp.dwFlags = PSP_DEFAULT|PSP_USEHEADERTITLE|PSP_USEHEADERSUBTITLE|PSP_USETITLE; + psp.pszHeaderTitle = MAKEINTRESOURCE(IDS_TITLE1); + psp.pszHeaderSubTitle = MAKEINTRESOURCE(IDS_SUBTITLE1); + psp.pszTemplate = MAKEINTRESOURCE(IDD_INTERIOR1); + psp.pfnDlgProc = IntPage1DlgProc; + + ahpsp[index++] = CreatePropertySheetPage(&psp); + + // + // Retrieve the value-add software chooser page from the toaster + // co-installer (toastco.dll). + // + ahpsp[index] = GetValueAddSoftwareWizPage(MediaRootDirectory, NULL, NULL); + + if(ahpsp[index]) { + index++; + } + + // + // Finish page... + // + psp.dwFlags = PSP_DEFAULT|PSP_HIDEHEADER; + psp.pszTemplate = MAKEINTRESOURCE(IDD_END); + psp.pfnDlgProc = EndDlgProc; + + ahpsp[index] = CreatePropertySheetPage(&psp); + + // + // Create the property sheet... + // + psh.dwSize = sizeof(psh); + psh.hInstance = g_hInstance; + psh.hwndParent = NULL; + psh.phpage = ahpsp; + psh.dwFlags = PSH_WIZARD97|PSH_WATERMARK|PSH_HEADER|PSH_STRETCHWATERMARK|PSH_WIZARD|PSH_USECALLBACK; + psh.pszbmWatermark = MAKEINTRESOURCE(IDB_WATERMARK); + psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER); + psh.nStartPage = 0; + psh.nPages = 4; + psh.pfnCallback = WizardCallback; + + // + // Set up the font for the titles on the intro and ending pages + // + ncm.cbSize = sizeof(ncm); + SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); + + // + // Create the intro/end title font + // + TitleLogFont = ncm.lfMessageFont; + TitleLogFont.lfWeight = FW_BOLD; + hr = StringCchCopy(TitleLogFont.lfFaceName, LF_FACESIZE, L"Verdana Bold"); + if(SUCCEEDED(hr) == FALSE) { + return; // assert + } + + hdc = GetDC(NULL); //gets the screen DC + FontSize = 12; + TitleLogFont.lfHeight = 0 - GetDeviceCaps(hdc, LOGPIXELSY) * FontSize / 72; + wizdata.hTitleFont = CreateFontIndirect(&TitleLogFont); + ReleaseDC(NULL, hdc); + wizdata.MediaRootDirectory = MediaRootDirectory; + + // + // Display the wizard + // + PropertySheet(&psh); + + // + // Destroy the fonts + // + DeleteObject(wizdata.hTitleFont); + + // + // If we did anything that requires a reboot, prompt the user + // now. Note that we need to do this regardle + // + if(wizdata.RebootRequired) { + SetupPromptReboot(NULL, NULL, FALSE); + } +} + + +INT_PTR +CALLBACK +IntroDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + This function is the dialog procedure for the Welcome page of the wizard. + +Arguments: + + hwndDlg - Supplies a handle to the dialog box window + + uMsg - Supplies the message + + wParam - Supplies the first message parameter + + lParam - Supplies the second message parameter + +Return Value: + + This dialog procedure always returns zero. + +--*/ + +{ + LPSHAREDWIZDATA pdata; + LPNMHDR lpnm; + + UNREFERENCED_PARAMETER( wParam ); + + // + // Retrieve the shared user data from GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(uMsg) { + + case WM_INITDIALOG : + { + HWND hwndControl; + + // + // Get the shared data from PROPSHEETPAGE lParam valueand load + // it into GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) ((LPPROPSHEETPAGE) lParam) -> lParam; + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pdata); + + // + // It's an intro/end page, so get the title font from the + // shared data and use it for the title control + // + hwndControl = GetDlgItem(hwndDlg, IDC_TITLE); + SetWindowFont(hwndControl,pdata->hTitleFont, TRUE); + break; + } + + case WM_NOTIFY : + + lpnm = (LPNMHDR)lParam; + + switch(lpnm->code) { + + case PSN_SETACTIVE : + // + // Enable the Next button + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + + // + // When we're moving forward through the wizard, we want + // the driver update page to do its work. + // + pdata->DoDriverUpdatePage = TRUE; + break; + + case PSN_WIZNEXT : + //Handle a Next button click here + break; + + case PSN_RESET : + //Handle a Cancel button click, if necessary + break; + + default : + break; + } + break; + + default: + break; + } + + return 0; +} + + +INT_PTR +CALLBACK +IntPage1DlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + This function is the dialog procedure for the first interior wizard page. + This page updates the drivers for any existing (present) devices, or + installs the INF if there aren't any present devices. + +Arguments: + + hwndDlg - Supplies a handle to the dialog box window + + uMsg - Supplies the message + + wParam - Supplies the first message parameter + + lParam - Supplies the second message parameter + +Return Value: + + This dialog procedure always returns zero. + +--*/ + +{ + LPSHAREDWIZDATA pdata; + LPNMHDR lpnm; + HANDLE hThread; + HKEY hKey; + DWORD UserPrompted; + + UNREFERENCED_PARAMETER( wParam ); + + // + // Retrieve the shared user data from GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(uMsg) { + + case WM_INITDIALOG : + // + // Get the PROPSHEETPAGE lParam value and load it into GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) ((LPPROPSHEETPAGE) lParam) -> lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pdata); + break; + + case WM_NOTIFY : + + lpnm = (LPNMHDR)lParam; + + switch(lpnm->code) { + + case PSN_SETACTIVE : + // + // If we're coming here from the intro page, then disable + // the Back and Next buttons (we're going to be busy for a + // little bit updating drivers). + // + // If we're coming to this page from anywhere else, + // immediately jump to the intro page. + // + if(pdata->DoDriverUpdatePage) { + // + // Reset our flag so that we won't try this again if we + // go to later pages, then come back to this one. (We + // only do anything when the wizard page is accessed in + // the forward direction, from the Intro page.) + // + pdata->DoDriverUpdatePage = FALSE; + + // + // Set our "UserPrompted" registry flag so the + // co-installer won't popup its own value-add software + // chooser page during driver update. + // + if(ERROR_SUCCESS == RegCreateKeyEx( + HKEY_LOCAL_MACHINE, + TEXT("SOFTWARE\\Microsoft\\Toaster"), + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ | KEY_WRITE, + NULL, + &hKey, + NULL)) { + + UserPrompted = 1; + RegSetValueEx(hKey, + TEXT("User Prompted"), + 0, + REG_DWORD, + (PBYTE)&UserPrompted, + sizeof(UserPrompted) + ); + + RegCloseKey(hKey); + } + + // + // Disable Next, Back, and Cancel + // + PropSheet_SetWizButtons(GetParent(hwndDlg), 0); + EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), FALSE); + + // + // Show "searching" animation... + // + ShowWindow(GetDlgItem(hwndDlg, IDC_ANIMATE1), SW_SHOW); + Animate_Open(GetDlgItem(hwndDlg, IDC_ANIMATE1), MAKEINTRESOURCE(IDA_SEARCHING)); + Animate_Play(GetDlgItem(hwndDlg, IDC_ANIMATE1), 0, -1, -1); + + // + // Create a thread to do the work of updating the + // driver, etc. + // + pdata->hwndDlg = hwndDlg; + + hThread = CreateThread(NULL, + 0, + UpdateDriverThreadProc, + pdata, + 0, + NULL + ); + + if(hThread) { + // + // Thread launched successfully--close the handle, + // then just wait to be notified of thread's + // completion. + // + CloseHandle(hThread); + + } else { + // + // Couldn't launch the thread--just move on to the + // value-add software page. + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT); + } + + } else { + // + // We're coming "back" to this page. Skip it, and go + // to the intro page. + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK); + PropSheet_PressButton(GetParent(hwndDlg), PSBTN_BACK); + } + break; + + case PSN_WIZNEXT : + //Handle a Next button click, if necessary + break; + + case PSN_WIZBACK : + //Handle a Back button click, if necessary + break; + + case PSN_RESET : + //Handle a Cancel button click, if necessary + break; + + default : + break; + } + break; + + case WMX_UPDATE_DRIVER_DONE : + // + // Stop "searching" animation... + // + Animate_Stop(GetDlgItem(hwndDlg, IDC_ANIMATE1)); + ShowWindow(GetDlgItem(hwndDlg, IDC_ANIMATE1), SW_HIDE); + + // + // Regardless of whether we succeeded in upgrading any drivers, we'll + // go ahead and proceed to the value-add software page. + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_NEXT); + EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); + + PropSheet_PressButton(GetParent(hwndDlg), PSBTN_NEXT); + + break; + + default: + break; + } + + return 0; +} + + +INT_PTR +CALLBACK +EndDlgProc( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + This function is the dialog procedure for the Finish page of the wizard. + +Arguments: + + hwndDlg - Supplies a handle to the dialog box window + + uMsg - Supplies the message + + wParam - Supplies the first message parameter + + lParam - Supplies the second message parameter + +Return Value: + + This dialog procedure always returns zero. + +--*/ + +{ + LPSHAREDWIZDATA pdata; + LPNMHDR lpnm; + + UNREFERENCED_PARAMETER( wParam ); + + // + // Retrieve the shared user data from GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + + switch(uMsg) { + + case WM_INITDIALOG : + { + HWND hwndControl; + + // + // Get the shared data from PROPSHEETPAGE lParam value and load + // it into GWL_USERDATA + // + pdata = (LPSHAREDWIZDATA) ((LPPROPSHEETPAGE) lParam) -> lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) pdata); + + // + // It's an intro/end page, so get the title font from userdata + // and use it on the title control + // + hwndControl = GetDlgItem(hwndDlg, IDC_TITLE); + SetWindowFont(hwndControl,pdata->hTitleFont, TRUE); + break; + } + + case WM_NOTIFY : + + lpnm = (LPNMHDR)lParam; + + switch(lpnm->code) { + + case PSN_SETACTIVE : + // + // Enable the correct buttons for the active page + // + PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_FINISH); + + // + // Doesn't make sense to have Cancel button enabled here + // + EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), FALSE); + + // + // If we didn't find any currently-present devices, then prompt + // the user to insert their device now. + // + if(!pdata->HwInsertedFirst) { + + WCHAR TempString[LINE_LEN]; + + if(LoadString(g_hInstance, + IDS_PROMPT_FOR_HW, + TempString, + sizeof(TempString) / sizeof(WCHAR))) { + + SetDlgItemText(hwndDlg, IDC_FINISH_TEXT, TempString); + } + } + + break; + + case PSN_WIZBACK : + // + // Jumping back from this page, so turn Cancel button back on. + // + EnableWindow(GetDlgItem(GetParent(hwndDlg), IDCANCEL), TRUE); + break; + + default : + break; + } + break; + + default: + break; + } + + return 0; +} + + +DWORD +WINAPI +UpdateDriverThreadProc( + _In_ LPVOID ThreadData + ) + +/*++ + +Routine Description: + + This function updates the drivers for any existing toasters. If there are + no toasters currently connected to the computer, it installs the INF/CAT so + that the system will be ready to automatically install toasters that are + plugged in later. This routine will also mark any non-present (aka, + "phantom") toasters as needs-reinstall, so that they'll be updated to the + new driver if they're ever plugged in again. + +Arguments: + + ThreadData - Supplies a pointer to a SHAREDWIZDATA structure that's used + both by this thread, and by the wizard in the main thread. + +Return Value: + + If successful, the function returns NO_ERROR. + + Otherwise, the function returns a Win32 error code indicating the cause of + failure. + +--*/ + +{ + DWORD Err; + LPSHAREDWIZDATA pdata; + WCHAR FullInfPath[MAX_PATH]; + HDEVINFO ExistingNonPresentDevices; + + + pdata = (LPSHAREDWIZDATA)ThreadData; + Err = NO_ERROR; + + // + // First, attempt to update any present devices to our driver... + // + if (FAILED(StringCchCopy(FullInfPath, MAX_PATH, pdata->MediaRootDirectory))) { + return ERROR_NOT_ENOUGH_MEMORY; + } + + if (FAILED(StringCchCat(FullInfPath, MAX_PATH, DEVICE_INF_NAME))) { + return ERROR_NOT_ENOUGH_MEMORY; + } + + if(UpdateDriverForPlugAndPlayDevices(GetParent(pdata->hwndDlg), + HW_ID_TO_UPDATE, + FullInfPath, + 0, + &pdata->RebootRequired)) { + // + // We know that at least one device existed, and was upgraded. + // + pdata->HwInsertedFirst = TRUE; + + } else { + + Err = GetLastError(); + + // + // We failed to update the driver. If we failed simply because + // there were no toasters currently attached to the computer, then + // we still want to install the INF. + // + if(Err == ERROR_NO_SUCH_DEVINST) { + + pdata->HwInsertedFirst = FALSE; + + // + // Since we didn't do any device installs, the INF (and CAT) + // didn't get automatically installed. We'll install them now, + // so that they'll be present when the user subsequently plugs + // their hardware in. + // + if(!SetupCopyOEMInf(FullInfPath, + NULL, + SPOST_PATH, + 0, + NULL, + 0, + NULL, + NULL)) { + // + // Failure to install the INF is more important (worse) than + // the absence of any devices! + // + Err = GetLastError(); + } + + } else { + // + // Apparently there _were_ existing devices--we just failed to + // upgrade their drivers. This might be due to an installation + // problem, or perhaps because the devices already have drivers + // newer than the one we offered. + // + pdata->HwInsertedFirst = TRUE; + } + } + + if((Err == NO_ERROR) || (Err == ERROR_NO_SUCH_DEVINST)) { + // + // Either we successfully upgraded one or more toasters, or there were + // no present toasters but we successfully installed our INF and CAT. + // + // There may exist, however, devices that were once connected to the + // computer, but presently are not. If such devices are connected + // again in the future, we want to ensure they go through device + // installation. We will retrieve the list of non-present devices, and + // mark each as "needs re-install" to kick them back through the "New + // Hardware Found" process if they ever show up again. (Note that this + // doesn't destroy any device-specific settings they may have, so this + // is just forcing an upgrade, not an uninstall/re-install.) + // + // (The HardwareID used is the one defined for the toaster sample, + // BUS_HARDWARE_IDS in src\general\toaster\bus\common.h. We also take + // advantage of the fact that we know these devices will always be + // enumerated under the "{b85b7c50-6a01-11d2-b841-00c04fad5171}" + // enum namespace.) + // + ExistingNonPresentDevices = GetNonPresentDevices(ENUMERATOR_NAME, + HW_ID_TO_UPDATE + ); + + if(ExistingNonPresentDevices != INVALID_HANDLE_VALUE) { + + MarkDevicesAsNeedReinstall(ExistingNonPresentDevices); + + SetupDiDestroyDeviceInfoList(ExistingNonPresentDevices); + } + } + + PostMessage(pdata->hwndDlg, WMX_UPDATE_DRIVER_DONE, 0, 0); + + return Err; +} + + +INT +CALLBACK +WizardCallback( + _In_ HWND hwndDlg, + _In_ UINT uMsg, + _In_ LPARAM lParam + ) + +/*++ + +Routine Description: + + Call back used to remove the "X" and "?" from the wizard page. + +Arguments: + + hwndDlg - Handle to the property sheet dialog box. + + uMsg - Identifies the message being received. This parameter is one of the + following values: + + PSCB_INITIALIZED - Indicates that the property sheet is being + initialized. The lParam value is zero for this + message. + + PSCB_PRECREATE - Indicates that the property sheet is about to be + created. The hwndDlg parameter is NULL and the + lParam parameter is a pointer to a dialog template + in memory. This template is in the form of a + DLGTEMPLATE structure followed by one or more + DLGITEMTEMPLATE structures. + + lParam - Specifies additional information about the message. The + meaning of this value depends on the uMsg parameter. + +Return Value: + + The function returns zero. + +--*/ + +{ + DLGTEMPLATE *pDlgTemplate; + + UNREFERENCED_PARAMETER( hwndDlg ); + + switch(uMsg) { + + case PSCB_PRECREATE: + if(lParam){ + // + // This is done to hide the X and ? at the top of the wizard + // + pDlgTemplate = (DLGTEMPLATE *)lParam; + pDlgTemplate->style &= ~(DS_CONTEXTHELP | WS_SYSMENU); + } + break; + + default: + break; + } + + return 0; +} + diff --git a/general/toaster/umdf2/Package/package.VcxProj b/general/toaster/umdf2/Package/package.VcxProj new file mode 100644 index 00000000..d03cefec --- /dev/null +++ b/general/toaster/umdf2/Package/package.VcxProj @@ -0,0 +1,91 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="PropertySheets"> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Utility</ConfigurationType> + <DriverType>Package</DriverType> + <DisableFastUpToDateCheck>true</DisableFastUpToDateCheck> + <Configuration>Debug</Configuration> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Globals"> + <ProjectGuid>{52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}</ProjectGuid> + <SampleGuid>{7F090110-1487-4DA8-8CEA-3C1A43F8C119}</SampleGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>true</UseDebugLibraries> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>false</UseDebugLibraries> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup /> + <PropertyGroup> + <DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor> + <ImportToStore>False</ImportToStore> + <InstallMode>None</InstallMode> + <HardwareIdString /> + <CommandLine /> + <ScriptPath /> + <DeployFiles /> + <ScriptName /> + <ScriptDeviceQuery>%PathToInf%</ScriptDeviceQuery> + <EnableVerifier>False</EnableVerifier> + <AllDrivers>False</AllDrivers> + <VerifyProjectOutput>True</VerifyProjectOutput> + <VerifyDrivers /> + <VerifyFlags>133563</VerifyFlags> + </PropertyGroup> + <ItemDefinitionGroup> + </ItemDefinitionGroup> + <ItemGroup> + <!--Inf Include="DriverInf.inv" /--> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\filter\generic\filterum.vcxproj"> + <Project>{A60F76D2-C512-4DA6-8C80-263F1B506267}</Project> + </ProjectReference> + <ProjectReference Include="..\func\simple\wdfsimpleum.vcxproj"> + <Project>{4867F54B-D8EF-45B0-984E-D571D987174A}</Project> + </ProjectReference> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/Package/package.VcxProj.Filters b/general/toaster/umdf2/Package/package.VcxProj.Filters new file mode 100644 index 00000000..8153ab30 --- /dev/null +++ b/general/toaster/umdf2/Package/package.VcxProj.Filters @@ -0,0 +1,21 @@ +<?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>{1B3C45DA-0194-4257-B308-970F7B2AB7C0}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{84FCFB7D-58FA-4617-9482-C1BD332BCC31}</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>{824C0178-16B0-4768-B411-CE9BDD79D690}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{9C6B14B3-304F-491F-B5F1-C14CA36EC7E8}</UniqueIdentifier> + </Filter> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/ReadMe.md b/general/toaster/umdf2/ReadMe.md new file mode 100644 index 00000000..8bd9dada --- /dev/null +++ b/general/toaster/umdf2/ReadMe.md @@ -0,0 +1,58 @@ +Toaster Sample (UMDF Version 2) +=============================== + +The Toaster (UMDF version 2) sample is an iterative series of samples that demonstrate fundamental aspects of Windows driver development. + +The Toaster sample collection is comprised of driver projects (.vcxproj files) that are contained in the umdf2toaster.sln solution file. + +For related information, see the [Toaster Sample](http://code.msdn.microsoft.com/windowshardware/Toaster-7d256224). + +## Universal Compliant +This sample builds a Windows Universal driver. It uses only APIs and DDIs that are included in Windows Core. + +Related technologies +-------------------- + +[User-Mode Driver Framework](http://msdn.microsoft.com/en-us/library/windows/hardware/ff560456) + +Run the sample +-------------- + +The computer where you install the driver is called the *target computer* or the *test computer*. Typically this is a separate computer from where you develop and build the driver package. The computer where you develop and build the driver is called the *host computer*. + +The process of moving the driver package to the target computer and installing the driver is called *deploying the driver*. You can deploy a driver sample automatically or manually. + +### Automatic deployment (root enumerated) + +Before you automatically deploy a driver, you must provision the target computer. For instructions, see [Configuring a Computer for Driver Deployment, Testing, and Debugging](http://msdn.microsoft.com/en-us/library/windows/hardware/). + +1. On the host computer, in Visual Studio, in Solution Explorer, right click **package** (lower case), and choose **Properties**. Navigate to **Configuration Properties \> Driver Install \> Deployment**. +2. Check **Enable deployment**, and check **Remove previous driver versions before deployment**. For **Target Computer Name**, select the name of a target computer that you provisioned previously. Select **Hardware ID Driver Update**, and enter **root\\toaster** for the hardware ID. Click **OK**. +3. Because this solution contains many projects, you may find it easier to remove some of them before you build and deploy a driver package. To do so, right click **package** (lower case), and choose **Properties**. Navigate to **Common Properties-\>References** and click **Remove Reference** to remove projects you don't want. (You can add them back later by using **Add New Reference**.) Click **OK**. +4. On the **Build** menu, choose **Build Solution** or **Rebuild Solution** (if you removed references). +5. If you removed references and deployment does not succeed, try deleting the contents of the c:\\DriverTest\\Drivers folder on the target machine, and then retry deployment. + +### Manual deployment (root enumerated) + +Before you manually deploy a driver, you must turn on test signing and install a certificate on the target computer. You also need to copy the [DevCon](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544707) tool to the target computer. For instructions, see [Preparing a Computer for Manual Driver Deployment](http://msdn.microsoft.com/en-us/library/windows/hardware/dn265571). + +1. Copy all of the files in your driver package to a folder on the target computer (for example, c:\\Umdf2toaster). +2. On the target computer, open a Command Prompt window as Administrator. Navigate to your driver package folder, and enter a command such as: + + **devcon install wdfsimpleum.inf root\\toaster** + +### View the root enumerated driver in Device Manager + +On the target computer, in a Command Prompt window, enter **devmgmt** to open Device Manager. In Device Manager, on the **View** menu, choose **Devices by type**. In the device tree, locate **Sample WDF Toaster Service + Filter** (for example, this might be under the **Toaster** node). + +In Device Manager, on the **View** menu, choose **Devices by connection**. Locate **Sample WDF Toaster Service + Filter** as a child of the root node of the device tree. + +Build the sample using MSBuild +------------------------------ + +As an alternative to building the driver sample in Visual Studio, you can build it in a Visual Studio Command Prompt window. In Visual Studio, on the **Tools** menu, choose **Visual Studio Command Prompt**. In the Visual Studio Command Prompt window, navigate to the folder that has the solution file, Umdf2toaster.sln. Use the MSBuild command to build the solution. Here is an example: + +**msbuild /p:configuration=”Win8 Release” /p:platform=”Win32” Umdf2toaster.sln** + +For more information about using MSBuild to build a driver package, see [Building a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554644). + diff --git a/general/toaster/umdf2/exe/enum/Enum.vcxproj b/general/toaster/umdf2/exe/enum/Enum.vcxproj new file mode 100644 index 00000000..822a36c7 --- /dev/null +++ b/general/toaster/umdf2/exe/enum/Enum.vcxproj @@ -0,0 +1,171 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{2F2E0D4F-031E-4B76-983A-ED7F18562A15}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>Enum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>Enum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>Enum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>Enum</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="enum.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/exe/enum/Enum.vcxproj.Filters b/general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters new file mode 100644 index 00000000..c84e1e9f --- /dev/null +++ b/general/toaster/umdf2/exe/enum/Enum.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{58C64BCB-5021-4790-BBB0-C1AB7A443B79}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{17570C2B-4A49-4EB7-9BC8-219A1CDD870D}</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>{B5B13117-98BA-4E65-833F-2DB49A70E1DF}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="enum.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/exe/enum/enum.c b/general/toaster/umdf2/exe/enum/enum.c new file mode 100644 index 00000000..ac285115 --- /dev/null +++ b/general/toaster/umdf2/exe/enum/enum.c @@ -0,0 +1,317 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Enum.c + +Abstract: + This application simulates the plugin, unplug or ejection + of devices. + +Environment: + + usermode console application + +Revision History: + + Eliyas Yakub Oct 14, 1998 + + +--*/ + +#include <basetyps.h> +#include <stdlib.h> +#include <wtypes.h> +#include <setupapi.h> +#include <initguid.h> +#include <stdio.h> +#include <string.h> +#include <winioctl.h> +#include "public.h" +#include <dontuse.h> + +// +// Prototypes +// + +BOOLEAN +OpenBusInterface ( + _In_ HDEVINFO HardwareDeviceInfo, + _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData + ); + + + +#define USAGE \ +"Usage: Enum [-p SerialNo] Plugs in a device. SerialNo must be greater than zero.\n\ + [-u SerialNo or 0] Unplugs device(s) - specify 0 to unplug all \ + the devices enumerated so far.\n\ + [-e SerialNo or 0] Ejects device(s) - specify 0 to eject all \ + the devices enumerated so far.\n" + +BOOLEAN bPlugIn, bUnplug, bEject; +ULONG SerialNo; + +INT __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + + bPlugIn = bUnplug = bEject = FALSE; + + if(argc <3) { + goto usage; + } + + if(argv[1][0] == '-') { + if(tolower(argv[1][1]) == 'p') { + if(argv[2]) + SerialNo = (USHORT)atol(argv[2]); + bPlugIn = TRUE; + } + else if(tolower(argv[1][1]) == 'u') { + if(argv[2]) + SerialNo = (ULONG)atol(argv[2]); + bUnplug = TRUE; + } + else if(tolower(argv[1][1]) == 'e') { + if(argv[2]) + SerialNo = (ULONG)atol(argv[2]); + bEject = TRUE; + } + else { + goto usage; + } + } + else + goto usage; + + if(bPlugIn && 0 == SerialNo) + goto usage; + // + // Open a handle to the device interface information set of all + // present toaster bus enumerator interfaces. + // + + hardwareDeviceInfo = SetupDiGetClassDevs ( + (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); + return 0; + } + + deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, + 0, // + &deviceInterfaceData)) { + + OpenBusInterface(hardwareDeviceInfo, &deviceInterfaceData); + } else if (ERROR_NO_MORE_ITEMS == GetLastError()) { + + printf( + "Error:Interface GUID_DEVINTERFACE_BUSENUM_TOASTER is not registered\n"); + } + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return 0; +usage: + printf(USAGE); + exit(0); +} + +BOOLEAN +OpenBusInterface ( + _In_ HDEVINFO HardwareDeviceInfo, + _In_ PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData + ) +{ + HANDLE file; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + ULONG bytes; + BUSENUM_UNPLUG_HARDWARE unplug; + BUSENUM_EJECT_HARDWARE eject; + PBUSENUM_PLUGIN_HARDWARE hardware; + BOOLEAN bSuccess; + + // + // Allocate a function class device data structure to receive the + // information about this particular device. + // + + SetupDiGetDeviceInterfaceDetail ( + HardwareDeviceInfo, + DeviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL); // not interested in the specific dev-node + + if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + printf("Error in SetupDiGetDeviceInterfaceDetail%d\n", + GetLastError()); + return FALSE; + } + + predictedLength = requiredLength; + + deviceInterfaceDetailData = malloc (predictedLength); + + if(deviceInterfaceDetailData) { + deviceInterfaceDetailData->cbSize = + sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + } else { + printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); + return FALSE; + } + + + if (! SetupDiGetDeviceInterfaceDetail ( + HardwareDeviceInfo, + DeviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + printf("Error in SetupDiGetDeviceInterfaceDetail\n"); + free (deviceInterfaceDetailData); + return FALSE; + } + + printf("Opening %s\n", deviceInterfaceDetailData->DevicePath); + + file = CreateFile ( deviceInterfaceDetailData->DevicePath, + GENERIC_READ, // Only read access + 0, // FILE_SHARE_READ | FILE_SHARE_WRITE + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); // No template file + + if (INVALID_HANDLE_VALUE == file) { + printf("CreateFile failed: 0x%x", GetLastError()); + free (deviceInterfaceDetailData); + return FALSE; + } + + printf("Bus interface opened!!!\n"); + + // + // From this point on, we need to jump to the end of the routine for + // common clean-up. Keep track of whether we succeeded or failed, so + // we'll know what to return to the caller. + // + bSuccess = FALSE; + + // + // Enumerate Devices + // + + if(bPlugIn) { + + printf("SerialNo. of the device to be enumerated: %d\n", SerialNo); + + hardware = malloc (bytes = (sizeof (BUSENUM_PLUGIN_HARDWARE) + + BUS_HARDWARE_IDS_LENGTH)); + + if(hardware) { + hardware->Size = sizeof (BUSENUM_PLUGIN_HARDWARE); + hardware->SerialNo = SerialNo; + } else { + printf("Couldn't allocate %d bytes for busenum plugin hardware structure.\n", bytes); + goto End; + } + + // + // Allocate storage for the Device ID + // + + memcpy (hardware->HardwareIDs, + BUS_HARDWARE_IDS, + BUS_HARDWARE_IDS_LENGTH); + + if (!DeviceIoControl (file, + IOCTL_BUSENUM_PLUGIN_HARDWARE , + hardware, bytes, + NULL, 0, + &bytes, NULL)) { + free (hardware); + printf("PlugIn failed:0x%x\n", GetLastError()); + goto End; + } + + free (hardware); + } + + // + // Removes a device if given the specific Id of the device. Otherwise this + // ioctls removes all the devices that are enumerated so far. + // + + if(bUnplug) { + printf("Unplugging device(s)....\n"); + + unplug.Size = bytes = sizeof (unplug); + unplug.SerialNo = SerialNo; + if (!DeviceIoControl (file, + IOCTL_BUSENUM_UNPLUG_HARDWARE, + &unplug, bytes, + NULL, 0, + &bytes, NULL)) { + printf("Unplug failed: 0x%x\n", GetLastError()); + goto End; + } + } + + // + // Ejects a device if given the specific Id of the device. Otherwise this + // ioctls ejects all the devices that are enumerated so far. + // + + if(bEject) + { + printf("Ejecting Device(s)\n"); + + eject.Size = bytes = sizeof (eject); + eject.SerialNo = SerialNo; + if (!DeviceIoControl (file, + IOCTL_BUSENUM_EJECT_HARDWARE, + &eject, bytes, + NULL, 0, + &bytes, NULL)) { + printf("Eject failed: 0x%x\n", GetLastError()); + goto End; + } + } + + printf("Success!!!\n"); + bSuccess = TRUE; + +End: + CloseHandle(file); + free (deviceInterfaceDetailData); + return bSuccess; +} + + diff --git a/general/toaster/umdf2/exe/notify/notify.c b/general/toaster/umdf2/exe/notify/notify.c new file mode 100644 index 00000000..3362ce3d --- /dev/null +++ b/general/toaster/umdf2/exe/notify/notify.c @@ -0,0 +1,1244 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: notify.c + + +Abstract: + + +Author: + + Eliyas Yakub Nov 23, 1999 + +Environment: + + User mode only. + +Revision History: + + Modified to use linked list for deviceInfo + instead of arrays. (5/12/2000) + +--*/ +#define UNICODE +#define _UNICODE +#define INITGUID + +// +// Annotation to indicate to prefast that this is nondriver user-mode code. +// +#include <DriverSpecs.h> +_Analysis_mode_(_Analysis_code_type_user_code_) + +#include <windows.h> +#include <stdlib.h> +#include <string.h> +#include <setupapi.h> +#include <dbt.h> +#include <winioctl.h> +#include <strsafe.h> +#include "public.h" +#include "notify.h" +#include <dontuse.h> + +BOOL +HandlePowerBroadcast( + HWND hWnd, + WPARAM wParam, + LPARAM lParam); + +// +// Global variables +// +HINSTANCE hInst; +HWND hWndList; +TCHAR szTitle[]=TEXT("Toaster Package Test Application"); +LIST_ENTRY ListHead; +HDEVNOTIFY hInterfaceNotification; +TCHAR OutText[500]; +UINT ListBoxIndex = 0; +GUID InterfaceGuid;// = GUID_DEVINTERFACE_TOASTER; +BOOLEAN Verbose= FALSE; + +_inline BOOLEAN +IsValid( + ULONG No + ) +{ + PLIST_ENTRY thisEntry; + PDEVICE_INFO deviceInfo; + + if(0==(No)) return TRUE; //special case + + for(thisEntry = ListHead.Flink; thisEntry != &ListHead; + thisEntry = thisEntry->Flink) + { + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + if((No) == deviceInfo->SerialNo) { + return TRUE; + } + } + return FALSE; +} + +VOID +Display( + _In_ LPWSTR pstrFormat, // @parm A printf style format string + ... // @parm | ... | Variable paramters based on <p pstrFormat> + ) +{ + HRESULT hr; + va_list va; + + va_start(va, pstrFormat); + // + // Truncation is acceptable. + // + hr = StringCbVPrintf(OutText, sizeof(OutText)-sizeof(WCHAR), pstrFormat, va); + va_end(va); + + if(FAILED(hr)){ + return; + } + + SendMessage(hWndList, LB_INSERTSTRING, ListBoxIndex, (LPARAM)OutText); + SendMessage(hWndList, LB_SETCURSEL, ListBoxIndex, 0); + ListBoxIndex++; + +} + +VOID +DisplayV( + _In_ LPWSTR pstrFormat, // @parm A printf style format string + ... // @parm | ... | Variable paramters based on <p pstrFormat> + ) +{ + va_list va; + + if (Verbose) + { + va_start(va, pstrFormat); + Display(pstrFormat, va); + va_end(va); + } +} +int PASCAL +WinMain ( + _In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPSTR lpCmdLine, + _In_ int nShowCmd + ) +{ + static TCHAR szAppName[]=TEXT("Toaster Notify"); + HWND hWnd; + MSG msg; + WNDCLASS wndclass; + + UNREFERENCED_PARAMETER( lpCmdLine ); + + InterfaceGuid = GUID_DEVINTERFACE_TOASTER; + hInst=hInstance; + + if (!hPrevInstance) + { + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground= GetStockObject(WHITE_BRUSH); + wndclass.lpszMenuName = TEXT("GenericMenu"); + wndclass.lpszClassName= szAppName; + + RegisterClass(&wndclass); + } + + hWnd = CreateWindow (szAppName, + szTitle, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + NULL, + NULL, + hInstance, + NULL); + + ShowWindow (hWnd, nShowCmd); + UpdateWindow(hWnd); + + while (GetMessage (&msg, NULL, 0,0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (0); +} + + +LRESULT +FAR PASCAL +WndProc ( + HWND hWnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ) +{ + DWORD nEventType = (DWORD)wParam; + PDEV_BROADCAST_HDR p = (PDEV_BROADCAST_HDR) lParam; + DEV_BROADCAST_DEVICEINTERFACE filter; + + switch (message) + { + + case WM_COMMAND: + HandleCommands(hWnd, message, wParam, lParam); + return 0; + + case WM_CREATE: + + // + // Load and set the icon of the program + // + SetClassLongPtr(hWnd, GCLP_HICON, + (LONG_PTR)LoadIcon((HINSTANCE)lParam,MAKEINTRESOURCE(IDI_CLASS_ICON))); + + hWndList = CreateWindow (TEXT("listbox"), + NULL, + WS_CHILD|WS_VISIBLE|LBS_NOTIFY | + WS_VSCROLL | WS_BORDER, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + CW_USEDEFAULT, + hWnd, + (HMENU)ID_EDIT, + hInst, + NULL); + + filter.dbcc_size = sizeof(filter); + filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + filter.dbcc_classguid = InterfaceGuid; + hInterfaceNotification = RegisterDeviceNotification(hWnd, &filter, 0); + + InitializeListHead(&ListHead); + EnumExistingDevices(hWnd); + + return 0; + + case WM_SIZE: + + MoveWindow(hWndList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); + return 0; + + case WM_SETFOCUS: + SetFocus(hWndList); + return 0; + + case WM_DEVICECHANGE: + + // + // The DBT_DEVNODES_CHANGED broadcast message is sent + // everytime a device is added or removed. This message + // is typically handled by Device Manager kind of apps, + // which uses it to refresh window whenever something changes. + // The lParam is always NULL in this case. + // + if(DBT_DEVNODES_CHANGED == wParam) { + DisplayV(TEXT("Received DBT_DEVNODES_CHANGED broadcast message")); + return 0; + } + + // + // All the events we're interested in come with lParam pointing to + // a structure headed by a DEV_BROADCAST_HDR. This is denoted by + // bit 15 of wParam being set, and bit 14 being clear. + // + if((wParam & 0xC000) == 0x8000) { + + if (!p) + return 0; + + if (p->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) { + + HandleDeviceInterfaceChange(hWnd, nEventType, (PDEV_BROADCAST_DEVICEINTERFACE) p); + } else if (p->dbch_devicetype == DBT_DEVTYP_HANDLE) { + + HandleDeviceChange(hWnd, nEventType, (PDEV_BROADCAST_HANDLE) p); + } + } + return 0; + + case WM_POWERBROADCAST: + HandlePowerBroadcast(hWnd, wParam, lParam); + return 0; + + case WM_CLOSE: + Cleanup(hWnd); + UnregisterDeviceNotification(hInterfaceNotification); + return DefWindowProc(hWnd,message, wParam, lParam); + + case WM_DESTROY: + PostQuitMessage(0); + return 0; + } + return DefWindowProc(hWnd,message, wParam, lParam); + } + + +LRESULT +HandleCommands( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ) + +{ + PDIALOG_RESULT result = NULL; + + UNREFERENCED_PARAMETER( uMsg ); + UNREFERENCED_PARAMETER( lParam ); + + switch (wParam) { + + case IDM_OPEN: + Cleanup(hWnd); // close all open handles + EnumExistingDevices(hWnd); + break; + + case IDM_CLOSE: + Cleanup(hWnd); + break; + + case IDM_HIDE: + result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); + if(result && result->SerialNo && IsValid(result->SerialNo)) { + DWORD bytes; + PDEVICE_INFO deviceInfo = NULL; + PLIST_ENTRY thisEntry; + + // + // Find out the deviceInfo that matches this SerialNo. + // We need the deviceInfo to get the handle to the device. + // + for(thisEntry = ListHead.Flink; thisEntry != &ListHead; + thisEntry = thisEntry->Flink) + { + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + if(result->SerialNo == deviceInfo->SerialNo) { + break; + } + deviceInfo = NULL; + } + + // + // If found send I/O control + // + + if (deviceInfo && !DeviceIoControl (deviceInfo->hDevice, + IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE, + NULL, 0, + NULL, 0, + &bytes, NULL)) { + MessageBox(hWnd, TEXT("Request Failed or Invalid Serial No"), + TEXT("Error"), MB_OK); + } + } + break; + case IDM_PLUGIN: + + result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG), hWnd, DlgProc); + if(result) { + if(!result->SerialNo || !OpenBusInterface(result->SerialNo, result->DeviceId, PLUGIN)){ + MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); + } + } + break; + case IDM_UNPLUG: + result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); + + if(result && IsValid(result->SerialNo)) { + if(!OpenBusInterface(result->SerialNo, NULL, UNPLUG)) { + MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); + } + } + break; + case IDM_EJECT: + result = (PDIALOG_RESULT)DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, DlgProc); + if(result && IsValid(result->SerialNo)) { + if(!OpenBusInterface(result->SerialNo, NULL, EJECT)) { + MessageBox(hWnd, TEXT("Invalid Serial Number or OpenBusInterface Failed"), TEXT("Error"), MB_OK); + } + } + break; + + case IDM_CLEAR: + SendMessage(hWndList, LB_RESETCONTENT, 0, 0); + ListBoxIndex = 0; + break; + + case IDM_IOCTL: + SendIoctlToFilterDevice(); + break; + + case IDM_VERBOSE: { + + HMENU hMenu = GetMenu(hWnd); + Verbose = !Verbose; + if(Verbose) { + CheckMenuItem(hMenu, (UINT)wParam, MF_CHECKED); + } else { + CheckMenuItem(hMenu, (UINT)wParam, MF_UNCHECKED); + } + } + break; + + case IDM_EXIT: + PostQuitMessage(0); + break; + + default: + break; + } + + if(result) { + HeapFree (GetProcessHeap(), 0, result); + } + return TRUE; +} + +INT_PTR CALLBACK +DlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam +) +{ + BOOL success; + PDIALOG_RESULT dialogResult = NULL; + + UNREFERENCED_PARAMETER( lParam ); + + switch(message) + { + case WM_INITDIALOG: + SetDlgItemText(hDlg, IDC_DEVICEID, BUS_HARDWARE_IDS); + return TRUE; + + case WM_COMMAND: + switch( wParam) + { + case ID_OK: + dialogResult = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (sizeof(DIALOG_RESULT) + MAX_PATH * sizeof(WCHAR))); + if(dialogResult) { + dialogResult->DeviceId = (PWCHAR)((PCHAR)dialogResult + sizeof(DIALOG_RESULT)); + dialogResult->SerialNo = GetDlgItemInt(hDlg,IDC_SERIALNO, &success, FALSE ); + GetDlgItemText(hDlg, IDC_DEVICEID, dialogResult->DeviceId, MAX_PATH-1 ); + } + EndDialog(hDlg, (UINT_PTR)dialogResult); + return TRUE; + case ID_CANCEL: + EndDialog(hDlg, 0); + return TRUE; + + } + break; + + } + return FALSE; +} + + +BOOL +HandleDeviceInterfaceChange( + HWND hWnd, + DWORD evtype, + PDEV_BROADCAST_DEVICEINTERFACE dip + ) +{ + DEV_BROADCAST_HANDLE filter; + PDEVICE_INFO deviceInfo = NULL; + HRESULT hr; + + switch (evtype) + { + case DBT_DEVICEARRIVAL: + // + // New device arrived. Open handle to the device + // and register notification of type DBT_DEVTYP_HANDLE + // + + deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DEVICE_INFO)); + if(!deviceInfo) + return FALSE; + + InitializeListHead(&deviceInfo->ListEntry); + InsertTailList(&ListHead, &deviceInfo->ListEntry); + + + if(!GetDeviceDescription(dip->dbcc_name, + (PBYTE)deviceInfo->DeviceName, + sizeof(deviceInfo->DeviceName), + &deviceInfo->SerialNo)) { + MessageBox(hWnd, TEXT("GetDeviceDescription failed"), TEXT("Error!"), MB_OK); + } + + Display(TEXT("New device Arrived (Interface Change Notification): %ws"), + deviceInfo->DeviceName); + + hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, dip->dbcc_name); + if(FAILED(hr)){ + // DeviceInfo will be freed later by the cleanup routine. + break; + } + + deviceInfo->hDevice = CreateFile(dip->dbcc_name, + GENERIC_READ |GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, 0, NULL); + if(deviceInfo->hDevice == INVALID_HANDLE_VALUE) { + Display(TEXT("Failed to open the device: %ws"), deviceInfo->DeviceName); + break; + } + + Display(TEXT("Opened handled to the device: %ws"), deviceInfo->DeviceName); + memset (&filter, 0, sizeof(filter)); //zero the structure + filter.dbch_size = sizeof(filter); + filter.dbch_devicetype = DBT_DEVTYP_HANDLE; + filter.dbch_handle = deviceInfo->hDevice; + + deviceInfo->hHandleNotification = + RegisterDeviceNotification(hWnd, &filter, 0); + break; + + case DBT_DEVICEREMOVECOMPLETE: + Display(TEXT("Remove Complete (Interface Change Notification)")); + break; + + // + // Device Removed. + // + + default: + Display(TEXT("Unknown (Interface Change Notification)")); + break; + } + return TRUE; +} + +BOOL +HandleDeviceChange( + HWND hWnd, + DWORD evtype, + PDEV_BROADCAST_HANDLE dhp + ) +{ + DEV_BROADCAST_HANDLE filter; + PDEVICE_INFO deviceInfo = NULL; + PLIST_ENTRY thisEntry; + + // + // Walk the list to get the deviceInfo for this device + // by matching the handle given in the notification. + // + for(thisEntry = ListHead.Flink; thisEntry != &ListHead; + thisEntry = thisEntry->Flink) + { + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + if(dhp->dbch_hdevnotify == deviceInfo->hHandleNotification) { + break; + } + deviceInfo = NULL; + } + + if(!deviceInfo) { + Display(TEXT("Error: spurious message, Event Type %x, Device Type %x"), + evtype, dhp->dbch_devicetype); + return FALSE; + } + + switch (evtype) + { + + case DBT_DEVICEQUERYREMOVE: + + Display(TEXT("Query Remove (Handle Notification)"), deviceInfo->DeviceName); + + // User is trying to disable, uninstall, or eject our device. + // Close the handle to the device so that the target device can + // get removed. Do not unregister the notification + // at this point, because we want to know whether + // the device is successfully removed or not. + // + if (deviceInfo->hDevice != INVALID_HANDLE_VALUE) { + + CloseHandle(deviceInfo->hDevice); + deviceInfo->hDevice = INVALID_HANDLE_VALUE; + Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); + } + break; + + case DBT_DEVICEREMOVECOMPLETE: + + Display(TEXT("Remove Complete (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Device is getting surprise removed. So close + // the handle to device and unregister the PNP notification. + // + + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + } + if (deviceInfo->hDevice != INVALID_HANDLE_VALUE) { + + CloseHandle(deviceInfo->hDevice); + deviceInfo->hDevice = INVALID_HANDLE_VALUE; + Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); + } + // + // Unlink this deviceInfo from the list and free the memory + // + RemoveEntryList(&deviceInfo->ListEntry); + HeapFree (GetProcessHeap(), 0, deviceInfo); + + break; + + case DBT_DEVICEREMOVEPENDING: + + Display(TEXT("Remove Pending (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Device is successfully removed so unregister the notification + // and free the memory. + // + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + deviceInfo->hDevice = INVALID_HANDLE_VALUE; + } + // + // Unlink this deviceInfo from the list and free the memory + // + RemoveEntryList(&deviceInfo->ListEntry); + HeapFree (GetProcessHeap(), 0, deviceInfo); + + break; + + case DBT_DEVICEQUERYREMOVEFAILED : + Display(TEXT("Remove failed (Handle Notification):%ws"), + deviceInfo->DeviceName); + // + // Remove failed. So reopen the device and register for + // notification on the new handle. But first we should unregister + // the previous notification. + // + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + } + deviceInfo->hDevice = CreateFile(deviceInfo->DevicePath, + GENERIC_READ | GENERIC_WRITE, + 0, NULL, OPEN_EXISTING, 0, NULL); + if(deviceInfo->hDevice == INVALID_HANDLE_VALUE) { + Display(TEXT("Failed to reopen the device: %ws"), + deviceInfo->DeviceName); + HeapFree (GetProcessHeap(), 0, deviceInfo); + break; + } + + // + // Register handle based notification to receive pnp + // device change notification on the handle. + // + memset (&filter, 0, sizeof(filter)); //zero the structure + filter.dbch_size = sizeof(filter); + filter.dbch_devicetype = DBT_DEVTYP_HANDLE; + filter.dbch_handle = deviceInfo->hDevice; + + deviceInfo->hHandleNotification = + RegisterDeviceNotification(hWnd, &filter, 0); + Display(TEXT("Reopened device %ws"), deviceInfo->DeviceName); + break; + + default: + Display(TEXT("Unknown (Handle Notification)"), deviceInfo->DeviceName); + break; + + } + return TRUE; +} + + +BOOLEAN +EnumExistingDevices( + HWND hWnd +) +{ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + DWORD error; + DEV_BROADCAST_HANDLE filter; + PDEVICE_INFO deviceInfo =NULL; + UINT i=0; + HRESULT hr; + + hardwareDeviceInfo = SetupDiGetClassDevs ( + (LPGUID)&InterfaceGuid, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + goto Error; + } + + // + // Enumerate devices of toaster class + // + deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); + + for(i=0; SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID)&InterfaceGuid, + i, // + &deviceInterfaceData); i++ ) { + + // + // Allocate a function class device data structure to + // receive the information about this particular device. + // + + // + // First find out required length of the buffer + // + if(deviceInterfaceDetailData) + { + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + } + + if(!SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + goto Error; + } + predictedLength = requiredLength; + + deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + predictedLength); + if (deviceInterfaceDetailData == NULL) { + goto Error; + } + deviceInterfaceDetailData->cbSize = + sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + + + if (! SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + goto Error; + } + + deviceInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(DEVICE_INFO)); + if (deviceInfo == NULL) { + goto Error; + } + + InitializeListHead(&deviceInfo->ListEntry); + InsertTailList(&ListHead, &deviceInfo->ListEntry); + + // + // Get the device details such as friendly name and SerialNo + // + if(!GetDeviceDescription(deviceInterfaceDetailData->DevicePath, + (PBYTE)deviceInfo->DeviceName, + sizeof(deviceInfo->DeviceName), + &deviceInfo->SerialNo)){ + goto Error; + } + + Display(TEXT("Found device %ws"), deviceInfo->DeviceName ); + + hr = StringCchCopy(deviceInfo->DevicePath, MAX_PATH, deviceInterfaceDetailData->DevicePath); + if(FAILED(hr)){ + goto Error; + } + // + // Open an handle to the device. + // + deviceInfo->hDevice = CreateFile ( + deviceInterfaceDetailData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); + + if (INVALID_HANDLE_VALUE == deviceInfo->hDevice) { + Display(TEXT("Failed to open the device: %ws"), deviceInfo->DeviceName); + continue; + } + + Display(TEXT("Opened handled to the device: %ws"), deviceInfo->DeviceName); + // + // Register handle based notification to receive pnp + // device change notification on the handle. + // + + memset (&filter, 0, sizeof(filter)); //zero the structure + filter.dbch_size = sizeof(filter); + filter.dbch_devicetype = DBT_DEVTYP_HANDLE; + filter.dbch_handle = deviceInfo->hDevice; + + deviceInfo->hHandleNotification = RegisterDeviceNotification(hWnd, &filter, 0); + + } + + if(deviceInterfaceDetailData) + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return 0; + +Error: + + MessageBox(hWnd, TEXT("EnumExisting Devices failed"), TEXT("Error!"), MB_OK); + if(deviceInterfaceDetailData) + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + Cleanup(hWnd); + return 0; +} + +BOOLEAN Cleanup(HWND hWnd) +{ + PDEVICE_INFO deviceInfo =NULL; + PLIST_ENTRY thisEntry; + + UNREFERENCED_PARAMETER( hWnd ); + + while (!IsListEmpty(&ListHead)) { + thisEntry = RemoveHeadList(&ListHead); + deviceInfo = CONTAINING_RECORD(thisEntry, DEVICE_INFO, ListEntry); + if (deviceInfo->hHandleNotification) { + UnregisterDeviceNotification(deviceInfo->hHandleNotification); + deviceInfo->hHandleNotification = NULL; + } + if (deviceInfo->hDevice != INVALID_HANDLE_VALUE && + deviceInfo->hDevice != NULL) { + CloseHandle(deviceInfo->hDevice); + deviceInfo->hDevice = INVALID_HANDLE_VALUE; + Display(TEXT("Closed handle to device %ws"), deviceInfo->DeviceName ); + } + HeapFree (GetProcessHeap(), 0, deviceInfo); + } + return TRUE; +} + + +BOOL +GetDeviceDescription( + _In_ LPTSTR DevPath, + _Out_writes_bytes_(OutBufferLen) PBYTE OutBuffer, + _In_ ULONG OutBufferLen, + _In_ PULONG SerialNo +) +{ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + SP_DEVINFO_DATA deviceInfoData; + DWORD dwRegType, error; + + hardwareDeviceInfo = SetupDiCreateDeviceInfoList(NULL, NULL); + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + goto Error; + } + + // + // Enumerate devices of toaster class + // + deviceInterfaceData.cbSize = sizeof(deviceInterfaceData); + + SetupDiOpenDeviceInterface (hardwareDeviceInfo, DevPath, + 0, // + &deviceInterfaceData); + + deviceInfoData.cbSize = sizeof(deviceInfoData); + if(!SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + NULL, + &deviceInfoData) && (error = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) + { + goto Error; + } + // + // Get the friendly name for this instance, if that fails + // try to get the device description. + // + + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, + SPDRP_FRIENDLYNAME, + &dwRegType, + OutBuffer, + OutBufferLen, + NULL)) + { + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, &deviceInfoData, + SPDRP_DEVICEDESC, + &dwRegType, + OutBuffer, + OutBufferLen, + NULL)){ + goto Error; + + } + + + } + + // + // Get the serial number of the device. The bus driver reports + // the device serial number as UINumber in the devcaps. + // + if(!SetupDiGetDeviceRegistryProperty(hardwareDeviceInfo, + &deviceInfoData, + SPDRP_UI_NUMBER, + &dwRegType, + (BYTE*) SerialNo, + sizeof(ULONG), + NULL)) { + Display(TEXT("SerialNo is not available for device: %ws"), OutBuffer ); + } + + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return TRUE; + +Error: + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return FALSE; +} + + + +BOOLEAN +OpenBusInterface ( + _In_ ULONG SerialNo, + _When_ (Action == PLUGIN, _In_) LPWSTR DeviceId, + _In_ USER_ACTION_TYPE Action + ) +{ + HANDLE hDevice=INVALID_HANDLE_VALUE; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + ULONG bytes; + BUSENUM_UNPLUG_HARDWARE unplug; + BUSENUM_EJECT_HARDWARE eject; + PBUSENUM_PLUGIN_HARDWARE hardware; + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + BOOLEAN status = FALSE; + HRESULT hr; + // + // Open a handle to the device interface information set of all + // present toaster bus enumerator interfaces. + // + + hardwareDeviceInfo = SetupDiGetClassDevs ( + (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + return FALSE; + } + + deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + if (!SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID)&GUID_DEVINTERFACE_BUSENUM_TOASTER, + 0, // + &deviceInterfaceData)) { + goto Clean0; + } + + // + // Allocate a function class device data structure to receive the + // information about this particular device. + // + + SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL);//not interested in the specific dev-node + + if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + goto Clean0; + } + + + predictedLength = requiredLength; + + deviceInterfaceDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + predictedLength); + + if(deviceInterfaceDetailData) { + deviceInterfaceDetailData->cbSize = + sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + } else { + goto Clean0; + } + + + if (! SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + goto Clean1; + } + + + hDevice = CreateFile ( deviceInterfaceDetailData->DevicePath, + GENERIC_READ, // Only read access + 0, // FILE_SHARE_READ | FILE_SHARE_WRITE + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); // No template file + + if (INVALID_HANDLE_VALUE == hDevice) { + goto Clean1; + } + + // + // Enumerate Devices + // + + if(Action == PLUGIN) { + int length = (int) (wcslen(DeviceId)+2)*sizeof(WCHAR); //in bytes + + bytes = sizeof (BUSENUM_PLUGIN_HARDWARE) + length; + hardware = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bytes); + + if(hardware) { + memset(hardware, 0, bytes); + hardware->Size = sizeof (BUSENUM_PLUGIN_HARDWARE); + hardware->SerialNo = SerialNo; + } else { + goto Clean2; + } + + // + // copy the Device ID + // + hr = StringCchCopy(hardware->HardwareIDs, length/sizeof(WCHAR), DeviceId); + if (SUCCEEDED(hr) && DeviceIoControl (hDevice, + IOCTL_BUSENUM_PLUGIN_HARDWARE , + hardware, bytes, + NULL, 0, + &bytes, NULL)) { + status = TRUE; + } + + HeapFree (GetProcessHeap(), 0, hardware); + + } + + // + // Removes a device if given the specific Id of the device. Otherwise this + // ioctls removes all the devices that are enumerated so far. + // + + if(Action == UNPLUG) { + + unplug.Size = bytes = sizeof (unplug); + unplug.SerialNo = SerialNo; + if (DeviceIoControl (hDevice, + IOCTL_BUSENUM_UNPLUG_HARDWARE, + &unplug, bytes, + NULL, 0, + &bytes, NULL)) { + status = TRUE; + } + } + + // + // Ejects a device if given the specific Id of the device. Otherwise this + // ioctls ejects all the devices that are enumerated so far. + // + + if(Action == EJECT) + { + + eject.Size = bytes = sizeof (eject); + eject.SerialNo = SerialNo; + if (DeviceIoControl (hDevice, + IOCTL_BUSENUM_EJECT_HARDWARE, + &eject, bytes, + NULL, 0, + &bytes, NULL)) { + status = TRUE; + } + } + +Clean2: + CloseHandle(hDevice); +Clean1: + HeapFree (GetProcessHeap(), 0, deviceInterfaceDetailData); +Clean0: + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return status; +} + +BOOL +HandlePowerBroadcast( + HWND hWnd, + WPARAM wParam, + LPARAM lParam) +{ + BOOL fRet = TRUE; + + UNREFERENCED_PARAMETER( hWnd ); + UNREFERENCED_PARAMETER( lParam ); + + switch (wParam) + { + case PBT_APMQUERYSTANDBY: + DisplayV(TEXT("PBT_APMQUERYSTANDBY")); + break; + case PBT_APMQUERYSUSPEND: + DisplayV(TEXT("PBT_APMQUERYSUSPEND")); + break; + case PBT_APMSTANDBY : + DisplayV(TEXT("PBT_APMSTANDBY")); + break; + case PBT_APMSUSPEND : + DisplayV(TEXT("PBT_APMSUSPEND")); + break; + case PBT_APMQUERYSTANDBYFAILED: + DisplayV(TEXT("PBT_APMQUERYSTANDBYFAILED")); + break; + case PBT_APMRESUMESTANDBY: + DisplayV(TEXT("PBT_APMRESUMESTANDBY")); + break; + case PBT_APMQUERYSUSPENDFAILED: + DisplayV(TEXT("PBT_APMQUERYSUSPENDFAILED")); + break; + case PBT_APMRESUMESUSPEND: + DisplayV(TEXT("PBT_APMRESUMESUSPEND")); + break; + case PBT_APMBATTERYLOW: + DisplayV(TEXT("PBT_APMBATTERYLOW")); + break; + case PBT_APMOEMEVENT: + DisplayV(TEXT("PBT_APMOEMEVENT")); + break; + case PBT_APMRESUMEAUTOMATIC: + DisplayV(TEXT("PBT_APMRESUMEAUTOMATIC")); + break; + case PBT_APMRESUMECRITICAL: + DisplayV(TEXT("PBT_APMRESUMECRITICAL")); + break; + case PBT_APMPOWERSTATUSCHANGE: + DisplayV(TEXT("PBT_APMPOWERSTATUSCHANGE")); + break; + default: + DisplayV(TEXT("Default")); + break; + } + return fRet; +} + +void +SendIoctlToFilterDevice() +{ +#define IOCTL_CUSTOM_CODE CTL_CODE(FILE_DEVICE_UNKNOWN, 0, METHOD_BUFFERED, FILE_READ_DATA) + + HANDLE hControlDevice; + ULONG bytes; + + // + // Open handle to the control device. Please note that even + // a non-admin user can open handle to the device with + // FILE_READ_ATTRIBUTES | SYNCHRONIZE DesiredAccess and send IOCTLs if the + // IOCTL is defined with FILE_ANY_ACCESS. So for better security avoid + // specifying FILE_ANY_ACCESS in your IOCTL defintions. + // If the IOCTL is defined to have FILE_READ_DATA access rights, you can + // open the device with GENERIC_READ and call DeviceIoControl. + // If the IOCTL is defined to have FILE_WRITE_DATA access rights, you can + // open the device with GENERIC_WRITE and call DeviceIoControl. + // + hControlDevice = CreateFile ( TEXT("\\\\.\\ToasterFilter"), + GENERIC_READ, // Only read access + 0, // FILE_SHARE_READ | FILE_SHARE_WRITE + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); // No template file + + if (INVALID_HANDLE_VALUE == hControlDevice) { + Display(TEXT("Failed to open ToasterFilter device")); + } else { + if (!DeviceIoControl (hControlDevice, + IOCTL_CUSTOM_CODE, + NULL, 0, + NULL, 0, + &bytes, NULL)) { + Display(TEXT("Ioctl to ToasterFilter device failed")); + } else { + Display(TEXT("Ioctl to ToasterFilter device succeeded")); + } + CloseHandle(hControlDevice); + } + return; +} diff --git a/general/toaster/umdf2/exe/notify/notify.h b/general/toaster/umdf2/exe/notify/notify.h new file mode 100644 index 00000000..98db2918 --- /dev/null +++ b/general/toaster/umdf2/exe/notify/notify.h @@ -0,0 +1,182 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + notify.h + +Abstract: + + +Author: + + Eliyas Yakub Nov 23, 1999 + +Environment: + + +Revision History: + + +--*/ + +#ifndef __NOTIFY_H +#define __NOTIFY_H + + +// +// Copied Macros from ntddk.h +// + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (PCHAR)(address) - \ + (ULONG_PTR)(&((type *)0)->field))) + + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +typedef struct _DEVICE_INFO +{ + HANDLE hDevice; // file handle + HDEVNOTIFY hHandleNotification; // notification handle + TCHAR DeviceName[MAX_PATH];// friendly name of device description + TCHAR DevicePath[MAX_PATH];// + ULONG SerialNo; // Serial number of the device. + LIST_ENTRY ListEntry; +} DEVICE_INFO, *PDEVICE_INFO; + + +typedef enum { + + PLUGIN = 1, + UNPLUG, + EJECT + +} USER_ACTION_TYPE; + +typedef struct _DIALOG_RESULT +{ + ULONG SerialNo; + PWCHAR DeviceId; +} DIALOG_RESULT, *PDIALOG_RESULT; + +#define ID_EDIT 1 + +#define IDM_OPEN 100 +#define IDM_CLOSE 101 +#define IDM_EXIT 102 +#define IDM_HIDE 103 +#define IDM_PLUGIN 104 +#define IDM_UNPLUG 105 +#define IDM_EJECT 106 +#define IDM_ENABLE 107 +#define IDM_DISABLE 108 +#define IDM_CLEAR 109 +#define IDM_IOCTL 110 +#define IDM_VERBOSE 111 + +#define IDD_DIALOG 115 +#define IDD_DIALOG1 116 +#define IDD_DIALOG2 117 +#define ID_OK 118 +#define ID_CANCEL 119 +#define IDC_SERIALNO 1000 +#define IDC_DEVICEID 1001 +#define IDC_STATIC -1 + +#define IDI_CLASS_ICON 200 + +LRESULT FAR PASCAL +WndProc ( + HWND hwnd, + UINT message, + WPARAM wParam, + LPARAM lParam + ); + +BOOLEAN EnumExistingDevices( + HWND hWnd + ); + +BOOL HandleDeviceInterfaceChange( + HWND hwnd, + DWORD evtype, + PDEV_BROADCAST_DEVICEINTERFACE dip + ); + +BOOL HandleDeviceChange( + HWND hwnd, + DWORD evtype, + PDEV_BROADCAST_HANDLE dhp + ); + +LRESULT +HandleCommands( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam + ); + +BOOLEAN Cleanup( + HWND hWnd + ); + +BOOL +GetDeviceDescription( + _In_ LPTSTR DevPath, + _Out_writes_bytes_(OutBufferLen) PBYTE OutBuffer, + _In_ ULONG OutBufferLen, + _In_ PULONG SerialNo + ); + +BOOLEAN +OpenBusInterface ( + _In_ ULONG SerialNo, + _When_ (Action == PLUGIN, _In_) LPWSTR DeviceId, + _In_ USER_ACTION_TYPE Action + ); + + +INT_PTR CALLBACK +DlgProc( + HWND hDlg, + UINT message, + WPARAM wParam, + LPARAM lParam); + +void +SendIoctlToFilterDevice(); + + +#endif + diff --git a/general/toaster/umdf2/exe/notify/notify.rc b/general/toaster/umdf2/exe/notify/notify.rc new file mode 100644 index 00000000..eb15657f --- /dev/null +++ b/general/toaster/umdf2/exe/notify/notify.rc @@ -0,0 +1,77 @@ +#include "windows.h" + +#include "notify.h" + + +GenericMenu MENU + { + POPUP "&File" + { + MENUITEM "Clear &Display", IDM_CLEAR + MENUITEM "&Verbose Trace", IDM_VERBOSE + MENUITEM "E&xit", IDM_EXIT + } + POPUP "&Bus" + { + MENUITEM "&PlugIn", IDM_PLUGIN + MENUITEM "&UnPlug (Surprise Removal)", IDM_UNPLUG + MENUITEM "&Eject", IDM_EJECT + } + POPUP "&Function" + { + MENUITEM "&Open", IDM_OPEN + MENUITEM "&Close", IDM_CLOSE + MENUITEM "&Hide", IDM_HIDE + + } + POPUP "Fil&ter" + { + MENUITEM "&Ioctl to Control Device", IDM_IOCTL + } + } + + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog for plug in +// + +IDD_DIALOG DIALOG DISCARDABLE 0, 0, 289, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Plug In Device" +FONT 8, "MS Shell Dlg" +BEGIN + DEFPUSHBUTTON "OK",ID_OK,72,61,50,14,BS_NOTIFY + PUSHBUTTON "CANCEL",ID_CANCEL,170,60,50,14,BS_NOTIFY + LTEXT "Serial Number :",IDC_STATIC,18,13,55,8 + LTEXT "Device ID :",IDC_STATIC,20,35,55,8 + EDITTEXT IDC_SERIALNO,75,11,24,14,ES_NUMBER + EDITTEXT IDC_DEVICEID,76,32,200,14,ES_AUTOHSCROLL +END + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog for unplug/hide/enable/disable +// + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 232, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Enter SerialNo of the device" +FONT 8, "MS Shell Dlg" +BEGIN + LTEXT "Serial Number :",IDC_STATIC,18,13,55,8 + EDITTEXT IDC_SERIALNO,75,11,24,14,ES_NUMBER + DEFPUSHBUTTON "OK",ID_OK,27,61,50,14,BS_NOTIFY + PUSHBUTTON "CANCEL",ID_CANCEL,121,60,50,14,BS_NOTIFY +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +IDI_CLASS_ICON ICON DISCARDABLE "TOASTER.ICO" + + diff --git a/general/toaster/umdf2/exe/notify/notify.vcxproj b/general/toaster/umdf2/exe/notify/notify.vcxproj new file mode 100644 index 00000000..9d65f2f7 --- /dev/null +++ b/general/toaster/umdf2/exe/notify/notify.vcxproj @@ -0,0 +1,172 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{83E3E107-0EC1-44A8-BA29-BFBB6C43DC53}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>notify</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>notify</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>notify</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>notify</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="notify.c" /> + <ResourceCompile Include="notify.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/exe/notify/notify.vcxproj.Filters b/general/toaster/umdf2/exe/notify/notify.vcxproj.Filters new file mode 100644 index 00000000..ccccf66b --- /dev/null +++ b/general/toaster/umdf2/exe/notify/notify.vcxproj.Filters @@ -0,0 +1,27 @@ +<?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>{26C90330-C836-4747-995F-76F38B79BDA9}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{04722C15-5D21-4294-B1A9-004CFAF38D17}</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>{600866EB-F078-4625-8B46-D93F60CD2380}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="notify.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="notify.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/exe/notify/toaster.ico b/general/toaster/umdf2/exe/notify/toaster.ico Binary files differnew file mode 100644 index 00000000..77ad2081 --- /dev/null +++ b/general/toaster/umdf2/exe/notify/toaster.ico diff --git a/general/toaster/umdf2/exe/toast/toast.c b/general/toaster/umdf2/exe/toast/toast.c new file mode 100644 index 00000000..4f0525c6 --- /dev/null +++ b/general/toaster/umdf2/exe/toast/toast.c @@ -0,0 +1,343 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + TOAST.C + +Abstract: + + Lists all the toaster device and interfaces present in the system + and opens the last interface to send an invalidate device Ioctl request + or read requests. + +Environment: + + usermode console application + +Revision History: + + Eliyas Yakub Nov 2, 1998 + + +--*/ + +#include <basetyps.h> +#include <stdlib.h> +#include <wtypes.h> +#include <setupapi.h> +#include <initguid.h> +#include <stdio.h> +#include <string.h> +#include <winioctl.h> +#include "public.h" +#include <conio.h> +#include <dontuse.h> + +#define USAGE \ +"Usage: Toast <-h> {-h option causes the device to hide from Device Manager UI}\n" + +BOOL PrintToasterDeviceInfo(); + +INT __cdecl +main( + _In_ ULONG argc, + _In_reads_(argc) PCHAR argv[] + ) +{ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0, bytes=0; + HANDLE file; + int i, ch; + char buffer[10]; + BOOL bHide = FALSE; + + if(argc == 2) { + if(argv[1][0] == '-') { + if(argv[1][1] == 'h' || argv[1][1] == 'H') { + bHide = TRUE; + } else { + printf(USAGE); + exit(0); + } + } + else { + printf(USAGE); + exit(0); + } + } + + + // + // Print a list of devices of Toaster Class + // + if(!PrintToasterDeviceInfo()) + { + printf("No toaster devices present\n"); + return 0; + } + + // + // Open a handle to the device interface information set of all + // present toaster class interfaces. + // + + hardwareDeviceInfo = SetupDiGetClassDevs ( + (LPGUID)&GUID_DEVINTERFACE_TOASTER, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if(INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); + return 0; + } + + deviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA); + + printf("\nList of Toaster Device Interfaces\n"); + printf("---------------------------------\n"); + + i = 0; + + // + // Enumerate devices of toaster class + // + + for(;;) { + if (SetupDiEnumDeviceInterfaces (hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID)&GUID_DEVINTERFACE_TOASTER, + i, // + &deviceInterfaceData)) { + + if(deviceInterfaceDetailData) { + free (deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + } + + // + // Allocate a function class device data structure to + // receive the information about this particular device. + // + + // + // First find out required length of the buffer + // + + if(!SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL)) { // not interested in the specific dev-node + if(ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + printf("SetupDiGetDeviceInterfaceDetail failed %d\n", GetLastError()); + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return FALSE; + } + + } + + predictedLength = requiredLength; + + deviceInterfaceDetailData = malloc (predictedLength); + + if(deviceInterfaceDetailData) { + deviceInterfaceDetailData->cbSize = + sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); + } else { + printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + return FALSE; + } + + + if (! SetupDiGetDeviceInterfaceDetail ( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + printf("Error in SetupDiGetDeviceInterfaceDetail\n"); + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + free (deviceInterfaceDetailData); + return FALSE; + } + printf("%d) %s\n", ++i, + deviceInterfaceDetailData->DevicePath); + } + else if (ERROR_NO_MORE_ITEMS != GetLastError()) { + free (deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + continue; + } + else + break; + + } + + + SetupDiDestroyDeviceInfoList (hardwareDeviceInfo); + + if(!deviceInterfaceDetailData) + { + printf("No device interfaces present\n"); + return 0; + } + + // + // Open the last toaster device interface + // + + printf("\nOpening the last interface:\n %s\n", + deviceInterfaceDetailData->DevicePath); + + file = CreateFile ( deviceInterfaceDetailData->DevicePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); + + if (INVALID_HANDLE_VALUE == file) { + printf("Error in CreateFile: %x", GetLastError()); + free (deviceInterfaceDetailData); + return 0; + } + + // + // Invalidate the Device State + // + + if(bHide) + { + if (!DeviceIoControl (file, + IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE, + NULL, 0, + NULL, 0, + &bytes, NULL)) { + printf("Invalidate device request failed:0x%x\n", GetLastError()); + free (deviceInterfaceDetailData); + CloseHandle(file); + return 0; + } + printf("\nRequest to hide the device completed successfully\n"); + + } + + + // + // Read/Write to the toaster device. + // + + printf("\nPress 'q' to exit, any other key to read...\n"); + fflush(stdin); + ch = _getche(); + + while(tolower(ch) != 'q' ) + { + + if(!ReadFile(file, buffer, sizeof(buffer), &bytes, NULL)) + { + printf("Error in ReadFile: %x", GetLastError()); + break; + } + printf("Read Successful\n"); + ch = _getche(); + } + + free (deviceInterfaceDetailData); + CloseHandle(file); + return 0; +} + + + +BOOL +PrintToasterDeviceInfo() +{ + HDEVINFO hdi; + DWORD dwIndex=0; + SP_DEVINFO_DATA deid; + BOOL fSuccess=FALSE; + CHAR szCompInstanceId[MAX_PATH]; + CHAR szCompDescription[MAX_PATH]; + CHAR szFriendlyName[MAX_PATH]; + DWORD dwRegType; + BOOL fFound=FALSE; + + // get a list of all devices of class 'GUID_DEVCLASS_TOASTER' + hdi = SetupDiGetClassDevs(&GUID_DEVCLASS_TOASTER, NULL, NULL, + DIGCF_PRESENT); + + if (INVALID_HANDLE_VALUE != hdi) + { + + // enumerate over each device + while (deid.cbSize = sizeof(SP_DEVINFO_DATA), + SetupDiEnumDeviceInfo(hdi, dwIndex, &deid)) + { + dwIndex++; + + // the right thing to do here would be to call this function + // to get the size required to hold the instance ID and then + // to call it second time with a buffer large enough for that size. + // However, that would tend to obscure the control flow in + // the sample code. Lets keep things simple by keeping the + // buffer large enough. + + // get the device instance ID + fSuccess = SetupDiGetDeviceInstanceId(hdi, &deid, + szCompInstanceId, + MAX_PATH, NULL); + if (fSuccess) + { + // get the description for this instance + fSuccess = + SetupDiGetDeviceRegistryProperty(hdi, &deid, + SPDRP_DEVICEDESC, + &dwRegType, + (BYTE*) szCompDescription, + MAX_PATH, + NULL); + if (fSuccess) + { + memset(szFriendlyName, 0, MAX_PATH); + SetupDiGetDeviceRegistryProperty(hdi, &deid, + SPDRP_FRIENDLYNAME, + &dwRegType, + (BYTE*) szFriendlyName, + MAX_PATH, + NULL); + fFound = TRUE; + printf("Instance ID : %s\n", szCompInstanceId); + printf("Description : %s\n", szCompDescription); + printf("FriendlyName: %s\n\n", szFriendlyName); + } + } + } + + // release the device info list + SetupDiDestroyDeviceInfoList(hdi); + } + + if(fFound) + return TRUE; + else + return FALSE; +} + diff --git a/general/toaster/umdf2/exe/toast/toast.vcxproj b/general/toaster/umdf2/exe/toast/toast.vcxproj new file mode 100644 index 00000000..45a4ceb0 --- /dev/null +++ b/general/toaster/umdf2/exe/toast/toast.vcxproj @@ -0,0 +1,171 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{9BF4F988-D8B7-4E73-BC77-6658D413212F}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{5A95B864-3AA6-41E5-AF06-4FB9836D4219}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>toast</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>toast</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>toast</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>toast</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);setupapi.lib</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="toast.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/exe/toast/toast.vcxproj.Filters b/general/toaster/umdf2/exe/toast/toast.vcxproj.Filters new file mode 100644 index 00000000..b418a4e3 --- /dev/null +++ b/general/toaster/umdf2/exe/toast/toast.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{74122CFE-AC0A-405A-887C-C84F0A71602A}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{BF44B779-EC06-4E53-8DA1-5B27378BE11C}</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>{92FCEB4A-CD44-4D16-8B54-1B192FADB341}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="toast.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/filter/generic/filter.c b/general/toaster/umdf2/filter/generic/filter.c new file mode 100644 index 00000000..d245c2ba --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filter.c @@ -0,0 +1,387 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + filter.c + +Abstract: + + This module shows how to a write a generic filter driver. The driver demonstrates how + to support device I/O control requests through queues. All the I/O requests passed on to + the lower driver. This filter driver shows how to handle IRP postprocessing by forwarding + the requests with and without a completion routine. To forward with a completion routine + set the define FORWARD_REQUEST_WITH_COMPLETION to 1. + +Environment: + + User mode + +--*/ + +#include "filter.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, FilterEvtDeviceAdd) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + WDFDRIVER hDriver; + + KdPrint(("Toaster Generic Filter Driver Sample - Driver Framework Edition.\n")); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + FilterEvtDeviceAdd + ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + &hDriver); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + return status; +} + + +NTSTATUS +FilterEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. Here you can query the device properties + using WdfFdoInitWdmGetPhysicalDevice/IoGetDeviceProperty and based + on that, decide to create a filter device object and attach to the + function stack. If you are not interested in filtering this particular + instance of the device, you can just return STATUS_SUCCESS without creating + a framework device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES deviceAttributes; + PFILTER_EXTENSION filterExt; + NTSTATUS status; + WDFDEVICE device; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + + PAGED_CODE (); + + UNREFERENCED_PARAMETER(Driver); + + // + // Tell the framework that you are filter driver. Framework + // takes care of inherting all the device flags & characterstics + // from the lower device you are attaching to. + // + WdfFdoInitSetFilter(DeviceInit); + + // + // Specify the size of device extension where we track per device + // context. + // + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, FILTER_EXTENSION); + + // + // Create a framework device object.This call will inturn create + // a WDM deviceobject, attach to the lower stack and set the + // appropriate flags and attributes. + // + status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); + return status; + } + + filterExt = FilterGetData(device); + + // + // Configure the default queue to be Parallel. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + // + // Framework by default creates non-power managed queues for + // filter drivers. + // + ioQueueConfig.EvtIoDeviceControl = FilterEvtIoDeviceControl; + + status = WdfIoQueueCreate(device, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + WDF_NO_HANDLE // pointer to default queue + ); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + return status; +} + +VOID +FilterEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This routine is the dispatch routine for internal device control requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + PFILTER_EXTENSION filterExt; + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE device; + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + KdPrint(("Entered FilterEvtIoDeviceControl\n")); + + device = WdfIoQueueGetDevice(Queue); + + filterExt = FilterGetData(device); + + switch (IoControlCode) { + + // + // Put your cases for handling IOCTLs here + // + + default: + status = STATUS_SUCCESS; + } + + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + return; + } + + // + // Forward the request down. WdfDeviceGetIoTarget returns + // the default target, which represents the device attached to us below in + // the stack. + // +#if FORWARD_REQUEST_WITH_COMPLETION + // + // Use this routine to forward a request if you are interested in post + // processing the IRP. + // + FilterForwardRequestWithCompletionRoutine(Request, + WdfDeviceGetIoTarget(device)); +#else + FilterForwardRequest(Request, WdfDeviceGetIoTarget(device)); +#endif + + return; +} + +VOID +FilterForwardRequest( + IN WDFREQUEST Request, + IN WDFIOTARGET Target + ) +/*++ +Routine Description: + + Passes a request on to the lower driver. + +--*/ +{ + WDF_REQUEST_SEND_OPTIONS options; + BOOLEAN ret; + NTSTATUS status; + + // + // We are not interested in post processing the IRP so + // fire and forget. + // + WDF_REQUEST_SEND_OPTIONS_INIT(&options, + WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); + + ret = WdfRequestSend(Request, Target, &options); + + if (ret == FALSE) { + status = WdfRequestGetStatus (Request); + KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + } + + return; +} + +#if FORWARD_REQUEST_WITH_COMPLETION + +VOID +FilterForwardRequestWithCompletionRoutine( + IN WDFREQUEST Request, + IN WDFIOTARGET Target + ) +/*++ +Routine Description: + + This routine forwards the request to a lower driver with + a completion so that when the request is completed by the + lower driver, it can regain control of the request and look + at the result. + +--*/ +{ + BOOLEAN ret; + NTSTATUS status; + + // + // The following funciton essentially copies the content of + // current stack location of the underlying IRP to the next one. + // + WdfRequestFormatRequestUsingCurrentType(Request); + + WdfRequestSetCompletionRoutine(Request, + FilterRequestCompletionRoutine, + WDF_NO_CONTEXT); + + ret = WdfRequestSend(Request, + Target, + WDF_NO_SEND_OPTIONS); + + if (ret == FALSE) { + status = WdfRequestGetStatus (Request); + KdPrint( ("WdfRequestSend failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + } + + return; +} + +VOID +FilterRequestCompletionRoutine( + IN WDFREQUEST Request, + IN WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + IN WDFCONTEXT Context + ) +/*++ + +Routine Description: + + Completion Routine + +Arguments: + + Target - Target handle + Request - Request handle + Params - request completion params + Context - Driver supplied context + + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(Target); + UNREFERENCED_PARAMETER(Context); + + WdfRequestComplete(Request, CompletionParams->IoStatus.Status); + + return; +} + +#endif //FORWARD_REQUEST_WITH_COMPLETION + + + + diff --git a/general/toaster/umdf2/filter/generic/filter.h b/general/toaster/umdf2/filter/generic/filter.h new file mode 100644 index 00000000..e9042c29 --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filter.h @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + filter.h + +Abstract: + + Contains structure definitions and function prototypes for a generic filter driver. + +Environment: + + User mode + +--*/ + +#include <windows.h> +#include <winioctl.h> +#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union +#include <ntstatus.h> +#include <devpropdef.h> +#include <wudfwdm.h> +#include <wdf.h> + +#if !defined(_FILTER_H_) +#define _FILTER_H_ + + +#define DRIVERNAME "Generic.sys: " + +// +// Change the following define to 1 if you want to forward +// the request with a completion routine. +// +#define FORWARD_REQUEST_WITH_COMPLETION 0 + + +typedef struct _FILTER_EXTENSION +{ + WDFDEVICE WdfDevice; + // More context data here + +}FILTER_EXTENSION, *PFILTER_EXTENSION; + + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FILTER_EXTENSION, + FilterGetData) + +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_DEVICE_ADD FilterEvtDeviceAdd; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL FilterEvtIoDeviceControl; + +VOID +FilterForwardRequest( + IN WDFREQUEST Request, + IN WDFIOTARGET Target + ); + +#if FORWARD_REQUEST_WITH_COMPLETION + +VOID +FilterForwardRequestWithCompletionRoutine( + IN WDFREQUEST Request, + IN WDFIOTARGET Target + ); + +VOID +FilterRequestCompletionRoutine( + IN WDFREQUEST Request, + IN WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + IN WDFCONTEXT Context + ); + +#endif //FORWARD_REQUEST_WITH_COMPLETION + +#endif + diff --git a/general/toaster/umdf2/filter/generic/filter.rc b/general/toaster/umdf2/filter/generic/filter.rc new file mode 100644 index 00000000..0c108f44 --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filter.rc @@ -0,0 +1,12 @@ +#include <windows.h> +#include <filter.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "UMDF 2.0 Filter Driver for the Toaster Stack" +#define VER_INTERNALNAME_STR DRIVERNAME +#define VER_ORIGINALFILENAME_STR DRIVERNAME + +#include "common.ver" + diff --git a/general/toaster/umdf2/filter/generic/filterum.inx b/general/toaster/umdf2/filter/generic/filterum.inx new file mode 100644 index 00000000..3e7013ae --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filterum.inx @@ -0,0 +1,98 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +;Module Name: +; +; filterum.INF +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=TOASTER +ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} +Provider=%MSFT% +DriverVer=06/16/1999,5.00.2064 +CatalogFile=wudf.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=ToasterClassReg + +[ToasterClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,100 +HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. + ;This one overrides the security set by the driver + +;***************************************** +; Toaster Device Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + + +; For XP and later +[Standard.NT$ARCH$] +%WdfSimpleDevice.DeviceDesc%=Toaster_Device, root\toaster + +[Toaster_Device.NT] +CopyFiles=UMDriverCopy + +; ---------------- file copy +[UMDriverCopy] +wdfsimpleum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME +filterum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers/umdf + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +wdfsimpleum.dll = 1,, +filterum.dll = 1,, + +;-------------- Service installation + +[Toaster_Device.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +;-------------- WDF specific section ------------- +[Toaster_Device.NT.Wdf] +UmdfService=wdfsimpleum, wdfsimple_Install +UmdfService=filterum, filter_Install +UmdfServiceOrder=wdfsimpleum, filterum + +[wdfsimple_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\wdfsimpleum.dll + +[filter_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\filterum.dll + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample Toaster Installation Disk #1" +WdfSimpleDevice.DeviceDesc = "Sample WDF Toaster Service + Filter" +ClassName = "Toaster" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" + diff --git a/general/toaster/umdf2/filter/generic/filterum.vcxproj b/general/toaster/umdf2/filter/generic/filterum.vcxproj new file mode 100644 index 00000000..d1f340e4 --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filterum.vcxproj @@ -0,0 +1,188 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{A60F76D2-C512-4DA6-8C80-263F1B506267}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <SupportsPackaging>false</SupportsPackaging> + <RequiresPackageProject>true</RequiresPackageProject> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{0B7A9ABA-5822-49BC-84D3-571A2C7F009A}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\filterum.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\filterum.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>filterum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>filterum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>filterum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>filterum</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </ResourceCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="filter.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/filter/generic/filterum.vcxproj.Filters b/general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters new file mode 100644 index 00000000..e36af926 --- /dev/null +++ b/general/toaster/umdf2/filter/generic/filterum.vcxproj.Filters @@ -0,0 +1,34 @@ +<?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>{DD0D84E8-FA6D-4F21-A94F-490114347147}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{D308818F-2345-4AAC-AE3A-51BD7F250DE2}</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>{79C52444-6CA6-4417-BC6A-85DD2B63D65C}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{D5C7C2FC-CFB2-4B65-879D-EE3C6847D48D}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\filterum.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\filterum.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="filter.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/func/featured/power.c b/general/toaster/umdf2/func/featured/power.c new file mode 100644 index 00000000..60b5df78 --- /dev/null +++ b/general/toaster/umdf2/func/featured/power.c @@ -0,0 +1,385 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Power.C + +Abstract: + + Implements callbacks to manager power transition, wait-wake and selective + suspend. + +Environment: + + Kernel mode + +--*/ + +#include "toaster.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, ToasterEvtDeviceD0Exit) +#pragma alloc_text(PAGE, ToasterEvtDeviceArmWakeFromS0) +#pragma alloc_text(PAGE, ToasterEvtDeviceArmWakeFromSx) +#pragma alloc_text(PAGE, ToasterEvtDeviceWakeFromS0Triggered) +#pragma alloc_text(PAGE, DbgDevicePowerString) +#endif // ALLOC_PRAGMA + + +NTSTATUS +ToasterEvtDeviceD0Entry( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE RecentPowerState + ) +/*++ +Routine Description: + + EvtDeviceD0Entry event is called to program the device to goto + D0, which is the working state. The framework calls the driver's + EvtDeviceD0Entry callback when the Power manager sends an + IRP_MN_SET_POWER-DevicePower request to the driver stack. The Power manager + sends this request when the power policy manager of this device stack + (probaby the FDO) requests a change in D-state by calling PoRequestPowerIrp. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - handle to a framework device object. + + RecentPowerState - WDF_POWER_DEVICE_STATE-typed enumerator that identifies the + device power state that the device was in before this transition + to D0. + +Return Value: + + NTSTATUS - A failure here will indicate a fatal error in the driver. + The Framework will attempt to tear down the stack. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(RecentPowerState); + + KdPrint(("ToasterEvtDeviceD0Entry - coming from %s\n", + DbgDevicePowerString(RecentPowerState))); + + return STATUS_SUCCESS; +} + +NTSTATUS +ToasterEvtDeviceD0Exit( + IN WDFDEVICE Device, + IN WDF_POWER_DEVICE_STATE PowerState + ) +/*++ +Routine Description: + + EvtDeviceD0Entry event is called to program the device to goto + D1, D2 or D3, which are the low-power states. The framework calls the + driver's EvtDeviceD0Exit callback when the Power manager sends an + IRP_MN_SET_POWER-DevicePower request to the driver stack. The Power manager + sends this request when the power policy manager of this device stack + (probaby the FDO) requests a change in D-state by calling PoRequestPowerIrp. + +Arguments: + + Device - handle to a framework device object. + + DeviceState - WDF_POWER_DEVICE_STATE-typed enumerator that identifies the + device power state that the power policy owner (probably the + FDO) has decided is appropriate. + +Return Value: + + NTSTATUS - A failure here will indicate a fatal error in the driver. + The Framework will attempt to tear down the stack. +--*/ +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(PowerState); + + PAGED_CODE(); + + KdPrint(("ToasterEvtDeviceD0Exit %s\n", + DbgDevicePowerString(PowerState))); + + return STATUS_SUCCESS; +} + +NTSTATUS +ToasterEvtDeviceArmWakeFromS0( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceArmWakeFromS0 is called when the Framework arms the device for + wake from S0. If there is any device-specific initialization + that needs to be done to arm internal wake signals, or to route internal + interrupt signals to the wake logic, it should be done here. The device + will be moved out of the D0 state soon after this callback is invoked. + + This function is pageable and it will run at PASSIVE_LEVEL. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + NTSTATUS - Failure will result in the device remaining in the D0 state. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + PAGED_CODE(); + + KdPrint(( "--> ToasterEvtDeviceArmWakeFromS0\n")); + + KdPrint(( "<-- ToasterEvtDeviceArmWakeFromS0\n")); + + return STATUS_SUCCESS; +} + +NTSTATUS +ToasterEvtDeviceArmWakeFromSx( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceArmWakeFromSx is called when the Framework arms the device for + wake from Sx. If there is any device-specific initialization + that needs to be done to arm internal wake signals, or to route internal + interrupt signals to the wake logic, it should be done here. The device + will be moved out of the D0 state soon after this callback is invoked. + + This function is pageable and it will run at PASSIVE_LEVEL. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + NTSTATUS - Failure will result in the device remaining in the D0 state. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + PAGED_CODE(); + + KdPrint(( "--> ToasterEvtDeviceArmWakeFromSx\n")); + + KdPrint(( "<-- ToasterEvtDeviceArmWakeFromSx\n")); + + return STATUS_SUCCESS; +} + +VOID +ToasterEvtDeviceDisarmWakeFromS0( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceDisarmWakeFromS0 reverses anything done in EvtDeviceArmWakeFromS0. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + KdPrint(( "--> ToasterEvtDeviceDisarmWakeFromS0\n")); + + KdPrint(( "<-- ToasterEvtDeviceDisarmWakeFromS0\n")); + + return ; +} + +VOID +ToasterEvtDeviceDisarmWakeFromSx( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceDisarmWakeFromSx reverses anything done in EvtDeviceArmWakeFromSx. + + This function will run at PASSIVE_LEVEL. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + KdPrint(( "--> ToasterEvtDeviceDisarmWakeFromSx\n")); + + KdPrint(( "<-- ToasterEvtDeviceDisarmWakeFromSx\n")); + + return ; +} + +VOID +ToasterEvtDeviceWakeFromS0Triggered( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeFromS0Triggered will be called whenever the device triggers its + wake signal after being armed for wake. + + This function is pageable and runs at PASSIVE_LEVEL. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + PAGED_CODE(); + + KdPrint(( "--> ToasterEvtDeviceWakeFromS0Triggered\n")); + + + KdPrint(( "<-- ToasterEvtDeviceWakeFromS0Triggered\n")); + +} + +VOID +ToasterEvtDeviceWakeFromSxTriggered( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceWakeFromSxTriggered will be called whenever the device triggers its + wake signal after being armed for wake. + + This function runs at PASSIVE_LEVEL. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a Framework device object. + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + KdPrint(( "--> ToasterEvtDeviceWakeFromSxTriggered\n")); + + KdPrint(( "<-- ToasterEvtDeviceWakeFromSxTriggered\n")); + +} + +PCHAR +DbgDevicePowerString( + IN WDF_POWER_DEVICE_STATE Type + ) +/*++ + +New Routine Description: + DbgDevicePowerString converts the device power state code of a power IRP to a + text string that is helpful when tracing the execution of power IRPs. + +Parameters Description: + Type + Type specifies the device power state code of a power IRP. + +Return Value Description: + DbgDevicePowerString returns a pointer to a string that represents the + text description of the incoming device power state code. + +--*/ +{ + PAGED_CODE(); + + switch (Type) + { + case WdfPowerDeviceInvalid: + return "WdfPowerDeviceInvalid"; + case WdfPowerDeviceD0: + return "WdfPowerDeviceD0"; + case WdfPowerDeviceD1: + return "WdfPowerDeviceD1"; + case WdfPowerDeviceD2: + return "WdfPowerDeviceD2"; + case WdfPowerDeviceD3: + return "WdfPowerDeviceD3"; + case WdfPowerDeviceD3Final: + return "WdfPowerDeviceD3Final"; + case WdfPowerDevicePrepareForHibernation: + return "WdfPowerDevicePrepareForHibernation"; + case WdfPowerDeviceMaximum: + return "WdfPowerDeviceMaximum"; + default: + return "UnKnown Device Power State"; + } +} + + + + diff --git a/general/toaster/umdf2/func/featured/toaster.c b/general/toaster/umdf2/func/featured/toaster.c new file mode 100644 index 00000000..c25eebd4 --- /dev/null +++ b/general/toaster/umdf2/func/featured/toaster.c @@ -0,0 +1,862 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Toaster.c + +Abstract: + + This is a featured version of the toaster function driver. This version + shows how to register for PNP and Power events, handle create & close + file requests. + +Environment: + + Kernel mode + +--*/ + +#include "toaster.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, ToasterEvtDeviceAdd) +#pragma alloc_text (PAGE, ToasterEvtDeviceFileCreate) +#pragma alloc_text (PAGE, ToasterEvtFileClose) +#pragma alloc_text (PAGE, ToasterEvtDevicePrepareHardware) +#pragma alloc_text (PAGE, ToasterEvtDeviceReleaseHardware) +#pragma alloc_text (PAGE, ToasterEvtDeviceContextCleanup) +#pragma alloc_text (PAGE, ToasterEvtIoDeviceControl) +#pragma alloc_text (PAGE, ToasterEvtIoRead) +#pragma alloc_text (PAGE, ToasterEvtIoWrite) +#endif + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as ToasterAddDevice and ToasterUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + + KdPrint(("WDF Toaster Function Driver Sample - Featured version\n")); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + ToasterEvtDeviceAdd + ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + return status; +} + + +NTSTATUS +ToasterEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + ToasterEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of toaster device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_OBJECT_ATTRIBUTES fdoAttributes; + WDFDEVICE device; + WDF_FILEOBJECT_CONFIG fileConfig; + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; + WDF_POWER_POLICY_EVENT_CALLBACKS powerPolicyCallbacks; + WDF_IO_QUEUE_CONFIG queueConfig; + //PFDO_DATA fdoData; + WDFQUEUE queue; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + KdPrint(("ToasterEvtDeviceAdd called\n")); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + + // + // Register PNP callbacks. + // + pnpPowerCallbacks.EvtDevicePrepareHardware = ToasterEvtDevicePrepareHardware; + pnpPowerCallbacks.EvtDeviceReleaseHardware = ToasterEvtDeviceReleaseHardware; + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = ToasterEvtDeviceSelfManagedIoInit; + + // + // Register Power callbacks. + // + pnpPowerCallbacks.EvtDeviceD0Entry = ToasterEvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = ToasterEvtDeviceD0Exit; + + + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // + // Register power policy event callbacks so that we would know when to + // arm/disarm the hardware to handle wait-wake and when the wake event + // is triggered by the hardware. + // + WDF_POWER_POLICY_EVENT_CALLBACKS_INIT(&powerPolicyCallbacks); + + // + // This group of three callbacks allows this sample driver to manage + // arming the device for wake from the S0 or Sx state. We don't really + // differentiate between S0 and Sx state.. + // + powerPolicyCallbacks.EvtDeviceArmWakeFromS0 = ToasterEvtDeviceArmWakeFromS0; + powerPolicyCallbacks.EvtDeviceDisarmWakeFromS0 = ToasterEvtDeviceDisarmWakeFromS0; + powerPolicyCallbacks.EvtDeviceWakeFromS0Triggered = ToasterEvtDeviceWakeFromS0Triggered; + powerPolicyCallbacks.EvtDeviceArmWakeFromSx = ToasterEvtDeviceArmWakeFromSx; + powerPolicyCallbacks.EvtDeviceDisarmWakeFromSx = ToasterEvtDeviceDisarmWakeFromSx; + powerPolicyCallbacks.EvtDeviceWakeFromSxTriggered = ToasterEvtDeviceWakeFromSxTriggered; + + // + // Register the power policy callbacks. + // + WdfDeviceInitSetPowerPolicyEventCallbacks(DeviceInit, &powerPolicyCallbacks); + + // + // Initialize WDF_FILEOBJECT_CONFIG_INIT struct to tell the + // framework whether you are interested in handling Create, Close and + // Cleanup requests that gets genereate when an application or another + // kernel component opens an handle to the device. If you don't register, + // the framework default behaviour would be complete these requests + // with STATUS_SUCCESS. A driver might be interested in registering these + // events if it wants to do security validation and also wants to maintain + // per handle (fileobject) context. + // + + WDF_FILEOBJECT_CONFIG_INIT( + &fileConfig, + ToasterEvtDeviceFileCreate, + ToasterEvtFileClose, + WDF_NO_EVENT_CALLBACK // not interested in Cleanup + ); + + WdfDeviceInitSetFileObjectConfig(DeviceInit, + &fileConfig, + WDF_NO_OBJECT_ATTRIBUTES); + + // + // Now specify the size of device extension where we track per device + // context. Along with setting the context type as shown below, you should also + // specify the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME in header to specify the + // accessor function name. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); + + // + // Set a context cleanup routine to cleanup any resources that are not + // parent to this device. This cleanup will be called in the context of + // pnp remove-device when the framework deletes the device object. + // + fdoAttributes.EvtCleanupCallback = ToasterEvtDeviceContextCleanup; + + // + // DeviceInit is completely initialized. So call the framework to create the + // device and attach it to the lower stack. + // + status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &device); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDeviceCreate failed with Status code 0x%x\n", status)); + return status; + } + + // + // Get the device context by using accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for FDO_DATA. + // + //fdoData = ToasterFdoGetData(device); + + // + // Tell the Framework that this device will need an interface so that + // application can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface( + device, + (LPGUID) &GUID_DEVINTERFACE_TOASTER, + NULL + ); + + if (!NT_SUCCESS (status)) { + KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); + return status; + } + + // + // Register I/O callbacks to tell the framework that you are interested + // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. + // In case a specific handler is not specified for one of these, + // the request will be dispatched to the EvtIoDefault handler, if any. + // If there is no EvtIoDefault handler, the request will be failed with + // STATUS_INVALID_DEVICE_REQUEST. + // WdfIoQueueDispatchParallel means that we are capable of handling + // all the I/O request simultaneously and we are responsible for protecting + // data that could be accessed by these callbacks simultaneously. + // A default queue gets all the requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, + WdfIoQueueDispatchParallel); // EvtIoCancel + + queueConfig.EvtIoRead = ToasterEvtIoRead; + queueConfig.EvtIoWrite = ToasterEvtIoWrite; + queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate(device, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue + ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS (status)) { + + KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + // + // Set the idle power policy to put the device to Dx if the device is not used + // for the specified IdleTimeout time. Since this is a virtual device we + // tell the framework that we cannot wake ourself if we sleep in S0. Only + // way the device can be brought to D0 is if the device recieves an I/O from + // the system. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0); + idleSettings.IdleTimeout = 60000; // 60 secs idle timeout + status = WdfDeviceAssignS0IdleSettings(device, &idleSettings); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDeviceAssignS0IdleSettings failed 0x%x\n", status)); + return status; + } + + // + // Set the wait-wake policy. + // + + WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); + status = WdfDeviceAssignSxWakeSettings(device, &wakeSettings); + if (!NT_SUCCESS(status)) { + // + // We are probably enumerated on a bus that doesn't support Sx-wake. + // Let us not fail the device add just because we aren't able to support + // wait-wake. I will let the user of this sample decide how important it's + // to support wait-wake for their hardware and return appropriate status. + // + KdPrint( ("WdfDeviceAssignSxWakeSettings failed 0x%x\n", status)); + status = STATUS_SUCCESS; + } + + return status; +} + +NTSTATUS +ToasterEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourcesRaw, + WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDevicePrepareHardware event callback performs operations that are + necessary to make the driver's device operational. The framework calls the + driver's EvtDevicePrepareHardware callback when the PnP manager sends an + IRP_MN_START_DEVICE request to the driver stack. + + Specifically, most drivers will use this callback to map resources. USB + drivers may use it to get device descriptors, config descriptors and to + select configs. + + Some drivers may choose to download firmware to a device in this callback, + but that is usually only a good choice if the device firmware won't be + destroyed by a D0 to D3 transition. If firmware will be gone after D3, + then firmware downloads should be done in EvtDeviceD0Entry, not here. + +Arguments: + + Device - Handle to a framework device object. + + ResourcesRaw - Handle to a collection of framework resource objects. + This collection identifies the raw (bus-relative) hardware + resources that have been assigned to the device. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + WDF status code + +--*/ +{ + //PFDO_DATA fdoData; + NTSTATUS status = STATUS_SUCCESS; + ULONG i; + PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; + + //fdoData = ToasterFdoGetData(Device); + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(ResourcesRaw); + + KdPrint(("ToasterEvtDevicePrepareHardware called\n")); + + PAGED_CODE(); + // + // Get the number item that are currently in Resources collection and + // iterate thru as many times to get more information about the each items + // + for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { + + descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); + + switch(descriptor->Type) { + + case CmResourceTypePort: + + KdPrint(("I/O Port: (%x) Length: (%d)\n", + descriptor->u.Port.Start.LowPart, + descriptor->u.Port.Length)); + break; + + case CmResourceTypeMemory: + + KdPrint(("Memory: (%x) Length: (%d)\n", + descriptor->u.Memory.Start.LowPart, + descriptor->u.Memory.Length)); + break; + case CmResourceTypeInterrupt: + + KdPrint(("Interrupt level: 0x%0x, Vector: 0x%0x, Affinity: 0x%0Ix\n", + descriptor->u.Interrupt.Level, + descriptor->u.Interrupt.Vector, + descriptor->u.Interrupt.Affinity)); + break; + + default: + break; + } + + } + + return status; + +} + +NTSTATUS +ToasterEvtDeviceReleaseHardware( + IN WDFDEVICE Device, + IN WDFCMRESLIST ResourcesTranslated + ) +/*++ + +Routine Description: + + EvtDeviceReleaseHardware is called by the framework whenever the PnP manager + is revoking ownership of our resources. This may be in response to either + IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before + passing down the IRP to the lower driver. + + In this callback, do anything necessary to free those resources. + +Arguments: + + Device - Handle to a framework device object. + + ResourcesTranslated - Handle to a collection of framework resource objects. + This collection identifies the translated (system-physical) + hardware resources that have been assigned to the device. + The resources appear from the CPU's point of view. + Use this list of resources to map I/O space and + device-accessible memory into virtual address space + +Return Value: + + NTSTATUS - Failures will be logged, but not acted on. + +--*/ +{ + //PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(ResourcesTranslated); + + KdPrint(("ToasterEvtDeviceReleaseHardware called\n")); + + PAGED_CODE(); + + //fdoData = ToasterFdoGetData(Device); + // + // Unmap any I/O ports, registers that you mapped in PrepareHardware. + // Disconnecting from the interrupt will be done automatically by the framework. + // + return STATUS_SUCCESS; +} + +NTSTATUS +ToasterEvtDeviceSelfManagedIoInit( + IN WDFDEVICE Device + ) +/*++ + +Routine Description: + + EvtDeviceSelfManagedIoInit is called it once for each device, + after the framework has called the driver's EvtDeviceD0Entry + callback function for the first time. The framework does not + call the EvtDeviceSelfManagedIoInit callback function again for + that device, unless the device is removed and reconnected, or + the drivers are reloaded. + + The EvtDeviceSelfManagedIoInit callback function must initialize + the self-managed I/O operations that the driver will handle + for the device. + + This function is not marked pageable because this function is in the + device power up path. When a function is marked pagable and the code + section is paged out, it will generate a page fault which could impact + the fast resume behavior because the client driver will have to wait + until the system drivers can service this page fault. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + NTSTATUS - Failures will result in the device stack being torn down. + +--*/ +{ + UNREFERENCED_PARAMETER(Device); + + KdPrint(("ToasterEvtDeviceSelfManagedIoInit called\n")); + + return STATUS_SUCCESS; +} + + +VOID +ToasterEvtDeviceContextCleanup( + IN WDFOBJECT Device + ) +/*++ + +Routine Description: + + EvtDeviceContextCleanup event callback must perform any operations that are + necessary before the specified device is removed. The framework calls + the driver's EvtDeviceContextCleanup callback when the device is deleted in response + to IRP_MN_REMOVE_DEVICE request. + +Arguments: + + Device - Handle to a framework device object. + +Return Value: + + None + +--*/ +{ + //PFDO_DATA fdoData; + UNREFERENCED_PARAMETER(Device); + KdPrint( ("ToasterEvtDeviceContextCleanup called\n")); + + PAGED_CODE(); + + //fdoData = ToasterFdoGetData((WDFDEVICE)Device); + + return; +} + +VOID +ToasterEvtDeviceFileCreate ( + IN WDFDEVICE Device, + IN WDFREQUEST Request, + IN WDFFILEOBJECT FileObject + ) +/*++ + +Routine Description: + + The framework calls a driver's EvtDeviceFileCreate callback + when the framework receives an IRP_MJ_CREATE request. + The system sends this request when a user application opens the + device to perform an I/O operation, such as reading or writing to a device. + This callback is called in the context of the thread + that created the IRP_MJ_CREATE request. + +Arguments: + + Device - Handle to a framework device object. + FileObject - Pointer to fileobject that represents the open handle. + CreateParams - Parameters for create + +Return Value: + + None + +--*/ +{ + //PFDO_DATA fdoData; + + UNREFERENCED_PARAMETER(FileObject); + UNREFERENCED_PARAMETER(Device); + + KdPrint( ("ToasterEvtDeviceFileCreate %p\n", Device)); + + PAGED_CODE (); + + // + // Get the device context given the device handle. + // + //fdoData = ToasterFdoGetData(Device); + + WdfRequestComplete(Request, STATUS_SUCCESS); + + return; +} + + +VOID +ToasterEvtFileClose ( + IN WDFFILEOBJECT FileObject + ) + +/*++ + +Routine Description: + + EvtFileClose is called when all the handles represented by the FileObject + is closed and all the references to FileObject is removed. This callback + may get called in an arbitrary thread context instead of the thread that + called CloseHandle. If you want to delete any per FileObject context that + must be done in the context of the user thread that made the Create call, + you should do that in the EvtDeviceCleanp callback. + +Arguments: + + FileObject - Pointer to fileobject that represents the open handle. + +Return Value: + + None + +--*/ +{ + //PFDO_DATA fdoData; + UNREFERENCED_PARAMETER(FileObject); + PAGED_CODE (); + + //fdoData = ToasterFdoGetData(WdfFileObjectGetDevice(FileObject)); + + KdPrint( ("ToasterEvtFileClose\n")); + + return; +} + + + +VOID +ToasterEvtIoRead ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length + ) +/*++ + +Routine Description: + + Performs read to the toaster device. This event is called when the + framework receives IRP_MJ_READ requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + None + +--*/ +{ + NTSTATUS status; + ULONG_PTR bytesCopied =0; + WDFMEMORY memory; + + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(Queue); + + PAGED_CODE(); + + KdPrint(("ToasterEvtIoRead: Request: 0x%p, Queue: 0x%p\n", + Request, Queue)); + + // + // Get the request memory and perform read operation here + // + status = WdfRequestRetrieveOutputMemory(Request, &memory); + if(NT_SUCCESS(status) ) { + // + // Copy data into the memory buffer using WdfMemoryCopyFromBuffer + // + } + + WdfRequestCompleteWithInformation(Request, status, bytesCopied); + +} + +VOID +ToasterEvtIoWrite ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length + ) +/*++ + +Routine Description: + + Performs write to the toaster device. This event is called when the + framework receives IRP_MJ_WRITE requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + None + +--*/ + +{ + NTSTATUS status; + WDFMEMORY memory; + + UNREFERENCED_PARAMETER(Queue); + + KdPrint(("ToasterEvtIoWrite. Request: 0x%p, Queue: 0x%p\n", + Request, Queue)); + PAGED_CODE(); + + // + // Get the request buffer and perform write operation here + // + status = WdfRequestRetrieveInputMemory(Request, &memory); + if(NT_SUCCESS(status) ) { + // + // 1) Use WdfMemoryCopyToBuffer to copy data from the request + // to driver buffer. + // 2) Or get the buffer pointer from the request by calling + // WdfRequestRetrieveInputBuffer to transfer data to the hw + // 3) Or you can get the buffer pointer from the memory handle + // by calling WdfMemoryGetBuffer to transfer data to the hw. + // + } + + WdfRequestCompleteWithInformation(Request, status, Length); + +} + + +VOID +ToasterEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + None + +--*/ +{ + NTSTATUS status= STATUS_SUCCESS; + WDF_DEVICE_STATE deviceState; + WDFDEVICE hDevice = WdfIoQueueGetDevice(Queue); + + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + KdPrint(("ToasterEvtIoDeviceControl called\n")); + + PAGED_CODE(); + + switch (IoControlCode) { + + case IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE: + // + // This is just an example on how to hide your device in the + // device manager. Please remove this code when you adapt + // this sample for your hardware. + // + WDF_DEVICE_STATE_INIT(&deviceState); + deviceState.DontDisplayInUI = WdfTrue; + WdfDeviceSetDeviceState( + hDevice, + &deviceState + ); + break; + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Complete the Request. + // + WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR) 0); + +} + + diff --git a/general/toaster/umdf2/func/featured/toaster.rc b/general/toaster/umdf2/func/featured/toaster.rc new file mode 100644 index 00000000..e9ba2ea8 --- /dev/null +++ b/general/toaster/umdf2/func/featured/toaster.rc @@ -0,0 +1,12 @@ +#include <windows.h> + +#include <ntverp.h> + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF UMDF2 Toaster Device Driver" +#define VER_INTERNALNAME_STR "wdftoaster.dll" +#define VER_ORIGINALFILENAME_STR "wdftoaster.dll" + +#include "common.ver" + diff --git a/general/toaster/umdf2/func/featured/wdffeaturedum.inx b/general/toaster/umdf2/func/featured/wdffeaturedum.inx new file mode 100644 index 00000000..feae7a33 --- /dev/null +++ b/general/toaster/umdf2/func/featured/wdffeaturedum.inx @@ -0,0 +1,98 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +;Module Name: +; wdffeatured.INF +; +;Abstract: +; INF file for installing the UMDF2 Toaster Driver +; +;Installation Notes: +; Using Devcon: Type "devcon install wdffeaturedum.inf root\toaster" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=TOASTER +ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=wudf.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=ToasterClassReg + +[ToasterClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,100 +HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. + ;This one overrides the security set by the driver + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +wdffeaturedum.dll = 1,, + +;***************************************** +; Toaster Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +; +; Hw Id is root\toaster +; +[Standard.NT$ARCH$] +%Toaster.DeviceDesc%=Toaster_Device, root\toaster + +;---------------- copy files + +[Toaster_Device.NT] +CopyFiles=UMDriverCopy + +[UMDriverCopy] +wdffeaturedum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\umdf + +;-------------- Service installation +[Toaster_Device.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +;-------------- WDF specific section ------------- +[Toaster_Device.NT.Wdf] +UmdfService=wdffeaturedum, Toaster_Install +UmdfServiceOrder=wdffeaturedum + +[Toaster_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\wdffeaturedum.dll + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample Toaster Installation Disk #1" +Toaster.DeviceDesc = "Sample UMDF Toaster Driver - featured" +Toaster.SVCDESC = "Sample WDF Toaster Service" +ClassName = "Toaster" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" + diff --git a/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj new file mode 100644 index 00000000..1af04c81 --- /dev/null +++ b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{99A6009E-6137-462F-89C4-6931045895B1}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{3E5FB5B1-CA59-4675-AAF8-93039F74CF02}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\wdffeaturedum.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\wdffeaturedum.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>wdffeaturedum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>wdffeaturedum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>wdffeaturedum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>wdffeaturedum</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="power.c" /> + <ClCompile Include="toaster.c" /> + <ResourceCompile Include="toaster.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters new file mode 100644 index 00000000..ad344822 --- /dev/null +++ b/general/toaster/umdf2/func/featured/wdffeaturedum.vcxproj.Filters @@ -0,0 +1,42 @@ +<?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>{180B07F2-6C79-44F0-9765-749A2975BA1F}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{025585BB-48DE-4F3B-A929-D58821892D58}</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>{A90CE102-D7E8-46E0-B8D8-D1A57A6CDE82}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{20EB3DBD-A818-46EE-A8B4-6A507F202B60}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\wdffeaturedum.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\wdffeaturedum.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="power.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="toaster.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="toaster.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/func/shared/toaster.h b/general/toaster/umdf2/func/shared/toaster.h new file mode 100644 index 00000000..006166e7 --- /dev/null +++ b/general/toaster/umdf2/func/shared/toaster.h @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + Toaster.h + +Abstract: + + Header file for the toaster driver modules. + +Environment: + + User mode + +--*/ + + +#if !defined(_TOASTER_H_) +#define _TOASTER_H_ + +#include <windows.h> +#include <winioctl.h> +#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union +#include <ntstatus.h> +#include <devpropdef.h> +#include <wudfwdm.h> +#include <wdf.h> +#include <initguid.h> +#include "..\inc\driver.h" +#include "..\inc\public.h" + +#define TOASTER_POOL_TAG (ULONG) 'saoT' + +// +// The device extension for the device object +// +typedef struct _FDO_DATA +{ + + WDFWMIINSTANCE WmiDeviceArrivalEvent; + + BOOLEAN WmiPowerDeviceEnableRegistered; + +} FDO_DATA, *PFDO_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, ToasterFdoGetData) + + +// +// Connector Types +// + +#define TOASTER_WMI_STD_I8042 0 +#define TOASTER_WMI_STD_SERIAL 1 +#define TOASTER_WMI_STD_PARALEL 2 +#define TOASTER_WMI_STD_USB 3 + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD ToasterEvtDeviceAdd; + +EVT_WDF_DEVICE_CONTEXT_CLEANUP ToasterEvtDeviceContextCleanup; +EVT_WDF_DEVICE_D0_ENTRY ToasterEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT ToasterEvtDeviceD0Exit; +EVT_WDF_DEVICE_PREPARE_HARDWARE ToasterEvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE ToasterEvtDeviceReleaseHardware; + +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT ToasterEvtDeviceSelfManagedIoInit; + +// +// Io events callbacks. +// +EVT_WDF_IO_QUEUE_IO_READ ToasterEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE ToasterEvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL ToasterEvtIoDeviceControl; +EVT_WDF_DEVICE_FILE_CREATE ToasterEvtDeviceFileCreate; +EVT_WDF_FILE_CLOSE ToasterEvtFileClose; + +NTSTATUS +ToasterWmiRegistration( + _In_ WDFDEVICE Device + ); + +// +// Power events callbacks +// +EVT_WDF_DEVICE_ARM_WAKE_FROM_S0 ToasterEvtDeviceArmWakeFromS0; +EVT_WDF_DEVICE_ARM_WAKE_FROM_SX ToasterEvtDeviceArmWakeFromSx; +EVT_WDF_DEVICE_DISARM_WAKE_FROM_S0 ToasterEvtDeviceDisarmWakeFromS0; +EVT_WDF_DEVICE_DISARM_WAKE_FROM_SX ToasterEvtDeviceDisarmWakeFromSx; +EVT_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED ToasterEvtDeviceWakeFromS0Triggered; +EVT_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED ToasterEvtDeviceWakeFromSxTriggered; + +PCHAR +DbgDevicePowerString( + IN WDF_POWER_DEVICE_STATE Type + ); + +// +// WMI event callbacks +// +EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceStdDeviceDataQueryInstance; +EVT_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceToasterControlQueryInstance; +EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceStdDeviceDataSetInstance; +EVT_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceToasterControlSetInstance; +EVT_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceToasterControlSetItem; +EVT_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceStdDeviceDataSetItem; +EVT_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceToasterControlExecuteMethod; + +NTSTATUS +ToasterFireArrivalEvent( + _In_ WDFDEVICE Device + ); + +#endif // _TOASTER_H_ + diff --git a/general/toaster/umdf2/func/simple/toaster.c b/general/toaster/umdf2/func/simple/toaster.c new file mode 100644 index 00000000..6ed215db --- /dev/null +++ b/general/toaster/umdf2/func/simple/toaster.c @@ -0,0 +1,418 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Toaster.c + +Abstract: + + This is a simple form of function driver for toaster device. The driver + doesn't handle any PnP and Power events because the framework provides + default behavior for those events. This driver has enough support to + allow an user application (toast/notify.exe) to open the device + interface registered by the driver and send read, write or ioctl requests. + +Environment: + + Kernel mode + +--*/ + +#include "toaster.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, ToasterEvtDeviceAdd) +#pragma alloc_text (PAGE, ToasterEvtIoRead) +#pragma alloc_text (PAGE, ToasterEvtIoWrite) +#pragma alloc_text (PAGE, ToasterEvtIoDeviceControl) +#endif + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry configures and creates a WDF driver + object. + . +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_DRIVER_CONFIG config; + + KdPrint(("Toaster Function Driver Sample - Driver Framework Edition.\n")); + + // + // Initiialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If DriverEntry creates any resources + // that require clean-up in driver unload, + // you can manually override the default by supplying a pointer to the EvtDriverUnload + // callback in the config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + ToasterEvtDeviceAdd + ); + + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate( + DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, // Driver Attributes + &config, // Driver Config Info + WDF_NO_HANDLE + ); + + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDriverCreate failed with status 0x%x\n", status)); + } + + return status; +} + + +NTSTATUS +ToasterEvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + ToasterEvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a WDF device object to + represent a new instance of toaster device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PFDO_DATA fdoData; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES fdoAttributes; + WDFDEVICE hDevice; + WDFQUEUE queue; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + KdPrint(("ToasterEvtDeviceAdd called\n")); + + // + // Initialize attributes and a context area for the device object. + // + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, FDO_DATA); + + // + // Create a framework device object.This call will in turn create + // a WDM device object, attach to the lower stack, and set the + // appropriate flags and attributes. + // + status = WdfDeviceCreate(&DeviceInit, &fdoAttributes, &hDevice); + if (!NT_SUCCESS(status)) { + KdPrint( ("WdfDeviceCreate failed with status code 0x%x\n", status)); + return status; + } + + // + // Get the device context by using the accessor function specified in + // the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for FDO_DATA. + // + fdoData = ToasterFdoGetData(hDevice); + + // + // Tell the Framework that this device will need an interface + // + status = WdfDeviceCreateDeviceInterface( + hDevice, + (LPGUID) &GUID_DEVINTERFACE_TOASTER, + NULL // ReferenceString + ); + + if (!NT_SUCCESS (status)) { + KdPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); + return status; + } + + // + // Register I/O callbacks to tell the framework that you are interested + // in handling IRP_MJ_READ, IRP_MJ_WRITE, and IRP_MJ_DEVICE_CONTROL requests. + // If a specific callback function is not specified for one ofthese, + // the request will be dispatched to the EvtIoDefault handler, if any. + // If there is no EvtIoDefault handler, the request will be failed with + // STATUS_INVALID_DEVICE_REQUEST. + // WdfIoQueueDispatchParallel means that we are capable of handling + // all the I/O requests simultaneously and we are responsible for protecting + // data that could be accessed by these callbacks simultaneously. + // A default queue gets all the requests that are not + // configured for forwarding using WdfDeviceConfigureRequestDispatching. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchParallel); + + queueConfig.EvtIoRead = ToasterEvtIoRead; + queueConfig.EvtIoWrite = ToasterEvtIoWrite; + queueConfig.EvtIoDeviceControl = ToasterEvtIoDeviceControl; + + // + // By default, Static Driver Verifier (SDV) displays a warning if it + // doesn't find the EvtIoStop callback on a power-managed queue. + // The 'assume' below causes SDV to suppress this warning. If the driver + // has not explicitly set PowerManaged to WdfFalse, the framework creates + // power-managed queues when the device is not a filter driver. Normally + // the EvtIoStop is required for power-managed queues, but for this driver + // it is not needed b/c the driver doesn't hold on to the requests or + // forward them to other drivers. This driver completes the requests + // directly in the queue's handlers. If the EvtIoStop callback is not + // implemented, the framework waits for all driver-owned requests to be + // done before moving in the Dx/sleep states or before removing the + // device, which is the correct behavior for this type of driver. + // If the requests were taking an indeterminate amount of time to complete, + // or if the driver forwarded the requests to a lower driver/another stack, + // the queue should have an EvtIoStop/EvtIoResume. + // + __analysis_assume(queueConfig.EvtIoStop != 0); + status = WdfIoQueueCreate( + hDevice, + &queueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue + ); + __analysis_assume(queueConfig.EvtIoStop == 0); + + if (!NT_SUCCESS (status)) { + + KdPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + return status; +} + +VOID +ToasterEvtIoRead ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length + ) +/*++ + +Routine Description: + + Performs read from the toaster device. This event is called when the + framework receives IRP_MJ_READ requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Lenght - Length of the data buffer associated with the request. + By default, the queue does not dispatch + zero length read & write requests to the driver and instead to + complete such requests with status success. So we will never get + a zero length request. + +Return Value: + + None. + +--*/ +{ + NTSTATUS status; + ULONG_PTR bytesCopied =0; + WDFMEMORY memory; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(Length); + + PAGED_CODE(); + + KdPrint(( "ToasterEvtIoRead: Request: 0x%p, Queue: 0x%p\n", + Request, Queue)); + + // + // Get the request memory and perform read operation here + // + status = WdfRequestRetrieveOutputMemory(Request, &memory); + if(NT_SUCCESS(status) ) { + // + // Copy data into the memory buffer using WdfMemoryCopyFromBuffer + // + } + + WdfRequestCompleteWithInformation(Request, status, bytesCopied); +} + +VOID +ToasterEvtIoWrite ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length + ) +/*++ + +Routine Description: + + Performs write to the toaster device. This event is called when the + framework receives IRP_MJ_WRITE requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated with the + I/O request. + Request - Handle to a framework request object. + + Lenght - Length of the data buffer associated with the request. + The default property of the queue is to not dispatch + zero lenght read & write requests to the driver and + complete is with status success. So we will never get + a zero length request. + +Return Value: + + None +--*/ + +{ + NTSTATUS status; + ULONG_PTR bytesWritten =0; + WDFMEMORY memory; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(Length); + + KdPrint(("ToasterEvtIoWrite. Request: 0x%p, Queue: 0x%p\n", + Request, Queue)); + + PAGED_CODE(); + + // + // Get the request buffer and perform write operation here + // + status = WdfRequestRetrieveInputMemory(Request, &memory); + if(NT_SUCCESS(status) ) { + // + // 1) Use WdfMemoryCopyToBuffer to copy data from the request + // to driver buffer. + // 2) Or get the buffer pointer from the request by calling + // WdfRequestRetrieveInputBuffer + // 3) Or you can get the buffer pointer from the memory handle + // by calling WdfMemoryGetBuffer. + // + bytesWritten = Length; + } + + WdfRequestCompleteWithInformation(Request, status, bytesWritten); + +} + + +VOID +ToasterEvtIoDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ +Routine Description: + + This event is called when the framework receives IRP_MJ_DEVICE_CONTROL + requests from the system. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status= STATUS_SUCCESS; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + KdPrint(("ToasterEvtIoDeviceControl called\n")); + + PAGED_CODE(); + + // + // Use WdfRequestRetrieveInputBuffer and WdfRequestRetrieveOutputBuffer + // to get the request buffers. + // + + switch (IoControlCode) { + + default: + status = STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Complete the Request. + // + WdfRequestCompleteWithInformation(Request, status, (ULONG_PTR) 0); +} + + diff --git a/general/toaster/umdf2/func/simple/wdfsimpleum.inx b/general/toaster/umdf2/func/simple/wdfsimpleum.inx new file mode 100644 index 00000000..6edb9388 --- /dev/null +++ b/general/toaster/umdf2/func/simple/wdfsimpleum.inx @@ -0,0 +1,97 @@ +;/*++ +; +;Copyright (c) Microsoft Corporation. All rights reserved. +; +;Module Name: +; wdfsimpleum.INF +; +;Abstract: +; INF file for installing the UMDF2 Toaster Driver +; +;Installation Notes: +; Using Devcon: Type "devcon install wdfsimpleum.inf root\toaster" to install +; +;--*/ + +[Version] +Signature="$WINDOWS NT$" +Class=TOASTER +ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171} +Provider=%MSFT% +DriverVer=03/20/2003,5.00.3788 +CatalogFile=wudf.cat + +[DestinationDirs] +DefaultDestDir = 12 + +; ================= Class section ===================== + +[ClassInstall32] +Addreg=ToasterClassReg + +[ToasterClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,100 +HKR,,DeviceCharacteristics,0x10001,0x100 ;Use same security checks on relative opens +HKR,,Security,,"D:P(A;;GA;;;SY)(A;;GA;;;BA)" ;Allow generic all access to system and built-in Admin. + ;This one overrides the security set by the driver + +[SourceDisksNames] +1 = %DiskId1%,,,"" + +[SourceDisksFiles] +wdfsimpleum.dll = 1,, + +;***************************************** +; Toaster Install Section +;***************************************** + +[Manufacturer] +%StdMfg%=Standard,NT$ARCH$ + +; +; Hw Id is root\toaster +; +[Standard.NT$ARCH$] +%Toaster.DeviceDesc%=Toaster_Device, root\toaster + +;---------------- copy files + +[Toaster_Device.NT] +CopyFiles=UMDriverCopy + +[UMDriverCopy] +wdfsimpleum.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers\umdf + +;-------------- Service installation +[Toaster_Device.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +;-------------- WDF specific section ------------- +[Toaster_Device.NT.Wdf] +UmdfService=wdfsimpleum, Toaster_Install +UmdfServiceOrder=wdfsimpleum + +[Toaster_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\wdfsimpleum.dll + +[Strings] +SPSVCINST_ASSOCSERVICE= 0x00000002 +MSFT = "Microsoft" +StdMfg = "(Standard system devices)" +DiskId1 = "WDF Sample Toaster Installation Disk #1" +Toaster.DeviceDesc = "Sample UMDF Toaster Driver - simple" +ClassName = "Toaster" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" + diff --git a/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj new file mode 100644 index 00000000..5420719a --- /dev/null +++ b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj @@ -0,0 +1,180 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{4867F54B-D8EF-45B0-984E-D571D987174A}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>2</UMDF_VERSION_MAJOR> + <SupportsPackaging>false</SupportsPackaging> + <RequiresPackageProject>true</RequiresPackageProject> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{04436AEB-A589-41DD-A088-A1503096D2D8}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Universal</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <Inf Include=".\wdfsimpleum.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\wdfsimpleum.inf</CopyOutput> + </Inf> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>wdfsimpleum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>wdfsimpleum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>wdfsimpleum</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>wdfsimpleum</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\mincore.lib</AdditionalDependencies> + </Link> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);..\..\inc;..\shared</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="toaster.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters new file mode 100644 index 00000000..6054e358 --- /dev/null +++ b/general/toaster/umdf2/func/simple/wdfsimpleum.vcxproj.Filters @@ -0,0 +1,34 @@ +<?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>{00F8EE65-92A7-4127-B44C-E8F26A2136D5}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{77C5B494-74A7-4FE1-97B8-0B859BE75D43}</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>{9769E294-A7B6-4585-9CA6-AFDEA3DCA9F4}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{18744B3D-F47A-476E-9BF7-FE6592698961}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\wdfsimpleum.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include=".\wdfsimpleum.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="toaster.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/toaster/umdf2/inc/driver.h b/general/toaster/umdf2/inc/driver.h new file mode 100644 index 00000000..b1073363 --- /dev/null +++ b/general/toaster/umdf2/inc/driver.h @@ -0,0 +1,69 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + driver.h + +Abstract: + + This module contains the common declarations for the + bus, function and filter drivers. + +Environment: + + kernel mode only + +--*/ + +//#include "public.h" + +// +// Define an Interface Guid to access the proprietary toaster interface. +// This guid is used to identify a specific interface in IRP_MN_QUERY_INTERFACE +// handler. +// + +DEFINE_GUID(GUID_TOASTER_INTERFACE_STANDARD, + 0xe0b27630, 0x5434, 0x11d3, 0xb8, 0x90, 0x0, 0xc0, 0x4f, 0xad, 0x51, 0x71); +// {E0B27630-5434-11d3-B890-00C04FAD5171} + + +// +// GUID definition are required to be outside of header inclusion pragma to avoid +// error during precompiled headers. +// + +#ifndef __DRIVER_H +#define __DRIVER_H + +// +// Define Interface reference/dereference routines for +// Interfaces exported by IRP_MN_QUERY_INTERFACE +// + +typedef VOID (*PINTERFACE_REFERENCE)(PVOID Context); +typedef VOID (*PINTERFACE_DEREFERENCE)(PVOID Context); + +typedef +BOOLEAN +(*PTOASTER_GET_CRISPINESS_LEVEL)( + IN PVOID Context, + OUT PUCHAR Level + ); + +typedef +BOOLEAN +(*PTOASTER_SET_CRISPINESS_LEVEL)( + IN PVOID Context, + OUT UCHAR Level + ); + +typedef +BOOLEAN +(*PTOASTER_IS_CHILD_PROTECTED)( + IN PVOID Context + ); + +#endif + diff --git a/general/toaster/umdf2/inc/public.h b/general/toaster/umdf2/inc/public.h new file mode 100644 index 00000000..0628f95f --- /dev/null +++ b/general/toaster/umdf2/inc/public.h @@ -0,0 +1,167 @@ +/*++ +Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved + +Module Name: + + public.h + +Abstract: + + This module contains the common declarations shared by driver + and user applications. + +Environment: + + user and kernel + +--*/ + +// +// Define an Interface Guid for bus enumerator class. +// This GUID is used to register (IoRegisterDeviceInterface) +// an instance of an interface so that enumerator application +// can send an ioctl to the bus driver. +// + +DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER, + 0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); +// {D35F7840-6A0C-11d2-B841-00C04FAD5171} + +// +// Define an Interface Guid for toaster device class. +// This GUID is used to register (IoRegisterDeviceInterface) +// an instance of an interface so that user application +// can control the toaster device. +// + +DEFINE_GUID (GUID_DEVINTERFACE_TOASTER, + 0x781EF630, 0x72B2, 0x11d2, 0xB8, 0x52, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); +//{781EF630-72B2-11d2-B852-00C04FAD5171} + +// +// Define a Setup Class GUID for Toaster Class. This is same +// as the TOASTSER CLASS guid in the INF files. +// + +DEFINE_GUID (GUID_DEVCLASS_TOASTER, + 0xB85B7C50, 0x6A01, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); +//{B85B7C50-6A01-11d2-B841-00C04FAD5171} + +// +// Define a WMI GUID to get busenum info. +// + +DEFINE_GUID (TOASTER_BUS_WMI_STD_DATA_GUID, + 0x0006A660, 0x8F12, 0x11d2, 0xB8, 0x54, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); +//{0006A660-8F12-11d2-B854-00C04FAD5171} + +// +// Define a WMI GUID to get toaster device info. +// + +DEFINE_GUID (TOASTER_WMI_STD_DATA_GUID, + 0xBBA21300L, 0x6DD3, 0x11d2, 0xB8, 0x44, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71); + +// +// Define a WMI GUID to represent device arrival notification WMIEvent class. +// + +DEFINE_GUID (TOASTER_NOTIFY_DEVICE_ARRIVAL_EVENT, + 0x1cdaff1, 0xc901, 0x45b4, 0xb3, 0x59, 0xb5, 0x54, 0x27, 0x25, 0xe2, 0x9c); +// {01CDAFF1-C901-45b4-B359-B5542725E29C} + + +// +// GUID definition are required to be outside of header inclusion pragma to avoid +// error during precompiled headers. +// + +#ifndef __PUBLIC_H +#define __PUBLIC_H + +#define BUS_HARDWARE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsToaster\0" +#define BUS_HARDWARE_IDS_LENGTH sizeof (BUS_HARDWARE_IDS) + +#define BUSENUM_COMPATIBLE_IDS L"{B85B7C50-6A01-11d2-B841-00C04FAD5171}\\MsCompatibleToaster\0" +#define BUSENUM_COMPATIBLE_IDS_LENGTH sizeof(BUSENUM_COMPATIBLE_IDS) + + +#define FILE_DEVICE_BUSENUM FILE_DEVICE_BUS_EXTENDER + +#define BUSENUM_IOCTL(_index_) \ + CTL_CODE (FILE_DEVICE_BUSENUM, _index_, METHOD_BUFFERED, FILE_READ_DATA) + +#define IOCTL_BUSENUM_PLUGIN_HARDWARE BUSENUM_IOCTL (0x0) +#define IOCTL_BUSENUM_UNPLUG_HARDWARE BUSENUM_IOCTL (0x1) +#define IOCTL_BUSENUM_EJECT_HARDWARE BUSENUM_IOCTL (0x2) +#define IOCTL_TOASTER_DONT_DISPLAY_IN_UI_DEVICE BUSENUM_IOCTL (0x3) + +// +// Data structure used in PlugIn and UnPlug ioctls +// + +typedef struct _BUSENUM_PLUGIN_HARDWARE +{ + // + // sizeof (struct _BUSENUM_HARDWARE) + // + IN ULONG Size; + + // + // Unique serial number of the device to be enumerated. + // Enumeration will be failed if another device on the + // bus has the same serail number. + // + + IN ULONG SerialNo; + + // + // An array of (zero terminated wide character strings). The array itself + // also null terminated (ie, MULTI_SZ) + // + #pragma warning(disable:4200) // nonstandard extension used + + IN WCHAR HardwareIDs[]; + + #pragma warning(default:4200) + +} BUSENUM_PLUGIN_HARDWARE, *PBUSENUM_PLUGIN_HARDWARE; + +typedef struct _BUSENUM_UNPLUG_HARDWARE +{ + // + // sizeof (struct _REMOVE_HARDWARE) + // + + IN ULONG Size; + + // + // Serial number of the device to be plugged out + // + + ULONG SerialNo; + + ULONG Reserved[2]; + +} BUSENUM_UNPLUG_HARDWARE, *PBUSENUM_UNPLUG_HARDWARE; + +typedef struct _BUSENUM_EJECT_HARDWARE +{ + // + // sizeof (struct _EJECT_HARDWARE) + // + + IN ULONG Size; + + // + // Serial number of the device to be ejected + // + + ULONG SerialNo; + + ULONG Reserved[2]; + +} BUSENUM_EJECT_HARDWARE, *PBUSENUM_EJECT_HARDWARE; + +#endif + diff --git a/general/toaster/umdf2/umdf2toaster.sln b/general/toaster/umdf2/umdf2toaster.sln new file mode 100644 index 00000000..27a7c11c --- /dev/null +++ b/general/toaster/umdf2/umdf2toaster.sln @@ -0,0 +1,123 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Package", "Package", "{DE39E506-CDA6-472B-AA38-CFD787389792}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notify", "Notify", "{6A99D8D7-8707-44E7-8952-C08DA9607026}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Exe", "Exe", "{812F37C3-6174-45B1-BAE8-8A1D22588B5A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Toast", "Toast", "{C76A23DC-DCC1-457B-A57C-FC050E0E28E0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Enum", "Enum", "{29F16893-9AB9-45AC-AF5B-4E933C2E6A95}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Simple", "Simple", "{5652F0ED-6624-49EC-9DB9-B5A3F7253FA3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Func", "Func", "{2C164544-0A50-43A5-A42C-B7B25D777B4E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Featured", "Featured", "{0213881B-B2CC-453E-BBCA-95EE52FEA9C1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Generic", "Generic", "{F2D765A7-8801-482C-924A-0B647DEAE5D5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Filter", "Filter", "{870F719A-95BC-485D-9787-2634A3C2652F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "Package\package.VcxProj", "{52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notify", "exe\notify\notify.vcxproj", "{FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "toast", "exe\toast\toast.vcxproj", "{9BF4F988-D8B7-4E73-BC77-6658D413212F}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Enum", "exe\enum\Enum.vcxproj", "{6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdfsimpleum", "func\simple\wdfsimpleum.vcxproj", "{4867F54B-D8EF-45B0-984E-D571D987174A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wdffeaturedum", "func\featured\wdffeaturedum.vcxproj", "{99A6009E-6137-462F-89C4-6931045895B1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filterum", "filter\generic\filterum.vcxproj", "{A60F76D2-C512-4DA6-8C80-263F1B506267}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|Win32.ActiveCfg = Debug|Win32 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|Win32.Build.0 = Debug|Win32 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|Win32.ActiveCfg = Release|Win32 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|Win32.Build.0 = Release|Win32 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|x64.ActiveCfg = Debug|x64 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Debug|x64.Build.0 = Debug|x64 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|x64.ActiveCfg = Release|x64 + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5}.Release|x64.Build.0 = Release|x64 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|Win32.ActiveCfg = Debug|Win32 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|Win32.Build.0 = Debug|Win32 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|Win32.ActiveCfg = Release|Win32 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|Win32.Build.0 = Release|Win32 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|x64.ActiveCfg = Debug|x64 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Debug|x64.Build.0 = Debug|x64 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|x64.ActiveCfg = Release|x64 + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76}.Release|x64.Build.0 = Release|x64 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|Win32.ActiveCfg = Debug|Win32 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|Win32.Build.0 = Debug|Win32 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|Win32.ActiveCfg = Release|Win32 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|Win32.Build.0 = Release|Win32 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|x64.ActiveCfg = Debug|x64 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Debug|x64.Build.0 = Debug|x64 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|x64.ActiveCfg = Release|x64 + {9BF4F988-D8B7-4E73-BC77-6658D413212F}.Release|x64.Build.0 = Release|x64 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|Win32.ActiveCfg = Debug|Win32 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|Win32.Build.0 = Debug|Win32 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|Win32.ActiveCfg = Release|Win32 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|Win32.Build.0 = Release|Win32 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|x64.ActiveCfg = Debug|x64 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Debug|x64.Build.0 = Debug|x64 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|x64.ActiveCfg = Release|x64 + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69}.Release|x64.Build.0 = Release|x64 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|Win32.ActiveCfg = Debug|Win32 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|Win32.Build.0 = Debug|Win32 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|Win32.ActiveCfg = Release|Win32 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|Win32.Build.0 = Release|Win32 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|x64.ActiveCfg = Debug|x64 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Debug|x64.Build.0 = Debug|x64 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|x64.ActiveCfg = Release|x64 + {4867F54B-D8EF-45B0-984E-D571D987174A}.Release|x64.Build.0 = Release|x64 + {99A6009E-6137-462F-89C4-6931045895B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {99A6009E-6137-462F-89C4-6931045895B1}.Debug|Win32.Build.0 = Debug|Win32 + {99A6009E-6137-462F-89C4-6931045895B1}.Release|Win32.ActiveCfg = Release|Win32 + {99A6009E-6137-462F-89C4-6931045895B1}.Release|Win32.Build.0 = Release|Win32 + {99A6009E-6137-462F-89C4-6931045895B1}.Debug|x64.ActiveCfg = Debug|x64 + {99A6009E-6137-462F-89C4-6931045895B1}.Debug|x64.Build.0 = Debug|x64 + {99A6009E-6137-462F-89C4-6931045895B1}.Release|x64.ActiveCfg = Release|x64 + {99A6009E-6137-462F-89C4-6931045895B1}.Release|x64.Build.0 = Release|x64 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|Win32.ActiveCfg = Debug|Win32 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|Win32.Build.0 = Debug|Win32 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|Win32.ActiveCfg = Release|Win32 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|Win32.Build.0 = Release|Win32 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|x64.ActiveCfg = Debug|x64 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Debug|x64.Build.0 = Debug|x64 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|x64.ActiveCfg = Release|x64 + {A60F76D2-C512-4DA6-8C80-263F1B506267}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {52EEA7C4-68B9-4AE9-B3EC-881A49E9E1E5} = {DE39E506-CDA6-472B-AA38-CFD787389792} + {FEBBDE46-4BD4-462D-87BD-8FDC8C1ECB76} = {6A99D8D7-8707-44E7-8952-C08DA9607026} + {9BF4F988-D8B7-4E73-BC77-6658D413212F} = {C76A23DC-DCC1-457B-A57C-FC050E0E28E0} + {6E1593D4-08A1-45E4-A77F-AF34AC6F0D69} = {29F16893-9AB9-45AC-AF5B-4E933C2E6A95} + {4867F54B-D8EF-45B0-984E-D571D987174A} = {5652F0ED-6624-49EC-9DB9-B5A3F7253FA3} + {99A6009E-6137-462F-89C4-6931045895B1} = {0213881B-B2CC-453E-BBCA-95EE52FEA9C1} + {A60F76D2-C512-4DA6-8C80-263F1B506267} = {F2D765A7-8801-482C-924A-0B647DEAE5D5} + {6A99D8D7-8707-44E7-8952-C08DA9607026} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} + {C76A23DC-DCC1-457B-A57C-FC050E0E28E0} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} + {29F16893-9AB9-45AC-AF5B-4E933C2E6A95} = {812F37C3-6174-45B1-BAE8-8A1D22588B5A} + {5652F0ED-6624-49EC-9DB9-B5A3F7253FA3} = {2C164544-0A50-43A5-A42C-B7B25D777B4E} + {0213881B-B2CC-453E-BBCA-95EE52FEA9C1} = {2C164544-0A50-43A5-A42C-B7B25D777B4E} + {F2D765A7-8801-482C-924A-0B647DEAE5D5} = {870F719A-95BC-485D-9787-2634A3C2652F} + EndGlobalSection +EndGlobal diff --git a/general/tracing/SystemTraceControl/ReadMe.md b/general/tracing/SystemTraceControl/ReadMe.md new file mode 100644 index 00000000..f581e52e --- /dev/null +++ b/general/tracing/SystemTraceControl/ReadMe.md @@ -0,0 +1,11 @@ +SystemTraceProvider +=================== + +This sample application demonstrates how to use event tracing control APIs to collect events from the system trace provider. + +The sample code provided shows how to start an [Event Tracing](http://msdn.microsoft.com/en-us/library/windows/hardware/bb968803) for Windows trace session and how to enable system events with stacks. When you build and run the application, it collects the trace data for 30 seconds and then stops. The sample application writes the results to a file, Systemtrace.etl. For more information, see [Tools for Software Tracing](http://msdn.microsoft.com/en-us/library/windows/hardware/ff552961). + +You can process the Systemtrace.etl file using Tracerpt.exe. Tracerpt.exe is a command-line trace tool that formats trace events. It also analyzes the events and generates summary reports. Tracerpt is included in Windows XP and later versions of Windows. For more information about how to use this tool, see [Tracerpt](http://go.microsoft.com/fwlink/p/?linkid=179389) topic on the TechNet website. + +You can also process the file using the [Windows Performance Toolkit](http://go.microsoft.com/fwlink/p/?linkid=250774) (WPT), which is available in the SDK. + diff --git a/general/tracing/SystemTraceControl/ReadMe.txt b/general/tracing/SystemTraceControl/ReadMe.txt new file mode 100644 index 00000000..54609bd7 --- /dev/null +++ b/general/tracing/SystemTraceControl/ReadMe.txt @@ -0,0 +1,36 @@ +EventTracing SystemTraceProvider control sample +==================================================================================== +This sample demonstrates how to use event tracing control API's to collect events +from system trace provider. The code provided will start an ETW system trace and +enable system events with stacks. After collecting the data for 30 seconds trace +will be stopped. Resulting file (systemtrace.etl) can be processed with +inbox tracerpt.exe, programmatically (OpenTrace/ProcessTrace/CloseTrace) or using +WPT (Windows Performance Toolkit) available in the SDK. + +Sample Language Implementations +=============================== +C++ + +Files +================================================= +SystemTraceProvider.sln +SystemTraceProvider.vcxproj +SystemTraceProvider.cpp +sources +ReadMe.txt + +To build the sample using the command prompt: +============================================= + 1. Open the Command Prompt window and navigate to the directory. + 2. Type msbuild SystemTraceControl.sln. + +To build the sample using Visual Studio (preferred method): +================================================ + 1. Open File Explorer and navigate to the SystemTraceControl directory. + 2. Double-click the icon for the .sln (solution) file to open the file in Visual Studio. + 3. In the Build menu, select Build Solution. The application will be built in the default \Debug or \Release directory. + +To run the sample: +================= + 1. Navigate to the directory that contains the new executable, using the command prompt or File Explorer. + 2. Type SystemTraceControl.exe at the command line, or double-click the icon for SystemTraceControl.exe to launch it from File Explorer.
\ No newline at end of file diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.cpp b/general/tracing/SystemTraceControl/SystemTraceControl.cpp new file mode 100644 index 00000000..a8c55026 --- /dev/null +++ b/general/tracing/SystemTraceControl/SystemTraceControl.cpp @@ -0,0 +1,221 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + SystemTraceControl.cpp + +Abstract: + + This sample demonstrates how to collect events from SystemTraceProvider + on Windows 8. + +Environment: + + User mode only. + +--*/ + +#define INITGUID +#include <windows.h> +#include <stdlib.h> +#include <stdio.h> +#include <strsafe.h> +#include <evntrace.h> + +#define MAXIMUM_SESSION_NAME 1024 + +// +// Guid definitions from "NT Kernel Logger Constants" section on MSDN. +// + +DEFINE_GUID ( /* 3d6fa8d0-fe05-11d0-9dda-00c04fd7ba7c */ + ProcessGuid, + 0x3d6fa8d0, + 0xfe05, + 0x11d0, + 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c + ); + +DEFINE_GUID ( /* 2cb15d1d-5fc1-11d2-abe1-00a0c911f518 */ + ImageLoadGuid, + 0x2cb15d1d, + 0x5fc1, + 0x11d2, + 0xab, 0xe1, 0x00, 0xa0, 0xc9, 0x11, 0xf5, 0x18 + ); + +PEVENT_TRACE_PROPERTIES +AllocateTraceProperties ( + _In_opt_ PWSTR LoggerName, + _In_opt_ PWSTR LogFileName + ) +{ + PEVENT_TRACE_PROPERTIES TraceProperties = NULL; + ULONG BufferSize; + + BufferSize = sizeof(EVENT_TRACE_PROPERTIES) + + (MAXIMUM_SESSION_NAME + MAX_PATH) * sizeof(WCHAR); + + TraceProperties = (PEVENT_TRACE_PROPERTIES)malloc(BufferSize); + if (TraceProperties == NULL) { + wprintf(L"Unable to allocate %d bytes for properties structure.\n", BufferSize); + goto Exit; + } + + // + // Set the session properties. + // + + ZeroMemory(TraceProperties, BufferSize); + TraceProperties->Wnode.BufferSize = BufferSize; + TraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; + TraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + TraceProperties->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + + (MAXIMUM_SESSION_NAME * sizeof(WCHAR)); + + if (LoggerName != NULL) { + StringCchCopy((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LoggerNameOffset), + MAXIMUM_SESSION_NAME, + LoggerName); + } + + if (LogFileName != NULL) { + StringCchCopy((LPWSTR)((PCHAR)TraceProperties + TraceProperties->LogFileNameOffset), + MAX_PATH, + LogFileName); + } + +Exit: + return TraceProperties; +} + +VOID +FreeTraceProperties ( + _In_ PEVENT_TRACE_PROPERTIES TraceProperties + ) +{ + free(TraceProperties); + return; +} + +int +__cdecl +wmain() +{ + CLASSIC_EVENT_ID EventId[2]; + ULONG Status = ERROR_SUCCESS; + TRACEHANDLE SessionHandle = 0; + PEVENT_TRACE_PROPERTIES TraceProperties; + ULONG SystemTraceFlags[8]; + PWSTR LoggerName = L"MyTrace"; + + HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0); + + // + // Allocate EVENT_TRACE_PROPERTIES structure and perform some + // basic initialization. + // + // N.B. LoggerName will be populated during StartTrace call. + // + + TraceProperties = AllocateTraceProperties(NULL, L"SystemTrace.etl"); + if (TraceProperties == NULL) { + Status = ERROR_OUTOFMEMORY; + goto Exit; + } + + // + // Configure additinal trace settings. + // + + TraceProperties->LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_SYSTEM_LOGGER_MODE; + TraceProperties->Wnode.ClientContext = 1; // Use QueryPerformanceCounter for time stamps + TraceProperties->MaximumFileSize = 100; // Limit file size to 100MB max + TraceProperties->BufferSize = 512; // Use 512KB trace buffers + TraceProperties->MinimumBuffers = 64; + TraceProperties->MaximumBuffers = 128; + + // + // Start trace session which can receive events from SystemTraceProvider. + // + + Status = StartTrace(&SessionHandle, LoggerName, TraceProperties); + if (Status != ERROR_SUCCESS) { + wprintf(L"StartTrace() failed with %lu\n", Status); + goto Exit; + } + + // + // Configure stack walking. In this example stack traces will be collected on + // ImageLoad and ProcessCreate events. + // + // N.B. Stack tracing is configured before enabling event collection. + // + + ZeroMemory(EventId, sizeof(EventId)); + EventId[0].EventGuid = ImageLoadGuid; + EventId[0].Type = EVENT_TRACE_TYPE_LOAD; + EventId[1].EventGuid = ProcessGuid; + EventId[1].Type = EVENT_TRACE_TYPE_START; + + Status = TraceSetInformation(SessionHandle, + TraceStackTracingInfo, + EventId, + sizeof(EventId)); + + if (Status != ERROR_SUCCESS) { + wprintf(L"TraceSetInformation(StackTracing) failed with %lu\n", Status); + goto Exit; + } + + // + // Enable system events for Process, Thread and Loader groups. + // + + ZeroMemory(SystemTraceFlags, sizeof(SystemTraceFlags)); + SystemTraceFlags[0] = (EVENT_TRACE_FLAG_PROCESS | + EVENT_TRACE_FLAG_THREAD | + EVENT_TRACE_FLAG_IMAGE_LOAD); + + Status = TraceSetInformation(SessionHandle, + TraceSystemTraceEnableFlagsInfo, + SystemTraceFlags, + sizeof(SystemTraceFlags)); + + if (Status != ERROR_SUCCESS) { + wprintf(L"TraceSetInformation(EnableFlags) failed with %lu\n", Status); + goto Exit; + } + + // + // Collect trace for 30 seconds. + // + + Sleep(30 * 1000); + +Exit: + + // + // Stop tracing. + // + + if (SessionHandle != 0) { + Status = ControlTrace(SessionHandle, NULL, TraceProperties, EVENT_TRACE_CONTROL_STOP); + if (Status != ERROR_SUCCESS) { + wprintf(L"StopTrace() failed with %lu\n", Status); + } + } + + if (TraceProperties != NULL) { + FreeTraceProperties(TraceProperties); + } + + return Status; +} diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.sln b/general/tracing/SystemTraceControl/SystemTraceControl.sln new file mode 100644 index 00000000..4e74108b --- /dev/null +++ b/general/tracing/SystemTraceControl/SystemTraceControl.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SystemTraceControl", "SystemTraceControl.vcxproj", "{BBB08463-9C86-4690-B95B-106B49DD46E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|Win32.ActiveCfg = Debug|Win32 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|Win32.Build.0 = Debug|Win32 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|Win32.ActiveCfg = Release|Win32 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|Win32.Build.0 = Release|Win32 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|x64.ActiveCfg = Debug|x64 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Debug|x64.Build.0 = Debug|x64 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|x64.ActiveCfg = Release|x64 + {BBB08463-9C86-4690-B95B-106B49DD46E2}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj new file mode 100644 index 00000000..556e6d7d --- /dev/null +++ b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj @@ -0,0 +1,179 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{BBB08463-9C86-4690-B95B-106B49DD46E2}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{E8A8798D-133D-48CA-B07A-E8D8A7C82C30}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>SystemTraceControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>SystemTraceControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>SystemTraceControl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>SystemTraceControl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;_UNICODE</PreprocessorDefinitions> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SDK_LIB_PATH)</AdditionalIncludeDirectories> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="SystemTraceControl.cpp" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters new file mode 100644 index 00000000..bc043bf7 --- /dev/null +++ b/general/tracing/SystemTraceControl/SystemTraceControl.vcxproj.Filters @@ -0,0 +1,22 @@ +<?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>{C2A52F8F-D414-40D4-998E-62C57FFF543E}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{CF32093A-DFB7-4C18-B086-1F1DB68AA8F4}</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>{C370B48B-D85C-4319-911D-CC6D213BB287}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="SystemTraceControl.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj new file mode 100644 index 00000000..38a37c6d --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj @@ -0,0 +1,195 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{71F967BF-4410-49F0-A9D9-A0968791E7C3}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{D1927512-3AD6-432A-B43A-993734933EA0}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <MessageCompile Include="evntdrv.xml"> + <GenerateKernelModeLoggingMacros>true</GenerateKernelModeLoggingMacros> + <HeaderFilePath>.\$(IntDir)</HeaderFilePath> + <GeneratedHeaderPath>true</GeneratedHeaderPath> + <WinmetaPath>"$(SDK_INC_PATH)\winmeta.xml"</WinmetaPath> + <RCFilePath>.\$(IntDir)</RCFilePath> + <GeneratedRCAndMessagesPath>true</GeneratedRCAndMessagesPath> + <GeneratedFilesBaseName>evntdrvEvents</GeneratedFilesBaseName> + <UseBaseNameOfInput>true</UseBaseNameOfInput> + </MessageCompile> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>Eventdrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>Eventdrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>Eventdrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>Eventdrv</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="Evntdrv.c" /> + <ResourceCompile Include="evntdrvEvents.rc" /> + </ItemGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters new file mode 100644 index 00000000..b3a19f20 --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/Eventdrv.vcxproj.Filters @@ -0,0 +1,34 @@ +<?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>{FF39F92A-78D6-4DC4-8C57-61B8235F689E}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{7D82ACC1-5CB5-4731-9F63-C6ECF120023F}</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>{C4F65E57-AD43-415D-A828-20341B0A35CA}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{42E3A915-3C68-4861-986D-5BECD364D878}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <MessageCompile Include="evntdrv.xml"> + <Filter>Resource Files</Filter> + </MessageCompile> + <ResourceCompile Include="evntdrvEvents.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Evntdrv.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/tracing/evntdrv/Eventdrv/drvioctl.h b/general/tracing/evntdrv/Eventdrv/drvioctl.h new file mode 100644 index 00000000..2185e451 --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/drvioctl.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + drvioctl.h + +Abstract: + + Definitions of IOCTL codes and data structures exported by TRACEDRV. + + +--*/ + +#ifndef __EVENTKMP_IOCTL__ +#define __EVENTKMP_IOCTL__ + +// +// IOCTL control codes +// +#define IOCTL_EVNTKMP_TRACE_EVENT_A \ + CTL_CODE( FILE_DEVICE_UNKNOWN, 0x801, \ + METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#endif // __EVENTKMP_IOCTL__ + + diff --git a/general/tracing/evntdrv/Eventdrv/evntdrv.c b/general/tracing/evntdrv/Eventdrv/evntdrv.c new file mode 100644 index 00000000..ad8b091d --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/evntdrv.c @@ -0,0 +1,345 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + evntdrv.c + +Abstract: + + Sample kernel mode trace provider/driver. + + +--*/ +#include <stdio.h> +#include <ntddk.h> +#include "drvioctl.h" + + +// +// evntdrvEvents.h is generated by MC.exe with the -km option, +// using the manifest evntdrv.htm. +// The file contains a macro per event, and the required code to raise the +// event. +#include "evntdrvEvents.h" + + +DRIVER_UNLOAD EventDrvDriverUnload; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH EventDrvDispatchOpenClose; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH EventDrvDispatchDeviceControl; + +#define EventDrv_NT_DEVICE_NAME L"\\Device\\EventEtw" +#define EventDrv_WIN32_DEVICE_NAME L"\\DosDevices\\EVENTETW" + +DRIVER_INITIALIZE DriverEntry; + +NTSTATUS +EventDrvDispatchOpenClose( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ); + +NTSTATUS +EventDrvDispatchDeviceControl( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ); + +VOID +EventDrvDriverUnload( + IN PDRIVER_OBJECT DriverObject + ); + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text( INIT, DriverEntry ) +#pragma alloc_text( PAGE, EventDrvDispatchOpenClose ) +#pragma alloc_text( PAGE, EventDrvDispatchDeviceControl ) +#pragma alloc_text( PAGE, EventDrvDriverUnload ) +#endif // ALLOC_PRAGMA + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path + to driver-specific key in the registry + +Return Value: + + STATUS_SUCCESS if successful + STATUS_UNSUCCESSFUL otherwise + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + UNICODE_STRING DeviceName; + UNICODE_STRING LinkName; + PDEVICE_OBJECT EventDrvDeviceObject; + WCHAR DeviceNameString[128]; + ULONG LengthToCopy = 128 * sizeof(WCHAR); + UNREFERENCED_PARAMETER (RegistryPath); + + KdPrint(("EventDrv: DriverEntry\n")); + + // + // Create Dispatch Entry Points. + // + DriverObject->DriverUnload = EventDrvDriverUnload; + DriverObject->MajorFunction[ IRP_MJ_CREATE ] = EventDrvDispatchOpenClose; + DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = EventDrvDispatchOpenClose; + DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = EventDrvDispatchDeviceControl; + + RtlInitUnicodeString( &DeviceName, EventDrv_NT_DEVICE_NAME ); + + // + // Create the Device object + // + Status = IoCreateDevice( + DriverObject, + 0, + &DeviceName, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &EventDrvDeviceObject); + + if (!NT_SUCCESS(Status)) { + return Status; + } + + RtlInitUnicodeString( &LinkName, EventDrv_WIN32_DEVICE_NAME ); + Status = IoCreateSymbolicLink( &LinkName, &DeviceName ); + + if ( !NT_SUCCESS( Status )) { + IoDeleteDevice( EventDrvDeviceObject ); + return Status; + } + + + // + // Choose a buffering mechanism + // + EventDrvDeviceObject->Flags |= DO_BUFFERED_IO; + + + // + // Register with ETW + // + EventRegisterSample_Driver(); + + // + // Log an Event with : DeviceNameLength + // DeviceName + // Status + // + + // Copy the device name into the WCHAR local buffer in order + // to place a NULL character at the end, since this field is + // defined in the manifest as a NULL-terminated string + + if (DeviceName.Length <= 128 * sizeof(WCHAR)) { + + LengthToCopy = DeviceName.Length; + + } + + RtlCopyMemory(DeviceNameString, + DeviceName.Buffer, + LengthToCopy); + + DeviceNameString[LengthToCopy/sizeof(WCHAR)] = L'\0'; + + EventWriteStartEvent(NULL, DeviceName.Length, DeviceNameString, Status); + + + return STATUS_SUCCESS; +} + +NTSTATUS +EventDrvDispatchOpenClose( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ) +/*++ + +Routine Description: + + Dispatch routine to handle Create/Close IRPs. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT status code + +--*/ +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER (pDO); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + + +NTSTATUS +EventDrvDispatchDeviceControl( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ) +/*++ + +Routine Description: + + Dispatch routine to handle IOCTL IRPs. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT Status code + +--*/ +{ + NTSTATUS Status = STATUS_SUCCESS; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp ); + ULONG ControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER (pDO); + + Irp->IoStatus.Information = + irpStack->Parameters.DeviceIoControl.OutputBufferLength; + + switch ( ControlCode ) { + case IOCTL_EVNTKMP_TRACE_EVENT_A: + { + + EventWriteSampleEventA(NULL); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + break; + } + + default: + + // + // Not one we recognize. Error. + // + + Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + + break; + } + + // + // Get rid of this request + // + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return Status; +} + + +VOID +EventDrvDriverUnload( + IN PDRIVER_OBJECT DriverObject + ) + +/*++ + +Routine Description: + + Free all the resources allocated in DriverEntry. + +Arguments: + + DriverObject - pointer to a driver object. + +Return Value: + + VOID. + +--*/ +{ + PDEVICE_OBJECT DevObj; + UNICODE_STRING LinkName; + + PAGED_CODE(); + + KdPrint(("EventDrv: Unloading \n")); + + // + // Get pointer to Device object + // + DevObj = DriverObject->DeviceObject; + + EventWriteUnloadEvent(NULL, DevObj); + + // + // Unregister the driver as an ETW provider + // + EventUnregisterSample_Driver(); + + + // + // Form the Win32 symbolic link name. + // + RtlInitUnicodeString( &LinkName, EventDrv_WIN32_DEVICE_NAME ); + + // + // Remove symbolic link from Object + // namespace... + // + IoDeleteSymbolicLink( &LinkName ); + + // + // Unload the callbacks from the kernel to this driver + // + IoDeleteDevice( DevObj ); + +} + + diff --git a/general/tracing/evntdrv/Eventdrv/evntdrv.xml b/general/tracing/evntdrv/Eventdrv/evntdrv.xml new file mode 100644 index 00000000..23cff805 --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/evntdrv.xml @@ -0,0 +1,99 @@ +<?xml version='1.0' encoding='utf-8' standalone='yes'?> +<instrumentationManifest + xmlns="http://schemas.microsoft.com/win/2004/08/events" + xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" + > + <instrumentation> + <events> + <provider + guid="{b5a0bda9-50fe-4d0e-a83d-bae3f58c94d6}" + messageFileName="%SystemDrive%\ETWDriverSample\Eventdrv.sys" + name="Sample Driver" + resourceFileName="%SystemDrive%\ETWDriverSample\Eventdrv.sys" + symbol="DriverControlGuid" + > + <channels> + <importChannel + chid="SYSTEM" + name="System" + /> + </channels> + <templates> + <template tid="tid_load_template"> + <data + inType="win:UInt16" + name="DeviceNameLength" + outType="xs:unsignedShort" + /> + <data + inType="win:UnicodeString" + name="name" + outType="xs:string" + /> + <data + inType="win:UInt32" + name="Status" + outType="xs:unsignedInt" + /> + </template> + <template tid="tid_unload_template"> + <data + inType="win:Pointer" + name="DeviceObjPtr" + outType="win:HexInt64" + /> + </template> + </templates> + <events> + <event + channel="SYSTEM" + level="win:Informational" + message="$(string.StartEvent.EventMessage)" + opcode="win:Start" + symbol="StartEvent" + template="tid_load_template" + value="1" + /> + <event + channel="SYSTEM" + level="win:Informational" + message="$(string.SampleEventA.EventMessage)" + opcode="win:Info" + symbol="SampleEventA" + value="2" + /> + <event + channel="SYSTEM" + level="win:Informational" + message="$(string.UnloadEvent.EventMessage)" + opcode="win:Stop" + symbol="UnloadEvent" + template="tid_unload_template" + value="3" + /> + </events> + </provider> + </events> + </instrumentation> + <localization xmlns="http://schemas.microsoft.com/win/2004/08/events"> + <resources culture="en-US"> + <stringTable> + <string + id="StartEvent.EventMessage" + value="Driver Loaded" + /> + <string + id="SampleEventA.EventMessage" + value="IRP A Occurred" + /> + <string + id="UnloadEvent.EventMessage" + value="Driver Unloaded" + /> + </stringTable> + </resources> + </localization> +</instrumentationManifest> diff --git a/general/tracing/evntdrv/Eventdrv/evntdrvevents.rc b/general/tracing/evntdrv/Eventdrv/evntdrvevents.rc new file mode 100644 index 00000000..1ee5105a --- /dev/null +++ b/general/tracing/evntdrv/Eventdrv/evntdrvevents.rc @@ -0,0 +1,3 @@ +LANGUAGE 0x9,0x1 +1 11 "evntdrvEvents_MSG00001.bin" +1 WEVT_TEMPLATE "evntdrvEventsTEMP.BIN" diff --git a/general/tracing/evntdrv/ReadMe.md b/general/tracing/evntdrv/ReadMe.md new file mode 100644 index 00000000..f5780ef6 --- /dev/null +++ b/general/tracing/evntdrv/ReadMe.md @@ -0,0 +1,62 @@ +Eventdrv +======== + +Eventdrv is a sample kernel-mode trace provider and driver. The driver does not control any hardware; it simply generates trace events. It is designed to demonstrate the use of the [Event Tracing for Windows (ETW)](http://msdn.microsoft.com/en-us/library/windows/hardware/ff545699) API in a driver. + +Evntdrv registers as a provider by calling the [**EtwRegister**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff545603) API. If the registration is successful, it logs a StartEvent with the device's name, the length of the name, and the status code. Then, when the sample receives a DeviceIOControl call, it logs a SampleEventA event. Finally, when the driver gets unloaded, it logs an UnloadEvent event with a pointer to the device object + +**Note** The Windows Pre-Processor (WPP) Tracing tools such as TraceView.exe cannot be used to start, stop, or view traces. + + +Run the sample +-------------- + +1. Install the manifest (Evntdrv.xml), which is located in the Evntdrv\\Eventdrv folder. Open a Visual Studio Command window (Run as administrator) and use the following command: + + ``` {.syntax xml:space="preserve"} + wevtutil im evntdrv.xml + ``` + + Installing the manifest creates registry keys that enable tools to find the resource and message files that contain event provider information. For further details about the WevtUtil.exe tool, see the MSDN Library. + + **Note** Using a Visual Studio Command windows sets up the environment variables you need to run the tracing tools for this sample. + +2. Make a folder in the system directory called ETWDriverSample (for example, C:\\ETWDriverSample). + + Copy Eventdrv.sys and Evntctrl.exe to the ETWDriverSample folder. + + The ETWDriverSample directory must be created because the path to the resource file that is specified in the evntdrv.xml manifest points to the %SystemRoot%\\ETWDriverSample folder. If this folder is not created and the Eventdrv.sys binary is not copied, decoding tools cannot find the event information to decode the trace file. + +3. Use Tracelog to start a trace session that is called "TestEventdrv." The following command starts the trace session and creates a trace log file, Eventdrv.etl, in the local directory. + + ``` {.syntax xml:space="preserve"} + Tracelog -start TestEventdrv -guid #b5a0bda9-50fe-4d0e-a83d-bae3f58c94d6 -f Eventdrv.etl + ``` + +4. To generate trace messages, run Evntctrl.exe. Each time you type a character other than **Q** or **q**, Evntctrl sends an IOCTL to the driver that signals it to generate trace messages. To stop Evntctrl, type **Q** or **q**. + +5. To stop the trace session, run the following command: + + ``` {.syntax xml:space="preserve"} + tracelog -stop TestEventdrv + ``` + +6. To display the traces collected in the Tracedrv.etl file, run the following command: + + ``` {.syntax xml:space="preserve"} + tracerpt Eventdrv.etl + ``` + + This command creates two files: Summary.txt and Dumpfile.xml. Dumpfile.xml will contain the event information in an XML format. + +7. To uninstall the manifest, run the following command: + + ``` {.syntax xml:space="preserve"} + wevtutil um evntdrv.xml + ``` + +Notes +----- + +If you are building the Eventdrv sample to test on a 64-bit version of Windows, you need to sign the driver. Starting with Windows Vista, all 64-bit versions of Windows require driver code to have a digital signature for the driver to load. See [Signing a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554809) and [Signing a Driver During Development and Testing](http://msdn.microsoft.com/en-us/library/windows/hardware/hh967733). You might also need to configure the test computer so that it can load test-signed kernel mode code, see [The TESTSIGNING Boot Configuration Option](http://msdn.microsoft.com/en-us/library/windows/hardware/ff553484) and [**BCDEdit /set**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff542202). + diff --git a/general/tracing/evntdrv/eventdrv.sln b/general/tracing/evntdrv/eventdrv.sln new file mode 100644 index 00000000..f7556ef7 --- /dev/null +++ b/general/tracing/evntdrv/eventdrv.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Eventdrv", "Eventdrv", "{622DAC05-C30E-4BEE-B268-690B1B0DA989}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Evntctrl", "Evntctrl", "{90152226-E1D1-482C-9AB8-701B24BA34A1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Eventdrv", "Eventdrv\Eventdrv.vcxproj", "{71F967BF-4410-49F0-A9D9-A0968791E7C3}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "evntctrl", "evntctrl\evntctrl.vcxproj", "{09705E95-23AF-44BE-AD49-703F2A469DB0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|Win32.ActiveCfg = Debug|Win32 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|Win32.Build.0 = Debug|Win32 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|Win32.ActiveCfg = Release|Win32 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|Win32.Build.0 = Release|Win32 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|x64.ActiveCfg = Debug|x64 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Debug|x64.Build.0 = Debug|x64 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|x64.ActiveCfg = Release|x64 + {71F967BF-4410-49F0-A9D9-A0968791E7C3}.Release|x64.Build.0 = Release|x64 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|Win32.ActiveCfg = Debug|Win32 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|Win32.Build.0 = Debug|Win32 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|Win32.ActiveCfg = Release|Win32 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|Win32.Build.0 = Release|Win32 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|x64.ActiveCfg = Debug|x64 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Debug|x64.Build.0 = Debug|x64 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|x64.ActiveCfg = Release|x64 + {09705E95-23AF-44BE-AD49-703F2A469DB0}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {71F967BF-4410-49F0-A9D9-A0968791E7C3} = {622DAC05-C30E-4BEE-B268-690B1B0DA989} + {09705E95-23AF-44BE-AD49-703F2A469DB0} = {90152226-E1D1-482C-9AB8-701B24BA34A1} + EndGlobalSection +EndGlobal diff --git a/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj new file mode 100644 index 00000000..91610949 --- /dev/null +++ b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj @@ -0,0 +1,152 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{09705E95-23AF-44BE-AD49-703F2A469DB0}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{4CB0AEF6-22DB-46DE-B86C-BA8FA83720FF}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>evntctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>evntctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>evntctrl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>evntctrl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\Eventdrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.c" /> + <ClCompile Include="tracectl.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters new file mode 100644 index 00000000..fc9905ff --- /dev/null +++ b/general/tracing/evntdrv/evntctrl/evntctrl.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{CBA4CFF0-1A7A-4894-AC68-18D38BD5EABB}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{6EB53DDD-D4F4-4C46-9218-63E8B1F46F74}</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>{479AEB6E-676D-4829-891B-3C82EADD4F94}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="tracectl.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/tracing/evntdrv/evntctrl/install.c b/general/tracing/evntdrv/evntctrl/install.c new file mode 100644 index 00000000..9f44073b --- /dev/null +++ b/general/tracing/evntdrv/evntctrl/install.c @@ -0,0 +1,499 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + + +--*/ +#define UNICODE +#define _UNICODE +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <tchar.h> + +#include "install.h" + + +BOOLEAN +InstallDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName, + IN LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName, + IN LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + _tprintf(_T("CreateService failed! Error = %d \n"), err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + IN LPCTSTR DriverName, + IN LPCTSTR ServiceName, + IN USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + _tprintf(_T("Invalid Driver or Service provided to ManageDriver() \n")); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + _tprintf(_T("Open SC Manager failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + case DRIVER_FUNC_STOP: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + _tprintf(_T("Unknown ManageDriver() function. \n")); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + if (schSCManager) { + + CloseServiceHandle(schSCManager); + } + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + _tprintf(_T("DeleteService failed! Error = %d \n"), GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + _tprintf(_T("StartService failure! Error = %d \n"), err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + _tprintf(_T("ControlService failed! Error = %d \n"), GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle (schService); + } + + return rCode; + +} // StopDriver + + + + diff --git a/general/tracing/evntdrv/evntctrl/install.h b/general/tracing/evntdrv/evntctrl/install.h new file mode 100644 index 00000000..879bc693 --- /dev/null +++ b/general/tracing/evntdrv/evntctrl/install.h @@ -0,0 +1,37 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.h + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + + +--*/ + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 +#define DRIVER_FUNC_STOP 0x03 + +#define DRIVER_NAME _T("Eventdrv") + +BOOLEAN +ManageDriver( + IN LPCTSTR DriverName, + IN LPCTSTR ServiceName, + IN USHORT Function + ); + diff --git a/general/tracing/evntdrv/evntctrl/tracectl.c b/general/tracing/evntdrv/evntctrl/tracectl.c new file mode 100644 index 00000000..2b9a0b78 --- /dev/null +++ b/general/tracing/evntdrv/evntctrl/tracectl.c @@ -0,0 +1,243 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + tracectl.c + +Environment: + + User mode Win32 console application + +Revision History: + + +--*/ +#define UNICODE +#define _UNICODE +#include <windows.h> +#include <winioctl.h> +#include <tchar.h> +#include <stdio.h> +#include "drvioctl.h" +#include "install.h" +#include <conio.h> +#include <strsafe.h> + +#define WAIT_TIME 10 + +BOOLEAN +SetupDriverName( + _Out_writes_(MAX_PATH)LPTSTR DriverLocation + ); + +int _cdecl main(int argc, LPCTSTR argv[]) +{ + HANDLE hDevice; // handle to a device, file, or directory + DWORD dwError = ERROR_SUCCESS; + LPVOID lpFileName = _T("\\\\.\\EventEtw") ; + TCHAR driverLocation[MAX_PATH]; + DWORD dwOutBuffer[2048]; + DWORD dwOutBufferCount ; + int ch; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + if ((hDevice = CreateFile( + lpFileName, // pointer to name of the file + 0, // access (read-write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL // handle to file with attributes to + // copy + )) == INVALID_HANDLE_VALUE) { + dwError = GetLastError(); + + if ( dwError != ERROR_FILE_NOT_FOUND ) { + _tprintf(_T("CreateFile failed ! error: %d\n"), dwError); + return 1; + } + + // + // Setup full path to driver name + // + + if (!SetupDriverName(driverLocation)) { + + return 2; + + } + + // + // Install driver + // + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + _tprintf(_T("Unable to install driver. \n")); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return 3; + } + + if ((hDevice = CreateFile( + lpFileName, // pointer to name of the file + 0, // access (read-write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL // handle to file with attributes to + // copy + )) == INVALID_HANDLE_VALUE) { + + _tprintf(_T("Error: CreateFile failed\n")); + return 4; + } + } + + + + _tprintf(_T("\nPress 'q' to exit, any other key to send ioctl...\n")); + fflush(stdin); + ch = _getche(); + + while(tolower(ch) != 'q' ) + { + + _tprintf(_T("Making IOCTL_EVNTKMP_TRACE_EVENT_A ioctl to log events\n")); + if (DeviceIoControl( + hDevice, // handle to a device, file, or directory + IOCTL_EVNTKMP_TRACE_EVENT_A, // control code of operation to perform + NULL, // pointer to buffer to supply input data + 0, // size, in bytes, of input buffer + dwOutBuffer, // pointer to buffer to receive output data + 2048, // size, in bytes, of output buffer + &dwOutBufferCount, // pointer to variable to receive byte count + NULL // pointer to structure for asynchronous operation + ) == 0) { + + _tprintf(_T("DeviceIOControl Failed %d\n"),GetLastError()); + return 5; + + } + ch = _getche(); + } + + if (CloseHandle(hDevice) == 0) { + + _tprintf(_T("CloseHandle Failed %d\n"),GetLastError()); + return 6; + + } + + // + // stop the driver + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + _tprintf(_T("Driver '%s' is removed\n"), DRIVER_NAME); + + return 0; +} + +BOOLEAN +SetupDriverName( + _Out_writes_(MAX_PATH) LPTSTR DriverLocation + ) +{ + HANDLE fileHandle; + + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(MAX_PATH, + DriverLocation + ); + + if (!driverLocLen) { + + _tprintf(_T("GetCurrentDirectory failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Setup path name to driver file. + // + + if (StringCchPrintf(&DriverLocation[_tcslen(DriverLocation)], + (MAX_PATH - _tcslen(DriverLocation)), + _T("\\%s.sys"), + DRIVER_NAME) != S_OK){ + _tprintf(_T("Failed to generate DriverLocation!, StringCchPrintf Error = %d \n"), GetLastError()); + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + _tprintf(_T("Driver: '%s' is not in the current directory. \n"), DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName diff --git a/general/tracing/tracedriver/ReadMe.md b/general/tracing/tracedriver/ReadMe.md new file mode 100644 index 00000000..99c46dd5 --- /dev/null +++ b/general/tracing/tracedriver/ReadMe.md @@ -0,0 +1,73 @@ +Tracedrv +======== + +Tracedrv is a sample driver instrumented for software tracing. The driver does not control any hardware; it simply generates trace messages. It is designed to show how to use WPP software tracing macros in a driver. + +Tracedrv initializes tracing (by using WPP\_INIT\_TRACING) and, when it receives a DeviceIOControl call, it starts a thread that logs 100 trace messages. The WPP software tracing directives, calls, and macros in the code are accompanied by comments that explain their purpose + +While examining Tracedrv, read the [WPP Software Tracing](http://msdn.microsoft.com/en-us/library/windows/hardware/ff556204) in the Windows Driver Kit (WDK). This section includes a reference section that describes the directives, macros, and calls required for WPP software tracing. + +Run the sample +-------------- + +To test the Tracedrv event tracing provider, use the following procedure. + +1. Copy the Tracectl.exe file that was created when you built the Tracedrv solution from the Tracectl directory (for example, \\Documents\\Visual Studio 2013\\Projects\\tracedrv\\tracectl\\*platform*) to the Tracedrv directory (for example, \\Documents\\Visual Studio 2013\\Projects\\tracedrv\\tracedrv\\*platform*). +2. Use Tracepdb to create a trace message format (TMF) file and a trace message control (TMC) file from the Tracedrv.pdb file. Tracepdb is located in the C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\*platform* directory. The PDB file that is used in this command is created when you the build the solution. Open a Visual Studio Command prompt window and navigate to the target build platform and configuration directory. Type the following command: + + **tracepdb -f tracedrv.pdb** + +3. In the same Tracedrv target build directory, create a control GUID file for Tracedrv by opening a text file, adding the following content, and saving the file as Tracedrv.ctl. + + <table> + <colgroup> + <col width="100%" /> + </colgroup> + <thead> + <tr class="header"> + <th align="left">Text</th> + </tr> + </thead> + <tbody> + <tr class="odd"> + <td align="left"><pre><code>d58c126f-b309-11d1-969e-0000f875a5bc </code></pre></td> + </tr> + </tbody> + </table> + +4. Use Tracelog to start a trace session that is called *TestTracedrv*. Tracelog is located in the C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\*platform* directory. The Tracedrv.ctl file that is used in this command was created in the previous step. The following command starts a trace session and creates a trace log file, tracedrv.etl, in the local directory. + + ``` {.syntax xml:space="preserve"} + tracelog -start TestTracedrv -guid tracedrv.ctl -f tracedrv.etl -flag 1 + ``` + + **Note** Note: Without the -flag parameter, Tracedrv will not generate any trace messages. + +5. To generate trace messages, run Tracectl.exe. This executable file is built when you build the solution. Each time you type a character, other than **Q** or **q**, Tracectl sends an IOCTL to the driver that signals it to generate trace messages. To stop Tracectl, type **Q** or **q**. +6. To stop the trace session, use the following Tracelog command. + + ``` {.syntax xml:space="preserve"} + tracelog -stop TestTracedrv + ``` + +7. To display the trace messages in the Tracedrv.etl file, use Tracefmt.exe. Tracefmt.exe is located in the C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\*platform*. The TMF file used in this command was created by Tracepdb.exe in step 2. The **-p** option specifies the directory of the TMF file. In this case, the TMF file is in the current directory. Type the following command: + + ``` {.syntax xml:space="preserve"} + tracefmt tracedrv.etl -p . -o Tracedrv.out + ``` + +The resulting Tracedrv.out file is a human-readable text file of the Tracedrv trace messages. To interpret the trace messages, in the Tracedrv.c file, search for the [**DoTraceMessage**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544918) macros. + +Notes +----- + +This sample driver should not be used in a production environment. + +Tracedrv is designed for Windows XP and later versions of Windows. It does not demonstrate how to add WPP software tracing to a Windows 2000 driver. (For information about adding WPP software tracing to a Windows 2000 driver, see the [Software Tracing FAQ](http://msdn.microsoft.com/en-us/library/windows/hardware/ff551795) topic in the Windows DDK documentation.) + +Also, because it is not a Plug and Play driver, Tracedrv does not demonstrate tracing in a Plug and Play environment. + +Tracedrv demonstrates the basic elements required for software tracing. It does not demonstrate more advanced tracing techniques, such as writing customized tracing calls (variations of [**DoTraceMessage**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff544918)), or the use of WMI calls for software tracing. + +If you are building the Tracedrv sample to test on a 64-bit version of Windows, you need to sign the driver. Starting with Windows Vista, all 64-bit versions of Windows require driver code to have a digital signature for the driver to load. See [Signing a Driver](http://msdn.microsoft.com/en-us/library/windows/hardware/ff554809) and [Signing a Driver During Development and Testing](http://msdn.microsoft.com/en-us/library/windows/hardware/hh967733). You might also need to configure the test computer so that it can load test-signed kernel mode code, see [The TESTSIGNING Boot Configuration Option](http://msdn.microsoft.com/en-us/library/windows/hardware/ff553484) and [**BCDEdit /set**](http://msdn.microsoft.com/en-us/library/windows/hardware/ff542202). + diff --git a/general/tracing/tracedriver/tracectl/install.c b/general/tracing/tracedriver/tracectl/install.c new file mode 100644 index 00000000..9f44073b --- /dev/null +++ b/general/tracing/tracedriver/tracectl/install.c @@ -0,0 +1,499 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + install.c + +Abstract: + + Win32 routines to dynamically load and unload a Windows NT kernel-mode + driver using the Service Control Manager APIs. + +Environment: + + User mode only + + +--*/ +#define UNICODE +#define _UNICODE +#include <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <tchar.h> + +#include "install.h" + + +BOOLEAN +InstallDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName, + IN LPCTSTR ServiceExe + ); + + +BOOLEAN +RemoveDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +StartDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +StopDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ); + +BOOLEAN +InstallDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName, + IN LPCTSTR ServiceExe + ) +/*++ + +Routine Description: + +Arguments: + +Return Value: + +--*/ +{ + SC_HANDLE schService; + DWORD err; + + // + // NOTE: This creates an entry for a standalone driver. If this + // is modified for use with a driver that requires a Tag, + // Group, and/or Dependencies, it may be necessary to + // query the registry for existing driver information + // (in order to determine a unique Tag, etc.). + // + + // + // Create a new a service object. + // + + schService = CreateService(SchSCManager, // handle of service control manager database + DriverName, // address of name of service to start + DriverName, // address of display name + SERVICE_ALL_ACCESS, // type of access to service + SERVICE_KERNEL_DRIVER, // type of service + SERVICE_DEMAND_START, // when to start service + SERVICE_ERROR_NORMAL, // severity if service fails to start + ServiceExe, // address of name of binary file + NULL, // service does not belong to a group + NULL, // no tag requested + NULL, // no dependency names + NULL, // use LocalSystem account + NULL // no password for service account + ); + + if (schService == NULL) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_EXISTS) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + _tprintf(_T("CreateService failed! Error = %d \n"), err ); + + // + // Indicate an error. + // + + return FALSE; + } + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + // + // Indicate success. + // + + return TRUE; + +} // InstallDriver + +BOOLEAN +ManageDriver( + IN LPCTSTR DriverName, + IN LPCTSTR ServiceName, + IN USHORT Function + ) +{ + + SC_HANDLE schSCManager; + + BOOLEAN rCode = TRUE; + + // + // Insure (somewhat) that the driver and service names are valid. + // + + if (!DriverName || !ServiceName) { + + _tprintf(_T("Invalid Driver or Service provided to ManageDriver() \n")); + + return FALSE; + } + + // + // Connect to the Service Control Manager and open the Services database. + // + + schSCManager = OpenSCManager(NULL, // local machine + NULL, // local database + SC_MANAGER_ALL_ACCESS // access required + ); + + if (!schSCManager) { + + _tprintf(_T("Open SC Manager failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Do the requested function. + // + + switch( Function ) { + + case DRIVER_FUNC_INSTALL: + + // + // Install the driver service. + // + + if (InstallDriver(schSCManager, + DriverName, + ServiceName + )) { + + // + // Start the driver service (i.e. start the driver). + // + + rCode = StartDriver(schSCManager, + DriverName + ); + + } else { + + // + // Indicate an error. + // + + rCode = FALSE; + } + + break; + + case DRIVER_FUNC_REMOVE: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Remove the driver service. + // + + RemoveDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + case DRIVER_FUNC_STOP: + + // + // Stop the driver. + // + + StopDriver(schSCManager, + DriverName + ); + + // + // Ignore all errors. + // + + rCode = TRUE; + + break; + + default: + + _tprintf(_T("Unknown ManageDriver() function. \n")); + + rCode = FALSE; + + break; + } + + // + // Close handle to service control manager. + // + + if (schSCManager) { + + CloseServiceHandle(schSCManager); + } + + return rCode; + +} // ManageDriver + + +BOOLEAN +RemoveDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + BOOLEAN rCode; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + // + // Indicate error. + // + + return FALSE; + } + + // + // Mark the service for deletion from the service control manager database. + // + + if (DeleteService(schService)) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + _tprintf(_T("DeleteService failed! Error = %d \n"), GetLastError()); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return rCode; + +} // RemoveDriver + + + +BOOLEAN +StartDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + SC_HANDLE schService; + DWORD err; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Start the execution of the service (i.e. start the driver). + // + + if (!StartService(schService, // service identifier + 0, // number of arguments + NULL // pointer to arguments + )) { + + err = GetLastError(); + + if (err == ERROR_SERVICE_ALREADY_RUNNING) { + + // + // Ignore this error. + // + + return TRUE; + + } else { + + _tprintf(_T("StartService failure! Error = %d \n"), err ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + return FALSE; + } + + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle(schService); + } + + return TRUE; + +} // StartDriver + + + +BOOLEAN +StopDriver( + IN SC_HANDLE SchSCManager, + IN LPCTSTR DriverName + ) +{ + BOOLEAN rCode = TRUE; + SC_HANDLE schService; + SERVICE_STATUS serviceStatus; + + // + // Open the handle to the existing service. + // + + schService = OpenService(SchSCManager, + DriverName, + SERVICE_ALL_ACCESS + ); + + if (schService == NULL) { + + _tprintf(_T("OpenService failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Request that the service stop. + // + + if (ControlService(schService, + SERVICE_CONTROL_STOP, + &serviceStatus + )) { + + // + // Indicate success. + // + + rCode = TRUE; + + } else { + + _tprintf(_T("ControlService failed! Error = %d \n"), GetLastError() ); + + // + // Indicate failure. Fall through to properly close the service handle. + // + + rCode = FALSE; + } + + // + // Close the service object. + // + + if (schService) { + + CloseServiceHandle (schService); + } + + return rCode; + +} // StopDriver + + + + diff --git a/general/tracing/tracedriver/tracectl/install.h b/general/tracing/tracedriver/tracectl/install.h new file mode 100644 index 00000000..843a8387 --- /dev/null +++ b/general/tracing/tracedriver/tracectl/install.h @@ -0,0 +1,14 @@ + +#define DRIVER_FUNC_INSTALL 0x01 +#define DRIVER_FUNC_REMOVE 0x02 +#define DRIVER_FUNC_STOP 0x03 + +#define DRIVER_NAME _T("tracedrv") + +BOOLEAN +ManageDriver( + IN LPCTSTR DriverName, + IN LPCTSTR ServiceName, + IN USHORT Function + ); + diff --git a/general/tracing/tracedriver/tracectl/tracectl.c b/general/tracing/tracedriver/tracectl/tracectl.c new file mode 100644 index 00000000..f4476946 --- /dev/null +++ b/general/tracing/tracedriver/tracectl/tracectl.c @@ -0,0 +1,244 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + tracectl.c + +Environment: + + User mode Win32 console application + +Revision History: + + +--*/ +#define UNICODE +#define _UNICODE +#include <windows.h> +#include <winioctl.h> +#include <tchar.h> +#include <stdio.h> +#include "drvioctl.h" +#include "install.h" +#include <conio.h> +#include <strsafe.h> + +#define WAIT_TIME 10 + +BOOLEAN +SetupDriverName( + _Out_writes_(MAX_PATH)LPTSTR DriverLocation + ); + +int _cdecl main(int argc, LPCTSTR argv[]) +{ + HANDLE hDevice; // handle to a device, file, or directory + DWORD dwError = ERROR_SUCCESS; + LPVOID lpFileName = _T("\\\\.\\TraceKmp") ; + TCHAR driverLocation[MAX_PATH]; + DWORD dwOutBuffer[2048]; + DWORD dwOutBufferCount ; + int ch; + + UNREFERENCED_PARAMETER(argc); + UNREFERENCED_PARAMETER(argv); + + + if ((hDevice = CreateFile( + lpFileName, // pointer to name of the file + 0, // access (read-write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL // handle to file with attributes to + // copy + )) == INVALID_HANDLE_VALUE) { + dwError = GetLastError(); + + if ( dwError != ERROR_FILE_NOT_FOUND ) { + _tprintf(_T("CreateFile failed ! error: %d\n"), dwError); + return 1; + } + + // + // Setup full path to driver name + // + + if (!SetupDriverName(driverLocation)) { + + return 2; + + } + + // + // Install driver + // + + if (!ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_INSTALL + )) { + + _tprintf(_T("Unable to install driver. \n")); + + // + // Error - remove driver. + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + return 3; + } + + if ((hDevice = CreateFile( + lpFileName, // pointer to name of the file + 0, // access (read-write) mode + 0, // share mode + NULL, // pointer to security attributes + OPEN_EXISTING, // how to create + FILE_ATTRIBUTE_NORMAL, // file attributes + NULL // handle to file with attributes to + // copy + )) == INVALID_HANDLE_VALUE) { + + _tprintf(_T("Error: CreateFile failed\n")); + return 4; + } + } + + + + _tprintf(_T("\nPress 'q' to exit, any other key to send ioctl...\n")); + fflush(stdin); + ch = _getche(); + + while(tolower(ch) != 'q' ) + { + + _tprintf(_T("Making TRACEKMP_TRACE_EVENT ioctl to log events\n")); + if (DeviceIoControl( + hDevice, // handle to a device, file, or directory + IOCTL_TRACEKMP_TRACE_EVENT, // control code of operation to perform + NULL, // pointer to buffer to supply input data + 0, // size, in bytes, of input buffer + dwOutBuffer, // pointer to buffer to receive output data + 2048, // size, in bytes, of output buffer + &dwOutBufferCount, // pointer to variable to receive byte count + NULL // pointer to structure for asynchronous operation + ) == 0) { + + _tprintf(_T("DeviceIOControl Failed %d\n"),GetLastError()); + return 5; + + } + ch = _getche(); + } + + if (CloseHandle(hDevice) == 0) { + + _tprintf(_T("CloseHandle Failed %d\n"),GetLastError()); + return 6; + + } + + // + // stop the driver + // + + ManageDriver(DRIVER_NAME, + driverLocation, + DRIVER_FUNC_REMOVE + ); + + _tprintf(_T("Driver '%s' is removed\n"), DRIVER_NAME); + + return 0; +} + +BOOLEAN +SetupDriverName( + _Out_writes_(MAX_PATH) LPTSTR DriverLocation + ) +{ + HANDLE fileHandle; + + DWORD driverLocLen = 0; + + // + // Get the current directory. + // + + driverLocLen = GetCurrentDirectory(MAX_PATH, + DriverLocation + ); + + if (!driverLocLen) { + + _tprintf(_T("GetCurrentDirectory failed! Error = %d \n"), GetLastError()); + + return FALSE; + } + + // + // Setup path name to driver file. + // + + if (StringCchPrintf(&DriverLocation[_tcslen(DriverLocation)], + (MAX_PATH - _tcslen(DriverLocation)), + _T("\\%s.sys"), + DRIVER_NAME) != S_OK){ + _tprintf(_T("Failed to generate DriverLocation!, StringCchPrintf Error = %d \n"), GetLastError()); + return FALSE; + } + + // + // Insure driver file is in the specified directory. + // + + if ((fileHandle = CreateFile(DriverLocation, + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + + + _tprintf(_T("Driver: '%s' is not in the current directory. \n"), DRIVER_NAME); + + // + // Indicate failure. + // + + return FALSE; + } + + // + // Close open file handle. + // + + if (fileHandle) { + + CloseHandle(fileHandle); + } + + // + // Indicate success. + // + + return TRUE; + + +} // SetupDriverName diff --git a/general/tracing/tracedriver/tracectl/tracectl.vcxproj b/general/tracing/tracedriver/tracectl/tracectl.vcxproj new file mode 100644 index 00000000..e1e21430 --- /dev/null +++ b/general/tracing/tracedriver/tracectl/tracectl.vcxproj @@ -0,0 +1,152 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{72739B3A-9B9B-41EE-9B0E-E73482470A03}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{707AFE5D-65EB-4AED-967A-114E753D1037}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType /> + <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset> + <ConfigurationType>Application</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>tracectl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>tracectl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>tracectl</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>tracectl</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.;..\tracedrv</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="install.c" /> + <ClCompile Include="tracectl.c" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters b/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters new file mode 100644 index 00000000..49a76abb --- /dev/null +++ b/general/tracing/tracedriver/tracectl/tracectl.vcxproj.Filters @@ -0,0 +1,25 @@ +<?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>{162117FB-9571-483E-8BDC-60E6A31AD53D}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{ECB2DAEF-8542-46F3-84A4-AB8FC5EDC817}</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>{CD34668D-32E2-4A6E-8DC5-7CCC09E3FC35}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="install.c"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="tracectl.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/tracing/tracedriver/tracedrv.sln b/general/tracing/tracedriver/tracedrv.sln new file mode 100644 index 00000000..b75b8638 --- /dev/null +++ b/general/tracing/tracedriver/tracedrv.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracectl", "Tracectl", "{F3C08B55-33D7-458F-BE79-6878512FF1B1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tracedrv", "Tracedrv", "{93C02447-AFF7-40E8-AED1-849588063150}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracectl", "tracectl\tracectl.vcxproj", "{72739B3A-9B9B-41EE-9B0E-E73482470A03}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracedrv", "tracedrv\tracedrv.vcxproj", "{959FDB65-EF62-4ED3-8856-326B5AD4BB41}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|Win32.ActiveCfg = Debug|Win32 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|Win32.Build.0 = Debug|Win32 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|Win32.ActiveCfg = Release|Win32 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|Win32.Build.0 = Release|Win32 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|x64.ActiveCfg = Debug|x64 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Debug|x64.Build.0 = Debug|x64 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|x64.ActiveCfg = Release|x64 + {72739B3A-9B9B-41EE-9B0E-E73482470A03}.Release|x64.Build.0 = Release|x64 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|Win32.ActiveCfg = Debug|Win32 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|Win32.Build.0 = Debug|Win32 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|Win32.ActiveCfg = Release|Win32 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|Win32.Build.0 = Release|Win32 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|x64.ActiveCfg = Debug|x64 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Debug|x64.Build.0 = Debug|x64 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|x64.ActiveCfg = Release|x64 + {959FDB65-EF62-4ED3-8856-326B5AD4BB41}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {72739B3A-9B9B-41EE-9B0E-E73482470A03} = {F3C08B55-33D7-458F-BE79-6878512FF1B1} + {959FDB65-EF62-4ED3-8856-326B5AD4BB41} = {93C02447-AFF7-40E8-AED1-849588063150} + EndGlobalSection +EndGlobal diff --git a/general/tracing/tracedriver/tracedrv/drvioctl.h b/general/tracing/tracedriver/tracedrv/drvioctl.h new file mode 100644 index 00000000..d4b84cdf --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/drvioctl.h @@ -0,0 +1,34 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + drvioctl.h + +Abstract: + + Definitions of IOCTL codes and data structures exported by TRACEDRV. + + +--*/ + +#ifndef __TRACEKMP_IOCTL__ +#define __TRACEKMP_IOCTL__ + +// +// IOCTL control codes +// +#define IOCTL_TRACEKMP_TRACE_EVENT \ + CTL_CODE( FILE_DEVICE_UNKNOWN, 0x801, \ + METHOD_BUFFERED, FILE_ANY_ACCESS ) + +#endif // __TRACEKMP_IOCTL__ + + diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.c b/general/tracing/tracedriver/tracedrv/tracedrv.c new file mode 100644 index 00000000..a1606f7b --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.c @@ -0,0 +1,379 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + tracedrv.c + +Abstract: + + Sample kernel mode trace provider/driver. + +--*/ +#include <stdio.h> +#include <ntddk.h> +#include "drvioctl.h" +#include "tracedrv.h" +#include "tracedrv.tmh" // this is the file that will be auto generated + + +DRIVER_UNLOAD TracedrvDriverUnload; + +_Dispatch_type_(IRP_MJ_CREATE) +_Dispatch_type_(IRP_MJ_CLOSE) +DRIVER_DISPATCH TracedrvDispatchOpenClose; + +_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) +DRIVER_DISPATCH TracedrvDispatchDeviceControl; + +VOID +TraceEventLogger( + IN PTRACEHANDLE pLoggerHandle + ); + + +DRIVER_INITIALIZE DriverEntry; +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +TracedrvDispatchOpenClose( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ); + +NTSTATUS +TracedrvDispatchDeviceControl( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ); + +VOID +TracedrvDriverUnload( + IN PDRIVER_OBJECT DriverObject + ); + + +#ifdef ALLOC_PRAGMA + #pragma alloc_text( INIT, DriverEntry ) + #pragma alloc_text( PAGE, TracedrvDispatchOpenClose ) + #pragma alloc_text( PAGE, TracedrvDispatchDeviceControl ) + #pragma alloc_text( PAGE, TracedrvDriverUnload ) +#endif // ALLOC_PRAGMA + + +#define MAXEVENTS 3 + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + DriverObject - pointer to the driver object + RegistryPath - pointer to a unicode string representing the path + to driver-specific key in the registry + +Return Value: + + STATUS_SUCCESS if successful + STATUS_UNSUCCESSFUL otherwise + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + UNICODE_STRING deviceName; + UNICODE_STRING linkName; + PDEVICE_OBJECT pTracedrvDeviceObject; + + + KdPrint(("TraceDrv: DriverEntry\n")); + + // + // Create Dispatch Entry Points. + // + DriverObject->DriverUnload = TracedrvDriverUnload; + DriverObject->MajorFunction[ IRP_MJ_CREATE ] = TracedrvDispatchOpenClose; + DriverObject->MajorFunction[ IRP_MJ_CLOSE ] = TracedrvDispatchOpenClose; + DriverObject->MajorFunction[ IRP_MJ_DEVICE_CONTROL ] = TracedrvDispatchDeviceControl; + + // + // include this macro to support Win2K. + // + WPP_SYSTEMCONTROL(DriverObject); + + + + RtlInitUnicodeString( &deviceName, TRACEDRV_NT_DEVICE_NAME ); + + // + // Create the Device object + // + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &pTracedrvDeviceObject); + + if ( !NT_SUCCESS( status )) { + return status; + } + + RtlInitUnicodeString( &linkName, TRACEDRV_WIN32_DEVICE_NAME ); + status = IoCreateSymbolicLink( &linkName, &deviceName ); + + if ( !NT_SUCCESS( status )) { + IoDeleteDevice( pTracedrvDeviceObject ); + return status; + } + + + // + // Choose a buffering mechanism + // + pTracedrvDeviceObject->Flags |= DO_BUFFERED_IO; + + + // + // This macro is required to initialize software tracing. + // + // Win2K use the deviceobject as the first argument. + // + // XP and beyond does not require device object. First argument + // is ignored. + // + WPP_INIT_TRACING(pTracedrvDeviceObject,RegistryPath); + + + return STATUS_SUCCESS; +} + +NTSTATUS +TracedrvDispatchOpenClose( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ) +/*++ + +Routine Description: + + Dispatch routine to handle Create/Close IRPs. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT status code + +--*/ +{ + + UNREFERENCED_PARAMETER(pDO); + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + PAGED_CODE(); + + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + return STATUS_SUCCESS; +} + + +NTSTATUS +TracedrvDispatchDeviceControl( + IN PDEVICE_OBJECT pDO, + IN PIRP Irp + ) +/*++ + +Routine Description: + + Dispatch routine to handle IOCTL IRPs. + +Arguments: + + DeviceObject - pointer to a device object. + + Irp - pointer to an I/O Request Packet. + +Return Value: + + NT status code + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation( Irp ); + ULONG ControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; + ULONG i=0; + static ULONG ioctlCount = 0; + MachineState CurrentState = Offline; + + + PAGED_CODE(); + UNREFERENCED_PARAMETER(pDO); + + Irp->IoStatus.Information = + irpStack->Parameters.DeviceIoControl.OutputBufferLength; + + switch ( ControlCode ) { + case IOCTL_TRACEKMP_TRACE_EVENT: + // + // Every time we get this IOCTL, we also log a trace Message if + // Trace flag one is enabled. This is used + // to illustrate that the event can be caused by user-mode. + // + + ioctlCount++; + + // + // Log a simple Message + // + + DoTraceMessage(FLAG_ONE, "IOCTL = %d", ioctlCount); + + while (i++ < MAXEVENTS) { + // + // Trace events in a loop. + // + DoTraceMessage(FLAG_ONE, "Hello, %d %s", i, "Hi" ); + + if ( !(i%MAXEVENTS)){ + // + // Trace if level >=2 and 2 bit set by -level 2 -flags 2 in tracelog + // Uses the format string for the defined enum MachineState in the + // scanned header file + // + DoTraceLevelMessage( + TRACE_LEVEL_ERROR, // ETW Level defined in evntrace.h + FLAG_TWO, // Flag defined in WPP_CONTROL_GUIDS + "Machine State :: %!state!", + CurrentState // enum parameter + ); + } + } + + // + // Set a fake error status to fire the TRACE_RETURN macro below + // + status = STATUS_DEVICE_POWERED_OFF; + + Irp->IoStatus.Information = 0; + break; + + // + // Not one we recognize. Error. + // + default: + status = STATUS_INVALID_PARAMETER; + Irp->IoStatus.Information = 0; + break; + } + + // + // Trace the return status using the TRACE_RETURN macro wich includes PRE/POST + // macros. The value could be either the fake error or invalid parameter + // + TRACE_RETURN(status); + + if (status != STATUS_INVALID_PARAMETER) { + // + // Set the status back to success + // + status = STATUS_SUCCESS; + } + + // + // Get rid of this request + // + Irp->IoStatus.Status = status; + IoCompleteRequest( Irp, IO_NO_INCREMENT ); + + return status; +} + + +VOID +TracedrvDriverUnload( + IN PDRIVER_OBJECT DriverObject + ) +/*++ + +Routine Description: + + Free all the resources allocated in DriverEntry. + +Arguments: + + DriverObject - pointer to a driver object. + +Return Value: + + VOID. + +--*/ +{ + PDEVICE_OBJECT pDevObj; + UNICODE_STRING linkName; + + + PAGED_CODE(); + + KdPrint(("TraceDrv: Unloading \n")); + + // + // Get pointer to Device object + // + pDevObj = DriverObject->DeviceObject; + + // + // Cleanup using DeviceObject on Win2K. Make sure + // this is same deviceobject that used for initializing. + // On XP the Parameter is ignored + WPP_CLEANUP(pDevObj); + + // + // Form the Win32 symbolic link name. + // + RtlInitUnicodeString( &linkName, TRACEDRV_WIN32_DEVICE_NAME ); + + // + // Remove symbolic link from Object + // namespace... + // + IoDeleteSymbolicLink( &linkName ); + + // + // Unload the callbacks from the kernel to this driver + // + IoDeleteDevice( pDevObj ); + +} + + diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.ctl b/general/tracing/tracedriver/tracedrv/tracedrv.ctl new file mode 100644 index 00000000..c5ff6bef --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.ctl @@ -0,0 +1 @@ +d58c126f-b309-11d1-969e-0000f875a5bc CtlGuid
\ No newline at end of file diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.h b/general/tracing/tracedriver/tracedrv/tracedrv.h new file mode 100644 index 00000000..1b86834a --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.h @@ -0,0 +1,113 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + tracedrv.h + +Abstract: + + tracedrv.h defines: + - The provider GUID for the driver. + - Macros for tracing with levels and flags + - Tracing enumerations using custom type + - Trace macro that incorporates PRE/POST macros + +Environment: + + Kernel mode + +--*/ + + +#define TRACEDRV_NT_DEVICE_NAME L"\\Device\\TraceKmp" +#define TRACEDRV_WIN32_DEVICE_NAME L"\\DosDevices\\TRACEKMP" + +// +// Software Tracing Definitions +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID(CtlGuid,(d58c126f, b309, 11d1, 969e, 0000f875a5bc), \ + WPP_DEFINE_BIT(FLAG_ONE) \ + WPP_DEFINE_BIT(FLAG_TWO) ) + +// +// DoTraceLevelMessage is a custom macro that adds support for levels to the +// default DoTraceMessage, which supports only flags. In this version, both +// flags and level are conditions for generating the trace message. +// The preprocessor is told to recognize the function by using the -func argument +// in the RUN_WPP line on the source file. In the source file you will find +// -func:DoTraceLevelMessage(LEVEL,FLAGS,MSG,...). The conditions for triggering +// this event in the macro are the Levels defined in evntrace.h and the flags +// defined above and are evaluated by the macro WPP_LEVEL_FLAGS_ENABLED below. +// +#define WPP_LEVEL_FLAGS_LOGGER(level,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_LEVEL_FLAGS_ENABLED(level, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= level) + +typedef enum _MachineState { + Offline = 2, + Online = 1, + Failed = 0xFF000001, + Stalled = 0xFF000002 +} MachineState; +// +// Configuration block to scan the enumeration definition MachineState. Used when +// viewing the trace to display names instead of the integer values that users must decode +// +// begin_wpp config +// CUSTOM_TYPE(state, ItemEnum(_MachineState)); +// end_wpp + + +// MACRO: TRACE_RETURN +// Configuration block that defines trace macro. It uses the PRE/POST macros to include +// code as part of the trace macro expansion. TRACE_MACRO is equivalent to the code below: +// +// {if (Status != STATUS_SUCCESS){ // This is the code in the PRE macro +// DoTraceMessage(FLAG_ONE, "Function Return = %!STATUS!", Status) +// ;}} // This is the code in the POST macro +// +// +// USEPREFIX statement: Defines a format string prefix to be used when logging the event, +// below the STDPREFIX is used. The first value is the trace function name with out parenthesis +// and the second value is the format string to be used. +// +// USESUFFIX statement: Defines a suffix format string that gets logged with the event. +// +// FUNC statement: Defines the name and signature of the trace function. The function defined +// below takes one argument, no format string, and predefines the flag equal to FLAG_ONE. +// +// +//begin_wpp config +//USEPREFIX (TRACE_RETURN, "%!STDPREFIX!"); +//FUNC TRACE_RETURN{FLAG=FLAG_ONE}(EXP); +//USESUFFIX (TRACE_RETURN, "Function Return=%!STATUS!",EXP); +//end_wpp + +// +// PRE macro: The name of the macro includes the condition arguments FLAGS and EXP +// define in FUNC above +// +#define WPP_FLAG_EXP_PRE(FLAGS, HR) {if (HR != STATUS_SUCCESS) { + +// +// POST macro +// The name of the macro includes the condition arguments FLAGS and EXP +// define in FUNC above +#define WPP_FLAG_EXP_POST(FLAGS, HR) ;}} + +// +// The two macros below are for checking if the event should be logged and for +// choosing the logger handle to use when calling the ETW trace API +// +#define WPP_FLAG_EXP_ENABLED(FLAGS, HR) WPP_FLAG_ENABLED(FLAGS) +#define WPP_FLAG_EXP_LOGGER(FLAGS, HR) WPP_FLAG_LOGGER(FLAGS) + + diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.rc b/general/tracing/tracedriver/tracedrv/tracedrv.rc new file mode 100644 index 00000000..88c83ddc --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.rc @@ -0,0 +1,28 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + tracedrv.rc + +--*/ + +#include <windows.h> +#include <ntverp.h> +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Trace Kernel Mode Driver" +#define VER_INTERNALNAME_STR "tracedrv.sys" +#define VER_ORIGINALFILENAME_STR "tracedrv.sys" + +#include "common.ver" + +LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL + diff --git a/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj new file mode 100644 index 00000000..febcbdd7 --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj @@ -0,0 +1,164 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{959FDB65-EF62-4ED3-8856-326B5AD4BB41}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{01308CF4-AB44-4626-BACF-D0555BC457DF}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>WDM</DriverType> + <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset> + <ConfigurationType>Driver</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="tracedrv.c"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>DoTraceLevelMessage(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppScanConfigurationData>tracedrv.h</WppScanConfigurationData> + </ClCompile> + <OtherWpp Include="tracedrv.rc"> + <WppEnabled>true</WppEnabled> + <WppKernelMode>true</WppKernelMode> + <WppTraceFunction>DoTraceLevelMessage(LEVEL,FLAGS,MSG,...)</WppTraceFunction> + <WppScanConfigurationData>tracedrv.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>tracedrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>tracedrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>tracedrv</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>tracedrv</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ResourceCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ResourceCompile> + <ClCompile> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </ClCompile> + <Midl> + <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);.</AdditionalIncludeDirectories> + </Midl> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="tracedrv.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters new file mode 100644 index 00000000..029e408d --- /dev/null +++ b/general/tracing/tracedriver/tracedrv/tracedrv.vcxproj.Filters @@ -0,0 +1,31 @@ +<?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>{91F6D41E-6246-46E8-99D5-002ACC23AA49}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{DF6424D7-7A22-42ED-B11F-508DD7CA41CD}</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>{A42F3913-01F8-47A1-B888-182B29B1B137}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{EC7A4F43-C45A-4AAA-97BC-DFDF6C41C75C}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="tracedrv.c"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="tracedrv.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/umdfSkeleton/ReadMe.md b/general/umdfSkeleton/ReadMe.md new file mode 100644 index 00000000..923f44df --- /dev/null +++ b/general/umdfSkeleton/ReadMe.md @@ -0,0 +1,7 @@ +UMDF Driver Skeleton Sample (UMDF Version 1) +============================================ + +This sample demonstrates how to use version 1 of the User-Mode Driver Framework to write a minimal driver. + +The Skeleton driver will successfully load on a device (either root enumerated or a real hardware device) but does not support any I/O operations. + diff --git a/general/umdfSkeleton/Skeleton.rc b/general/umdfSkeleton/Skeleton.rc new file mode 100644 index 00000000..b6ecda7f --- /dev/null +++ b/general/umdfSkeleton/Skeleton.rc @@ -0,0 +1,21 @@ +//--------------------------------------------------------------------------- +// Skeleton.rc +// +// Copyright (c) Microsoft Corporation, All Rights Reserved +//--------------------------------------------------------------------------- + + +#include <windows.h> +#include <ntverp.h> + +// +// TODO: Change the file description and file names to match your binary. +// + +#define VER_FILETYPE VFT_DLL +#define VER_FILESUBTYPE VFT_UNKNOWN +#define VER_FILEDESCRIPTION_STR "WDF:UMDF Skeleton User-Mode Driver Sample" +#define VER_INTERNALNAME_STR "UMDFSkeleton" +#define VER_ORIGINALFILENAME_STR "UMDFSkeleton.dll" + +#include "common.ver" diff --git a/general/umdfSkeleton/UMDFSkeleton.vcxproj b/general/umdfSkeleton/UMDFSkeleton.vcxproj new file mode 100644 index 00000000..947c3517 --- /dev/null +++ b/general/umdfSkeleton/UMDFSkeleton.vcxproj @@ -0,0 +1,264 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{A0B8804E-85A9-4432-A812-E9F6947C647A}</ProjectGuid> + <RootNamespace>$(MSBuildProjectName)</RootNamespace> + <UMDF_VERSION_MAJOR>1</UMDF_VERSION_MAJOR> + <KMDF_VERSION_MAJOR>1</KMDF_VERSION_MAJOR> + <UMDF_VERSION_MINOR>9</UMDF_VERSION_MINOR> + <KMDF_VERSION_MINOR>9</KMDF_VERSION_MINOR> + <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <SampleGuid>{A084ACA0-8591-462C-A3F8-EB936C200BCA}</SampleGuid> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>False</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetVersion>Windows10</TargetVersion> + <UseDebugLibraries>True</UseDebugLibraries> + <DriverTargetPlatform>Desktop</DriverTargetPlatform> + <DriverType>UMDF</DriverType> + <PlatformToolset>WindowsUserModeDriver10.0</PlatformToolset> + <ConfigurationType>DynamicLibrary</ConfigurationType> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <PropertyGroup> + <OutDir>$(IntDir)</OutDir> + </PropertyGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" /> + </ImportGroup> + <ItemGroup Label="WrappedTaskItems"> + <ClCompile Include="dllsup.cpp; comsup.cpp; driver.cpp; device.cpp"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </ClCompile> + <Inf Include="UMDFSkeleton_OSR.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\UMDFSkeleton_OSR.inf</CopyOutput> + </Inf> + <Inf Include="UMDFSkeleton_Root.inx"> + <Architecture>$(InfArch)</Architecture> + <SpecifyArchitecture>true</SpecifyArchitecture> + <CopyOutput>.\$(IntDir)\UMDFSkeleton_Root.inf</CopyOutput> + </Inf> + <OtherWpp Include="Skeleton.rc"> + <WppEnabled>true</WppEnabled> + <WppDllMacro>true</WppDllMacro> + <WppScanConfigurationData>internal.h</WppScanConfigurationData> + </OtherWpp> + </ItemGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <TargetName>UMDFSkeleton</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <TargetName>UMDFSkeleton</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <TargetName>UMDFSkeleton</TargetName> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <TargetName>UMDFSkeleton</TargetName> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ClCompile> + <Midl> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </Midl> + <ResourceCompile> + <PreprocessorDefinitions>%(PreprocessorDefinitions);_UNICODE;UNICODE</PreprocessorDefinitions> + </ResourceCompile> + </ItemDefinitionGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <WIN32_WINNT_VERSION>0x0A00</WIN32_WINNT_VERSION> + <NTDDI_VERSION>0x0A000000</NTDDI_VERSION> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Link> + <EntryPointSymbol Condition="'$(Platform)'=='win32'">_DllMainCRTStartup@12</EntryPointSymbol> + <EntryPointSymbol Condition="'$(Platform)'!='win32'">_DllMainCRTStartup</EntryPointSymbol> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <TreatWarningAsError>true</TreatWarningAsError> + <WarningLevel>Level4</WarningLevel> + <ExceptionHandling> + </ExceptionHandling> + </ClCompile> + <Link> + <AdditionalDependencies>%(AdditionalDependencies);$(SDK_LIB_PATH)\strsafe.lib;$(SDK_LIB_PATH)\kernel32.lib;$(SDK_LIB_PATH)\advapi32.lib</AdditionalDependencies> + <ModuleDefinitionFile>exports.def</ModuleDefinitionFile> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ResourceCompile Include="Skeleton.rc" /> + </ItemGroup> + <ItemGroup> + <Inf Exclude="@(Inf)" Include="*.inf" /> + <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" /> + <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" /> + </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/umdfSkeleton/UMDFSkeleton.vcxproj.Filters b/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters new file mode 100644 index 00000000..da7d8ca7 --- /dev/null +++ b/general/umdfSkeleton/UMDFSkeleton.vcxproj.Filters @@ -0,0 +1,57 @@ +<?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>{16B2A720-AEC4-4627-959C-8A289CB6F699}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files"> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + <UniqueIdentifier>{F54667DA-A0EB-4C54-92C9-9D2E3B44E169}</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>{949A3C23-B62C-4219-A44F-CF5DBE78DD73}</UniqueIdentifier> + </Filter> + <Filter Include="Driver Files"> + <Extensions>inf;inv;inx;mof;mc;</Extensions> + <UniqueIdentifier>{DDA0FB16-FA5D-4FB7-8EE6-DB37C36326C6}</UniqueIdentifier> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="comsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="device.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="dllsup.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <None Include="exports.def"> + <Filter>Source Files</Filter> + </None> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include=".\Debug\\UMDFSkeleton_OSR.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <FilesToPackage Include=".\Debug\\UMDFSkeleton_Root.inf"> + <Filter>Driver Files</Filter> + </FilesToPackage> + <Inf Include="UMDFSkeleton_OSR.inx"> + <Filter>Driver Files</Filter> + </Inf> + <Inf Include="UMDFSkeleton_Root.inx"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="Skeleton.rc"> + <Filter>Resource Files</Filter> + </ResourceCompile> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/general/umdfSkeleton/UMDFSkeleton_OSR.inx b/general/umdfSkeleton/UMDFSkeleton_OSR.inx new file mode 100644 index 00000000..4da9c3f9 --- /dev/null +++ b/general/umdfSkeleton/UMDFSkeleton_OSR.inx @@ -0,0 +1,96 @@ +; UMDFSkeleton_OSR.inf - Install the Skeleton driver on the OSR USB device +; + +[Version] +Signature="$Windows NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFTUMDF% +DriverVer=03/25/2005,0.0.0.1 +CatalogFile=wudf.cat + +[Manufacturer] +%MSFTUMDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%SkeletonDeviceName%=Skeleton_Install, USB\Vid_045e&Pid_94aa&mi_00 +%SkeletonDeviceName%=Skeleton_Install, USB\VID_0547&PID_1002 + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +UMDFSkeleton.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== UMDF Skeleton Device ================================== + +[Skeleton_Install.NT] +CopyFiles=UMDriverCopy +Include=WINUSB.INF ; Import sections from WINUSB.INF +Needs=WINUSB.NT ; Run the CopyFiles & AddReg directives for WinUsb.INF + +[Skeleton_Install.NT.hw] +AddReg=Skeleton_Device_AddReg + +[Skeleton_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall ; flag 0x2 sets this as the service for the device +AddService=WinUsb,0x000001f8,WinUsb_ServiceInstall ; this service is installed because its a filter. + +[Skeleton_Install.NT.CoInstallers] +AddReg=CoInstallers_AddReg + +[Skeleton_Install.NT.Wdf] +KmdfService = WINUSB, WinUsb_Install +UmdfService = UMDFSkeleton, UMDFSkeleton_Install +UmdfServiceOrder = UMDFSkeleton + +[WinUsb_Install] +KmdfLibraryVersion = $KMDFVERSION$ + +[UMDFSkeleton_Install] +UmdfLibraryVersion=$UMDFVERSION$ +DriverCLSID="{d4112073-d09b-458f-a5aa-35ef21eef5de}" +ServiceBinary="%12%\umdf\UMDFSkeleton.dll" + +[Skeleton_Device_AddReg] +HKR,,"LowerFilters",0x00010008,"WinUsb" ; FLG_ADDREG_TYPE_MULTI_SZ | FLG_ADDREG_APPEND + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[WinUsb_ServiceInstall] +DisplayName = %WinUsb_SvcDesc% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WinUSB.sys + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll" + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to drivers/umdf + +[UMDriverCopy] +UMDFSkeleton.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +; =================== Generic ================================== + +[Strings] +MSFTUMDF="Microsoft Internal (WDF:UMDF)" +MediaDescription="Microsoft Sample Driver Installation Media" +ClassName="Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +SkeletonDeviceName="Microsoft Skeleton User-Mode Driver on OSR USB Device Sample" +WinUsb_SvcDesc="WinUSB Driver" diff --git a/general/umdfSkeleton/UMDFSkeleton_Root.inx b/general/umdfSkeleton/UMDFSkeleton_Root.inx new file mode 100644 index 00000000..22b5459a --- /dev/null +++ b/general/umdfSkeleton/UMDFSkeleton_Root.inx @@ -0,0 +1,77 @@ +; +; UMDFSkeleton_Root.inf +; + +[Version] +Signature="$Windows NT$" +Class=Sample +ClassGuid={78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider=%MSFTUMDF% +CatalogFile=WUDF.cat +DriverVer=03/25/2005,0.0.0.1 + +[Manufacturer] +%MSFTUMDF%=Microsoft,NT$ARCH$ + +[Microsoft.NT$ARCH$] +%SkeletonDeviceName%=Skeleton_Install,UMDFSamples\Skeleton + +[ClassInstall32] +AddReg=SampleClass_RegistryAdd + +[SampleClass_RegistryAdd] +HKR,,,,%ClassName% +HKR,,Icon,,"-10" + +[SourceDisksFiles] +UMDFSkeleton.dll=1 + +[SourceDisksNames] +1 = %MediaDescription% + +; =================== UMDF Skeleton Device ================================== + +[Skeleton_Install.NT] +CopyFiles=UMDriverCopy + +[Skeleton_Install.NT.hw] + +[Skeleton_Install.NT.Services] +AddService=WUDFRd,0x000001fa,WUDFRD_ServiceInstall + +[Skeleton_Install.NT.CoInstallers] +AddReg=CoInstallers_AddReg + +[Skeleton_Install.NT.Wdf] +UmdfService=UMDFSkeleton,UMDFSkeleton_Install +UmdfServiceOrder=UMDFSkeleton + +[UMDFSkeleton_Install] +UmdfLibraryVersion=$UMDFVERSION$ +ServiceBinary=%12%\UMDF\UMDFSkeleton.dll +DriverCLSID={d4112073-d09b-458f-a5aa-35ef21eef5de} + +[WUDFRD_ServiceInstall] +DisplayName = %WudfRdDisplayName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\WUDFRd.sys + +[CoInstallers_AddReg] +HKR,,CoInstallers32,0x00010000,"WUDFCoinstaller.dll" + +[DestinationDirs] +UMDriverCopy=12,UMDF ; copy to driversMdf + +[UMDriverCopy] +UMDFSkeleton.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME + +; =================== Generic ================================== + +[Strings] +MSFTUMDF="Microsoft Internal (WDF:UMDF)" +MediaDescription="Microsoft Sample Driver Installation Media" +ClassName="Sample Device" +WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector" +SkeletonDeviceName="Microsoft Skeleton User-Mode Device Sample" diff --git a/general/umdfSkeleton/comsup.cpp b/general/umdfSkeleton/comsup.cpp new file mode 100644 index 00000000..fd298470 --- /dev/null +++ b/general/umdfSkeleton/comsup.cpp @@ -0,0 +1,344 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.cpp + +Abstract: + + This module contains implementations for the functions and methods + used for providing COM support. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" + +#include "comsup.tmh" + +// +// Implementation of CUnknown methods. +// + +CUnknown::CUnknown( + VOID + ) : m_ReferenceCount(1) +/*++ + + Routine Description: + + Constructor for an instance of the CUnknown class. This simply initializes + the reference count of the object to 1. The caller is expected to + call Release() if it wants to delete the object once it has been allocated. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + // do nothing. +} + +HRESULT +STDMETHODCALLTYPE +CUnknown::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method provides the basic support for query interface on CUnknown. + If the interface requested is IUnknown it references the object and + returns an interface pointer. Otherwise it returns an error. + + Arguments: + + InterfaceId - the IID being requested + + Object - a location to store the interface pointer to return. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IUnknown))) + { + *Object = QueryIUnknown(); + return S_OK; + } + else + { + *Object = NULL; + return E_NOINTERFACE; + } +} + +IUnknown * +CUnknown::QueryIUnknown( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IUnknown interface. + + This allows other methods to convert a CUnknown pointer into an IUnknown + pointer without a typecast and without calling QueryInterface and dealing + with the return value. + + Arguments: + + None + + Return Value: + + A pointer to the object's IUnknown interface. + +--*/ +{ + AddRef(); + return static_cast<IUnknown *>(this); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::AddRef( + VOID + ) +/*++ + + Routine Description: + + This method adds one to the object's reference count. + + Arguments: + + None + + Return Value: + + The new reference count. The caller should only use this for debugging + as the object's actual reference count can change while the caller + examines the return value. + +--*/ +{ + return InterlockedIncrement(&m_ReferenceCount); +} + +ULONG +STDMETHODCALLTYPE +CUnknown::Release( + VOID + ) +/*++ + + Routine Description: + + This method subtracts one to the object's reference count. If the count + goes to zero, this method deletes the object. + + Arguments: + + None + + Return Value: + + The new reference count. If the caller uses this value it should only be + to check for zero (i.e. this call caused or will cause deletion) or + non-zero (i.e. some other call may have caused deletion, but this one + didn't). + +--*/ +{ + ULONG count = InterlockedDecrement(&m_ReferenceCount); + + if (count == 0) + { + delete this; + } + return count; +} + +// +// Implementation of CClassFactory methods. +// + +// +// Define storage for the factory's static lock count variable. +// + +LONG CClassFactory::s_LockCount = 0; + +IClassFactory * +CClassFactory::QueryIClassFactory( + VOID + ) +/*++ + + Routine Description: + + This helper method references the object and returns a pointer to the + object's IClassFactory interface. + + This allows other methods to convert a CClassFactory pointer into an + IClassFactory pointer without a typecast and without dealing with the + return value QueryInterface. + + Arguments: + + None + + Return Value: + + A referenced pointer to the object's IClassFactory interface. + +--*/ +{ + AddRef(); + return static_cast<IClassFactory *>(this); +} + +HRESULT +CClassFactory::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method attempts to retrieve the requested interface from the object. + + If the interface is found then the reference count on that interface (and + thus the object itself) is incremented. + + Arguments: + + InterfaceId - the interface the caller is requesting. + + Object - a location to store the interface pointer. + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + // + // This class only supports IClassFactory so check for that. + // + + if (IsEqualIID(InterfaceId, __uuidof(IClassFactory))) + { + *Object = QueryIClassFactory(); + return S_OK; + } + else + { + // + // See if the base class supports the interface. + // + + return CUnknown::QueryInterface(InterfaceId, Object); + } +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::CreateInstance( + _In_opt_ IUnknown * /* OuterObject */, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This COM method is the factory routine - it creates instances of the driver + callback class and returns the specified interface on them. + + Arguments: + + OuterObject - only used for aggregation, which our driver callback class + does not support. + + InterfaceId - the interface ID the caller would like to get from our + new object. + + Object - a location to store the referenced interface pointer to the new + object. + + Return Value: + + Status. + +--*/ +{ + HRESULT hr; + + PCMyDriver driver; + + *Object = NULL; + + hr = CMyDriver::CreateInstance(&driver); + + if (SUCCEEDED(hr)) + { + hr = driver->QueryInterface(InterfaceId, Object); + driver->Release(); + } + + return hr; +} + +HRESULT +STDMETHODCALLTYPE +CClassFactory::LockServer( + _In_ BOOL Lock + ) +/*++ + + Routine Description: + + This COM method can be used to keep the DLL in memory. However since the + driver's DllCanUnloadNow function always returns false, this has little + effect. Still it tracks the number of lock and unlock operations. + + Arguments: + + Lock - Whether the caller wants to lock or unlock the "server" + + Return Value: + + S_OK + +--*/ +{ + if (Lock) + { + InterlockedIncrement(&s_LockCount); + } + else + { + InterlockedDecrement(&s_LockCount); + } + return S_OK; +} + diff --git a/general/umdfSkeleton/comsup.h b/general/umdfSkeleton/comsup.h new file mode 100644 index 00000000..5472338c --- /dev/null +++ b/general/umdfSkeleton/comsup.h @@ -0,0 +1,215 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + ComSup.h + +Abstract: + + This module contains classes and functions use for providing COM support + code. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Forward type declarations. They are here rather than in internal.h as +// you only need them if you choose to use these support classes. +// + +typedef class CUnknown *PCUnknown; +typedef class CClassFactory *PCClassFactory; + +// +// Base class to implement IUnknown. You can choose to derive your COM +// classes from this class, or simply implement IUnknown in each of your +// classes. +// + +class CUnknown : public IUnknown +{ + +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The reference count for this object. Initialized to 1 in the + // constructor. + // + + LONG m_ReferenceCount; + +// +// Protected data members and methods. These are accessible by the subclasses +// but not by other classes. +// +protected: + + // + // The constructor and destructor are protected to ensure that only the + // subclasses of CUnknown can create and destroy instances. + // + + CUnknown( + VOID + ); + + // + // The destructor MUST be virtual. Since any instance of a CUnknown + // derived class should only be deleted from within CUnknown::Release, + // the destructor MUST be virtual or only CUnknown::~CUnknown will get + // invoked on deletion. + // + // If you see that your CMyDevice specific destructor is never being + // called, make sure you haven't deleted the virtual destructor here. + // + + virtual + ~CUnknown( + VOID + ) + { + // Do nothing + } + +// +// Public Methods. These are accessible by any class. +// +public: + + IUnknown * + QueryIUnknown( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ); + + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ); + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; + +// +// Class factory support class. Create an instance of this from your +// DllGetClassObject method and modify the implementation to create +// an instance of your driver event handler class. +// + +class CClassFactory : public CUnknown, public IClassFactory +{ +// +// Private data members and methods. These are only accessible by the methods +// of this class. +// +private: + + // + // The lock count. This is shared across all instances of IClassFactory + // and can be queried through the public IsLocked method. + // + + static LONG s_LockCount; + +// +// Public Methods. These are accessible by any class. +// +public: + + IClassFactory * + QueryIClassFactory( + VOID + ); + +// +// COM Methods. +// +public: + + // + // IUnknown methods + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + // + // IClassFactory methods. + // + + virtual + HRESULT + STDMETHODCALLTYPE + CreateInstance( + _In_opt_ IUnknown *OuterObject, + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + + virtual + HRESULT + STDMETHODCALLTYPE + LockServer( + _In_ BOOL Lock + ); +}; diff --git a/general/umdfSkeleton/device.cpp b/general/umdfSkeleton/device.cpp new file mode 100644 index 00000000..677f39e6 --- /dev/null +++ b/general/umdfSkeleton/device.cpp @@ -0,0 +1,238 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Device.cpp + +Abstract: + + This module contains the implementation of the UMDF Skeleton sample driver's + device callback object. + + The skeleton sample device does very little. It does not implement either + of the PNP interfaces so once the device is setup, it won't ever get any + callbacks until the device is removed. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "device.tmh" + +HRESULT +CMyDevice::CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit, + _Out_ PCMyDevice *Device + ) +/*++ + + Routine Description: + + This method creates and initializs an instance of the skeleton driver's + device callback object. + + Arguments: + + FxDeviceInit - the settings for the device. + + Device - a location to store the referenced pointer to the device object. + + Return Value: + + Status + +--*/ +{ + PCMyDevice device; + HRESULT hr; + + // + // Allocate a new instance of the device class. + // + + device = new CMyDevice(); + + if (NULL == device) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the instance. + // + + hr = device->Initialize(FxDriver, FxDeviceInit); + + if (SUCCEEDED(hr)) + { + *Device = device; + } + else + { + device->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Initialize( + _In_ IWDFDriver * FxDriver, + _In_ IWDFDeviceInitialize * FxDeviceInit + ) +/*++ + + Routine Description: + + This method initializes the device callback object and creates the + partner device object. + + The method should perform any device-specific configuration that: + * could fail (these can't be done in the constructor) + * must be done before the partner object is created -or- + * can be done after the partner object is created and which aren't + influenced by any device-level parameters the parent (the driver + in this case) might set. + + Arguments: + + FxDeviceInit - the settings for this device. + + Return Value: + + status. + +--*/ +{ + IWDFDevice *fxDevice; + HRESULT hr; + + // + // Configure things like the locking model before we go to create our + // partner device. + // + + // + // Set no locking unless you need an automatic callbacks synchronization + // + + FxDeviceInit->SetLockingConstraint(None); + + // + // TODO: If you're writing a filter driver then indicate that here. + // + // FxDeviceInit->SetFilter(); + // + + // + // TODO: Any per-device initialization which must be done before + // creating the partner object. + // + + // + // Create a new FX device object and assign the new callback object to + // handle any device level events that occur. + // + + // + // QueryIUnknown references the IUnknown interface that it returns + // (which is the same as referencing the device). We pass that to + // CreateDevice, which takes its own reference if everything works. + // + + { + IUnknown *unknown = this->QueryIUnknown(); + + hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice); + + unknown->Release(); + } + + // + // If that succeeded then set our FxDevice member variable. + // + + if (SUCCEEDED(hr)) + { + m_FxDevice = fxDevice; + + // + // Drop the reference we got from CreateDevice. Since this object + // is partnered with the framework object they have the same + // lifespan - there is no need for an additional reference. + // + + fxDevice->Release(); + } + + return hr; +} + +HRESULT +CMyDevice::Configure( + VOID + ) +/*++ + + Routine Description: + + This method is called after the device callback object has been initialized + and returned to the driver. It would setup the device's queues and their + corresponding callback objects. + + Arguments: + + FxDevice - the framework device object for which we're handling events. + + Return Value: + + status + +--*/ +{ + // + // TODO: Setup your device queues and I/O forwarding. + // + + return S_OK; +} + +HRESULT +CMyDevice::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ) +/*++ + + Routine Description: + + This method is called to get a pointer to one of the object's callback + interfaces. + + Since the skeleton driver doesn't support any of the device events, this + method simply calls the base class's BaseQueryInterface. + + If the skeleton is extended to include device event interfaces then this + method must be changed to check the IID and return pointers to them as + appropriate. + + Arguments: + + InterfaceId - the interface being requested + + Object - a location to store the interface pointer if successful + + Return Value: + + S_OK or E_NOINTERFACE + +--*/ +{ + return CUnknown::QueryInterface(InterfaceId, Object); +} diff --git a/general/umdfSkeleton/device.h b/general/umdfSkeleton/device.h new file mode 100644 index 00000000..d5e1baa6 --- /dev/null +++ b/general/umdfSkeleton/device.h @@ -0,0 +1,115 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Device.h + +Abstract: + + This module contains the type definitions for the UMDF Skeleton sample + driver's device callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// Class for the iotrace driver. +// + +class CMyDevice : public CUnknown +{ + +// +// Private data members. +// +private: + + IWDFDevice *m_FxDevice; + +// +// Private methods. +// + +private: + + CMyDevice( + VOID + ) + { + m_FxDevice = NULL; + } + + HRESULT + Initialize( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _In_ IWDFDriver *FxDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit, + _Out_ PCMyDevice *Device + ); + + HRESULT + Configure( + VOID + ); + +// +// COM methods +// +public: + + // + // IUnknown methods. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); + +}; diff --git a/general/umdfSkeleton/dllsup.cpp b/general/umdfSkeleton/dllsup.cpp new file mode 100644 index 00000000..3a59f303 --- /dev/null +++ b/general/umdfSkeleton/dllsup.cpp @@ -0,0 +1,177 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + dllsup.cpp + +Abstract: + + This module contains the implementation of the UMDF Skeleton Sample + Driver's entry point and its exported functions for providing COM support. + + This module can be copied without modification to a new UMDF driver. It + depends on some of the code in comsup.cpp & comsup.h to handle DLL + registration and creating the first class factory. + + This module is dependent on the following defines: + + MYDRIVER_TRACING_ID - A wide string passed to WPP when initializing + tracing. For example the skeleton uses + L"Microsoft\\UMDF\\Skeleton" + + MYDRIVER_CLASS_ID - A GUID encoded in struct format used to + initialize the driver's ClassID. + + These are defined in internal.h for the sample. If you choose + to use a different primary include file, you should ensure they are + defined there as well. + +Environment: + + WDF User-Mode Driver Framework (WDF:UMDF) + +--*/ + +#include "internal.h" +#include "dllsup.tmh" + +const GUID CLSID_MyDriverCoClass = MYDRIVER_CLASS_ID; + +BOOL +WINAPI +DllMain( + HINSTANCE ModuleHandle, + DWORD Reason, + PVOID /* Reserved */ + ) +/*++ + + Routine Description: + + This is the entry point and exit point for the I/O trace driver. This + does very little as the I/O trace driver has minimal global data. + + This method initializes tracing. + + Arguments: + + ModuleHandle - the DLL handle for this module. + + Reason - the reason this entry point was called. + + Reserved - unused + + Return Value: + + TRUE + +--*/ +{ + + UNREFERENCED_PARAMETER( ModuleHandle ); + + if (DLL_PROCESS_ATTACH == Reason) + { + // + // Initialize tracing. + // + + WPP_INIT_TRACING(MYDRIVER_TRACING_ID); + + } + else if (DLL_PROCESS_DETACH == Reason) + { + // + // Cleanup tracing. + // + + WPP_CLEANUP(); + } + + return TRUE; +} + +HRESULT +STDAPICALLTYPE +DllGetClassObject( + _In_ REFCLSID ClassId, + _In_ REFIID InterfaceId, + _Outptr_ LPVOID *Interface + ) +/*++ + + Routine Description: + + This routine is called by COM in order to instantiate the + driver callback object and do an initial query interface on it. + + This method only creates an instance of the driver's class factory, as this + is the minimum required to support UMDF. + + Arguments: + + ClassId - the CLSID of the object being "gotten" + + InterfaceId - the interface the caller wants from that object. + + Interface - a location to store the referenced interface pointer + + Return Value: + + S_OK if the function succeeds or error indicating the cause of the + failure. + +--*/ +{ + PCClassFactory factory; + + HRESULT hr = S_OK; + + *Interface = NULL; + + // + // If the CLSID doesn't match that of our "coclass" (defined in the IDL + // file) then we can't create the object the caller wants. This may + // indicate that the COM registration is incorrect, and another CLSID + // is referencing this drvier. + // + + if (IsEqualCLSID(ClassId, CLSID_MyDriverCoClass) == false) + { + Trace( + TRACE_LEVEL_ERROR, + L"ERROR: Called to create instance of unrecognized class (%!GUID!)", + &ClassId + ); + + return CLASS_E_CLASSNOTAVAILABLE; + } + + // + // Create an instance of the class factory for the caller. + // + + factory = new CClassFactory(); + + if (NULL == factory) + { + hr = E_OUTOFMEMORY; + } + + // + // Query the object we created for the interface the caller wants. After + // that we release the object. This will drive the reference count to + // 1 (if the QI succeeded an referenced the object) or 0 (if the QI failed). + // In the later case the object is automatically deleted. + // + + if (SUCCEEDED(hr)) + { + hr = factory->QueryInterface(InterfaceId, Interface); + factory->Release(); + } + + return hr; +} diff --git a/general/umdfSkeleton/driver.cpp b/general/umdfSkeleton/driver.cpp new file mode 100644 index 00000000..2061ec2d --- /dev/null +++ b/general/umdfSkeleton/driver.cpp @@ -0,0 +1,220 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This module contains the implementation of the UMDF Skeleton Sample's + core driver callback object. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#include "internal.h" +#include "driver.tmh" + +HRESULT +CMyDriver::CreateInstance( + _Out_ PCMyDriver *Driver + ) +/*++ + + Routine Description: + + This static method is invoked in order to create and initialize a new + instance of the driver class. The caller should arrange for the object + to be released when it is no longer in use. + + Arguments: + + Driver - a location to store a referenced pointer to the new instance + + Return Value: + + S_OK if successful, or error otherwise. + +--*/ +{ + PCMyDriver driver; + HRESULT hr; + + // + // Allocate the callback object. + // + + driver = new CMyDriver(); + + if (NULL == driver) + { + return E_OUTOFMEMORY; + } + + // + // Initialize the callback object. + // + + hr = driver->Initialize(); + + if (SUCCEEDED(hr)) + { + // + // Store a pointer to the new, initialized object in the output + // parameter. + // + + *Driver = driver; + } + else + { + + // + // Release the reference on the driver object to get it to delete + // itself. + // + + driver->Release(); + } + + return hr; +} + +HRESULT +CMyDriver::Initialize( + VOID + ) +/*++ + + Routine Description: + + This method is called to initialize a newly created driver callback object + before it is returned to the creator. Unlike the constructor, the + Initialize method contains operations which could potentially fail. + + Arguments: + + None + + Return Value: + + None + +--*/ +{ + return S_OK; +} + +HRESULT +CMyDriver::QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Interface + ) +/*++ + + Routine Description: + + This method returns a pointer to the requested interface on the callback + object.. + + Arguments: + + InterfaceId - the IID of the interface to query/reference + + Interface - a location to store the interface pointer. + + Return Value: + + S_OK if the interface is supported. + E_NOINTERFACE if it is not supported. + +--*/ +{ + if (IsEqualIID(InterfaceId, __uuidof(IDriverEntry))) + { + *Interface = QueryIDriverEntry(); + return S_OK; + } + else + { + return CUnknown::QueryInterface(InterfaceId, Interface); + } +} + +HRESULT +CMyDriver::OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ) +/*++ + + Routine Description: + + The FX invokes this method when it wants to install our driver on a device + stack. This method creates a device callback object, then calls the Fx + to create an Fx device object and associate the new callback object with + it. + + Arguments: + + FxWdfDriver - the Fx driver object. + + FxDeviceInit - the initialization information for the device. + + Return Value: + + status + +--*/ +{ + HRESULT hr; + + PCMyDevice device = NULL; + + // + // TODO: Do any per-device initialization (reading settings from the + // registry for example) that's necessary before creating your + // device callback object here. Otherwise you can leave such + // initialization to the initialization of the device event + // handler. + // + + // + // Create a new instance of our device callback object + // + + hr = CMyDevice::CreateInstance(FxWdfDriver, FxDeviceInit, &device); + + // + // TODO: Change any per-device settings that the object exposes before + // calling Configure to let it complete its initialization. + // + + // + // If that succeeded then call the device's construct method. This + // allows the device to create any queues or other structures that it + // needs now that the corresponding fx device object has been created. + // + + if (SUCCEEDED(hr)) + { + hr = device->Configure(); + } + + // + // Release the reference on the device callback object now that it's been + // associated with an fx device object. + // + + if (NULL != device) + { + device->Release(); + } + + return hr; +} diff --git a/general/umdfSkeleton/driver.h b/general/umdfSkeleton/driver.h new file mode 100644 index 00000000..c5664ac0 --- /dev/null +++ b/general/umdfSkeleton/driver.h @@ -0,0 +1,149 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Driver.h + +Abstract: + + This module contains the type definitions for the UMDF Skeleton sample's + driver callback class. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +// +// This class handles driver events for the skeleton sample. In particular +// it supports the OnDeviceAdd event, which occurs when the driver is called +// to setup per-device handlers for a new device stack. +// + +class CMyDriver : public CUnknown, public IDriverEntry +{ +// +// Private data members. +// +private: + +// +// Private methods. +// +private: + + // + // Returns a refernced pointer to the IDriverEntry interface. + // + + IDriverEntry * + QueryIDriverEntry( + VOID + ) + { + AddRef(); + return static_cast<IDriverEntry*>(this); + } + + HRESULT + Initialize( + VOID + ); + +// +// Public methods +// +public: + + // + // The factory method used to create an instance of this driver. + // + + static + HRESULT + CreateInstance( + _Out_ PCMyDriver *Driver + ); + +// +// COM methods +// +public: + + // + // IDriverEntry methods + // + + virtual + HRESULT + STDMETHODCALLTYPE + OnInitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return S_OK; + } + + virtual + HRESULT + STDMETHODCALLTYPE + OnDeviceAdd( + _In_ IWDFDriver *FxWdfDriver, + _In_ IWDFDeviceInitialize *FxDeviceInit + ); + + virtual + VOID + STDMETHODCALLTYPE + OnDeinitialize( + _In_ IWDFDriver *FxWdfDriver + ) + { + UNREFERENCED_PARAMETER( FxWdfDriver ); + + return; + } + + // + // IUnknown methods. + // + // We have to implement basic ones here that redirect to the + // base class becuase of the multiple inheritance. + // + + virtual + ULONG + STDMETHODCALLTYPE + AddRef( + VOID + ) + { + return __super::AddRef(); + } + + _At_(this, __drv_freesMem(object)) + virtual + ULONG + STDMETHODCALLTYPE + Release( + VOID + ) + { + return __super::Release(); + } + + virtual + HRESULT + STDMETHODCALLTYPE + QueryInterface( + _In_ REFIID InterfaceId, + _Out_ PVOID *Object + ); +}; diff --git a/general/umdfSkeleton/exports.def b/general/umdfSkeleton/exports.def new file mode 100644 index 00000000..a1ab223c --- /dev/null +++ b/general/umdfSkeleton/exports.def @@ -0,0 +1,10 @@ +; Skeleton.def : Declares the module parameters. + +; +; TODO: Change the library name here to match your binary name. +; + +LIBRARY "UMDFSkeleton.DLL" + +EXPORTS + DllGetClassObject PRIVATE diff --git a/general/umdfSkeleton/internal.h b/general/umdfSkeleton/internal.h new file mode 100644 index 00000000..bd8c3c6d --- /dev/null +++ b/general/umdfSkeleton/internal.h @@ -0,0 +1,90 @@ +/*++ + +Copyright (C) Microsoft Corporation, All Rights Reserved + +Module Name: + + Internal.h + +Abstract: + + This module contains the local type definitions for the UMDF Skeleton + driver sample. + +Environment: + + Windows User-Mode Driver Framework (WUDF) + +--*/ + +#pragma once + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#endif + +// +// Include the WUDF DDI +// + +#include "wudfddi.h" + +// +// Use specstrings for in/out annotation of function parameters. +// + +#include "specstrings.h" + +// +// Forward definitions of classes in the other header files. +// + +typedef class CMyDriver *PCMyDriver; +typedef class CMyDevice *PCMyDevice; + +// +// Define the tracing flags. +// +// TODO: Choose a different trace control GUID +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + MyDriverTraceControl, (e7541cdd,30e8,4b50,aeb0,51927330ae64), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// end_wpp +// + +// +// Driver specific #defines +// +// TODO: Change these values to be appropriate for your driver. +// + +#define MYDRIVER_TRACING_ID L"Microsoft\\UMDF\\Skeleton" +#define MYDRIVER_CLASS_ID { 0xd4112073, 0xd09b, 0x458f, { 0xa5, 0xaa, 0x35, 0xef, 0x21, 0xee, 0xf5, 0xde } } + + +// +// Include the type specific headers. +// + +#include "comsup.h" +#include "driver.h" +#include "device.h" diff --git a/general/umdfSkeleton/umdfSkeleton.sln b/general/umdfSkeleton/umdfSkeleton.sln new file mode 100644 index 00000000..2deba81c --- /dev/null +++ b/general/umdfSkeleton/umdfSkeleton.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0 +MinimumVisualStudioVersion = 12.0 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UMDFSkeleton", "UMDFSkeleton.vcxproj", "{A0B8804E-85A9-4432-A812-E9F6947C647A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|Win32.ActiveCfg = Debug|Win32 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|Win32.Build.0 = Debug|Win32 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|Win32.ActiveCfg = Release|Win32 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|Win32.Build.0 = Release|Win32 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|x64.ActiveCfg = Debug|x64 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Debug|x64.Build.0 = Debug|x64 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|x64.ActiveCfg = Release|x64 + {A0B8804E-85A9-4432-A812-E9F6947C647A}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal |
