summaryrefslogtreecommitdiff
path: root/gpio/samples/simdeviceumdf/device.cpp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /gpio/samples/simdeviceumdf/device.cpp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'gpio/samples/simdeviceumdf/device.cpp')
-rw-r--r--gpio/samples/simdeviceumdf/device.cpp1106
1 files changed, 1106 insertions, 0 deletions
diff --git a/gpio/samples/simdeviceumdf/device.cpp b/gpio/samples/simdeviceumdf/device.cpp
new file mode 100644
index 00000000..0ced0bd1
--- /dev/null
+++ b/gpio/samples/simdeviceumdf/device.cpp
@@ -0,0 +1,1106 @@
+/*++
+
+Copyright (c) 1990-2010 Microsoft Corporation
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ This is a simple UMDF device driver that consumes GPIO pins for I/O and interrupt.
+
+
+Environment:
+
+ UMDF
+
+--*/
+
+//
+// Inlcude the below set of headers to get the CM_RESOURCE_ definitions
+//
+
+
+#include "internal.h"
+
+DEFINE_GUID (GUID_DEVINTERFACE_ECHO,
+ 0xcdc35b6e, 0xbe4, 0x4936, 0xbf, 0x5f, 0x55, 0x37, 0x38, 0xa, 0x7c, 0x1a);
+// {CDC35B6E-0BE4-4936-BF5F-5537380A7C1A}
+
+
+HRESULT
+CSimdevice::CreateInstance(
+ _In_ IWDFDriver *FxDriver,
+ _In_ IWDFDeviceInitialize * FxDeviceInit,
+ _Out_ PCSimdevice *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
+
+--*/
+{
+ PCSimdevice device;
+ HRESULT hr;
+
+ //
+ // Allocate a new instance of the device class.
+ //
+
+ device = new CSimdevice();
+
+ 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
+CSimdevice::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;
+ 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);
+
+ //
+ // 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.
+ //
+
+ FxDeviceInit->QueryInterface(IID_PPV_ARGS(&fxDeviceInit2));
+
+ if (fxDeviceInit2 == NULL) {
+ hr = E_FAIL;
+ return hr;
+ }
+
+ fxDeviceInit2->SetIoTypePreference(WdfDeviceIoBufferRetrievalDeferred,
+ WdfDeviceIoDirect,
+ WdfDeviceIoDirect);
+
+ 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
+CSimdevice::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
+
+--*/
+{
+ PCSimdeviceQueue defaultQueue;
+
+ HRESULT hr;
+
+ hr = CSimdeviceQueue::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
+CSimdevice::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 if (IsEqualIID(InterfaceId, __uuidof(IPnpCallbackHardware2))) {
+ *Object = QueryIPnpCallbackHardware2();
+ hr = S_OK;
+ } else if (IsEqualIID(InterfaceId, __uuidof(IPnpCallback))) {
+ *Object = QueryIPnpCallback();
+ hr = S_OK;
+ } else {
+ hr = CUnknown::QueryInterface(InterfaceId, Object);
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::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,
+ CSimdeviceQueue::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
+CSimdevice::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);
+}
+
+
+HRESULT
+CSimdevice::OnPrepareHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesRaw,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ )
+/*++
+
+Routine Description:
+
+ This routine is called by WUDF to initialize hardware resources (e.g. interrupts,
+ IO resources)
+
+Arguments:
+
+ pWdfDevice - pointer to an IWDFDevice object for the device
+
+ pWdfResourcesRaw - Supplies a pointer to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ pWdfResourcesTranslated - Supplies a pointer 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.
+
+Return Value:
+
+ HRESULT
+
+--*/
+{
+
+ ULONG i;
+ HRESULT hr = S_OK;
+ ULONG ConnectionCount = 0;
+ BOOLEAN fInterruptFound = FALSE;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorTranslated;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR DescriptorRaw;
+
+ //
+ // Parse the resource list and save the resource information.
+ //
+
+ for (i=0; i < pWdfResourcesTranslated->GetCount(); i++) {
+
+ DescriptorTranslated = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)pWdfResourcesTranslated->GetDescriptor(i);
+ DescriptorRaw = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)pWdfResourcesRaw->GetDescriptor(i);
+
+ if(DescriptorTranslated == NULL) {
+ return E_FAIL;
+ }
+
+ switch (DescriptorTranslated->Type) {
+
+ //
+ // One or more GPIO IO resources are expected. In this implementation of the sample
+ // driver, however, only the first IO resource will be used (see OnD0Entry).
+ //
+
+ case CmResourceTypeConnection:
+
+ //
+ // Check against expected connection type for a GPIO IO descriptor
+ //
+
+ if ((DescriptorTranslated->u.Connection.Class ==
+ CM_RESOURCE_CONNECTION_CLASS_GPIO) &&
+ (DescriptorTranslated->u.Connection.Type ==
+ CM_RESOURCE_CONNECTION_TYPE_GPIO_IO)) {
+
+ if (ConnectionCount >= MAX_CONNECTIONS) {
+ break;
+ }
+
+ //
+ // Store GPIO IO resource connection ID in the device extension
+ //
+
+ this->GetDeviceExtension()->ConnectionId[ConnectionCount].LowPart =
+ DescriptorTranslated->u.Connection.IdLowPart;
+
+ this->GetDeviceExtension()->ConnectionId[ConnectionCount].HighPart =
+ DescriptorTranslated->u.Connection.IdHighPart;
+ }
+
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ //
+ // Connect the first interrupt resource we find
+ //
+
+ if (fInterruptFound == FALSE) {
+ hr = this->SimdeviceConnectInterrupt(
+ pWdfDevice,
+ DescriptorRaw,
+ DescriptorTranslated);
+
+ if (SUCCEEDED(hr)) {
+ fInterruptFound = TRUE;
+ }
+ }
+ default:
+
+ //
+ // Ignore all other descriptors
+ //
+
+ break;
+ }
+ }
+
+ return hr;
+
+}
+
+HRESULT
+CSimdevice::OnReleaseHardware(
+ _In_ IWDFDevice3 * pWdfDevice,
+ _In_ IWDFCmResourceList * pWdfResourcesTranslated
+ )
+/*++
+
+
+Routine Description:
+
+ This method is called by WUDF to uninitialize the hardware.
+
+Parameters:
+
+ pWdfDevice - pointer to an IWDFDevice object for the device
+
+ pWdfResourcesTranslated - pointer to the translated resource list
+
+Return Values:
+ status
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(pWdfResourcesTranslated);
+
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::OnD0Entry(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE previousState
+ )
+
+/*++
+
+Routine Description:
+
+This method is called after a new device enters the system
+
+Parameters:
+
+ pWdfDevice - pointer to a device object
+
+ previousState - previous WDF power state
+
+Return Values:
+ status
+
+--*/
+{
+
+ PDEVICE_EXTENSION DevExt;
+ HRESULT hr = S_OK;
+ BYTE Data;
+ NTSTATUS Status;
+ NTSTATUS Status1;
+ WCHAR ReadStringBuffer[100];
+ WCHAR WriteStringBuffer[100];
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(previousState);
+
+ DevExt = GetDeviceExtension();
+
+ Status = StringCbPrintfW(&ReadStringBuffer[0],
+ sizeof(ReadStringBuffer),
+ L"\\\\.\\RESOURCE_HUB\\%0*I64x",
+ (size_t)(sizeof(LARGE_INTEGER) * 2),
+ DevExt->ConnectionId[0].QuadPart);
+
+ Status = StringCbPrintfW(&WriteStringBuffer[0],
+ sizeof(WriteStringBuffer),
+ L"\\\\.\\RESOURCE_HUB\\%0*I64x",
+ (size_t)(sizeof(LARGE_INTEGER) * 2),
+ DevExt->ConnectionId[0].QuadPart);
+
+ //
+ // Connect the first GPIO IO descriptor we find (in OnPrepareHardware) for read and write operations
+ //
+
+ Data = 0xDB;
+ Status = STATUS_SUCCESS;
+ Status1 = TestReadWrite(pWdfDevice, &WriteStringBuffer[0], FALSE, &Data, sizeof(Data), NULL);
+ if (!NT_SUCCESS(Status1)) {
+ Status = Status1;
+ }
+
+ Data = 0;
+ Status1 = TestReadWrite(pWdfDevice, &ReadStringBuffer[0], TRUE, &Data, sizeof(Data), NULL);
+ if (!NT_SUCCESS(Status1)) {
+ Status = Status1;
+ }
+
+ return hr;
+}
+
+HRESULT
+CSimdevice::OnD0Exit(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ WDF_POWER_DEVICE_STATE TargetState
+ )
+
+/*++
+
+Routine Description:
+
+This method is called when a device exit D0
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+ TargetState - target D-state
+
+Return Values:
+ status
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ UNREFERENCED_PARAMETER(TargetState);
+
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::TestReadWrite(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_ PWSTR RequestString,
+ _In_ BOOLEAN ReadOperation,
+ _Inout_updates_bytes_(Size) UCHAR *Data,
+ _In_ ULONG Size,
+ _Inout_opt_ IWDFRemoteTarget *IoTargetOut
+ )
+
+/*++
+
+Routine Description:
+
+ This is a utility routine to test read or write on a set of GPIO pins.
+
+Arguments:
+
+ pWdfDevice - Supplies a pointer to the framework device object.
+
+ RequestString - Supplies a pointer to the unicode string to be opened.
+
+ ReadOperation - Supplies a boolean that identifies whether read (TRUE) or
+ write (FALSE) should be performed.
+
+ Data - Supplies a pointer containing the buffer that should be read from
+ or written to.
+
+ Size - Supplies the size of the data buffer in bytes.
+
+ IoTargetOut - Supplies a pointer that receives the IOTARGET created by
+ UMDF.
+
+Return Value:
+
+ HRESULT
+
+--*/
+
+{
+
+ IWDFMemory *pOutputMemory = NULL;
+ IWDFMemory *pInputMemory = NULL;
+ IRequestCallbackRequestCompletion *pICallback = NULL;
+ IWDFIoRequest *pIoRequest = NULL;
+ IWDFRemoteTarget *pRemoteTarget = NULL;
+ UMDF_IO_TARGET_OPEN_PARAMS OpenParams;
+ DWORD DesiredAccess;
+ HRESULT hr = S_OK;
+ IWDFRequestCompletionParams * FxComplParams = NULL;
+ IWDFDriver *pWdfDriver = NULL;
+
+ UNREFERENCED_PARAMETER(IoTargetOut);
+
+ if (ReadOperation != FALSE) {
+ DesiredAccess = FILE_GENERIC_READ;
+
+ } else {
+ DesiredAccess = FILE_GENERIC_WRITE;
+ }
+
+ //
+ // QueryIUnknown references the IUnknown interface that it returns
+ // (which is the same as referencing the CMyRemoteTarget). We pass that
+ // to the various Create* calls, which take their own reference if
+ // everything works.
+ //
+
+ IUnknown * unknown = this->QueryIUnknown();
+
+
+ IWDFDevice2 *pWdfDevice2 = NULL;
+ hr = pWdfDevice->QueryInterface(IID_PPV_ARGS(&pWdfDevice2));
+
+ // Create the IoTarget
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice2->CreateRemoteTarget(
+ unknown,
+ NULL,
+ &pRemoteTarget);
+ }
+
+ //
+ // Determine whether the request is a read or write
+ //
+
+ OpenParams.dwCreationDisposition = OPEN_EXISTING;
+ OpenParams.dwFlagsAndAttributes = FILE_FLAG_OVERLAPPED;
+ OpenParams.dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->OpenFileByName(RequestString,
+ DesiredAccess,
+ &OpenParams);
+ }
+
+ //
+ //Create a new IO request
+ //
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice->CreateRequest(NULL, pWdfDevice, &pIoRequest);
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = this->QueryInterface(__uuidof(IRequestCallbackRequestCompletion), (PVOID*)&pICallback);
+
+ //
+ //Set completion callback
+ //
+
+ if (SUCCEEDED(hr)){
+ pIoRequest->SetCompletionCallback(pICallback, NULL);
+ }
+
+ pWdfDevice->GetDriver(&pWdfDriver);
+
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(Data,
+ Size,
+ NULL, // no object event callback
+ pIoRequest, // request object as parent
+ &pInputMemory);
+
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(Data,
+ Size,
+ NULL, // no object event callback
+ pIoRequest, // request object as parent
+ &pOutputMemory);
+
+ //
+ //Format IO request
+ //
+
+ if (ReadOperation != FALSE){
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->FormatRequestForIoctl(pIoRequest,
+ IOCTL_GPIO_READ_PINS,
+ NULL,
+ NULL,
+ NULL,
+ pOutputMemory,
+ NULL);
+ }
+ }
+ else {
+ if (SUCCEEDED(hr)) {
+ hr = pRemoteTarget->FormatRequestForIoctl(pIoRequest,
+ IOCTL_GPIO_WRITE_PINS,
+ NULL,
+ pInputMemory,
+ NULL,
+ pOutputMemory,
+ NULL);
+ }
+ }
+
+ //
+ //Send down the request
+ //
+ if (SUCCEEDED(hr)) {
+ hr = pIoRequest->Send(pRemoteTarget,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
+ 0); //No timeout
+ }
+
+ if (SUCCEEDED(hr)) {
+
+ //
+ //Get IWDFRequestCompletionParams interface and then get completion status.
+ //
+
+ pIoRequest->GetCompletionParams(&FxComplParams);
+ hr = FxComplParams->GetCompletionStatus();
+ }
+
+ if(FAILED(hr)) {
+ pIoRequest->DeleteWdfObject();
+ pIoRequest = NULL;
+ }
+ }
+
+ //
+ // Clean-up
+ //
+
+ if (pWdfDevice2 != NULL) {
+ SAFE_RELEASE(pWdfDevice2);
+ }
+
+ if (pWdfDriver != NULL) {
+ SAFE_RELEASE(pWdfDriver);
+ }
+
+ if (pRemoteTarget != NULL) {
+ pRemoteTarget->Close();
+ }
+
+ return hr;
+}
+
+
+void
+CSimdevice::OnSurpriseRemoval(
+ _In_ IWDFDevice* pWdfDevice
+ )
+
+/*++
+
+Routine Description:
+
+This method is called when a device is surprise removed
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+}
+
+
+HRESULT
+CSimdevice::OnQueryRemove(
+ _In_ IWDFDevice* pWdfDevice
+ )
+/*++
+
+Routine Description:
+
+This method is called when a device processes the query remove IRP
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ HRESULT
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::OnQueryStop(
+ _In_ IWDFDevice* pWdfDevice
+ )
+/*++
+
+Routine Description:
+
+This method is called when a device processes the query stop IRP
+
+Parameters:
+
+ pWdfDevice pointer to a device object
+
+Return Values:
+ HRESULT
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pWdfDevice);
+ return S_OK;
+}
+
+HRESULT
+CSimdevice::SimdeviceConnectInterrupt(
+ _In_ IWDFDevice* pWdfDevice,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR RawResource,
+ _In_opt_ PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedResource
+ )
+
+/*++
+
+Routine Description:
+
+ This is a utility routine to create an interrupt descriptor from the interrupt resource
+ acquired from OnPrepareHardware and connect the device ISR routine.
+Arguments:
+
+ pWdfDevice - Supplies a pointer to the framework device object.
+
+ pWdfResourcesRaw - Supplies a pointer to a collection of framework resource
+ objects. This collection identifies the raw (bus-relative) hardware
+ resources that have been assigned to the device.
+
+ pWdfResourcesTranslated - Supplies a pointer 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.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IWDFDevice3 * pIWDFDevice3 = NULL;
+ IWDFInterrupt * spInterrupt = NULL;
+ HRESULT hr = S_OK;
+
+ if (pWdfDevice == NULL) {
+ hr = E_INVALIDARG;
+ }
+
+ if (SUCCEEDED(hr)) {
+ hr = pWdfDevice->QueryInterface(IID_PPV_ARGS(&pIWDFDevice3));
+ }
+
+ if (SUCCEEDED(hr)) {
+
+ //
+ // Create interrupt
+ //
+
+ WUDF_INTERRUPT_CONFIG config;
+ WUDF_INTERRUPT_CONFIG_INIT(
+ &config,
+ &CSimdevice::OnInterruptIsr,
+ &CSimdevice::OnInterruptWorkItem);
+
+ config.InterruptRaw = RawResource;
+ config.InterruptTranslated = TranslatedResource;
+
+ hr = pIWDFDevice3->CreateInterrupt(&config, &spInterrupt);
+ }
+
+ //
+ // Associate the device context with the interrupt
+ //
+
+ if (SUCCEEDED(hr)) {
+ hr = spInterrupt->AssignContext(NULL, (void*)this);
+ }
+
+ return hr;
+}
+
+BOOLEAN
+CSimdevice::OnInterruptIsr(
+ _In_ IWDFInterrupt* pInterrupt,
+ _In_ ULONG MessageID,
+ _In_ ULONG Reserved
+ )
+
+/* ++
+
+Routine Description:
+
+ This method is called when an interrupt occurs. It determines if the
+ driver owns the interrupt and queues a work item to defer processing
+ of the data.
+
+ Arguments:
+
+ pInterrupt - pointer to the interrupt object
+ MessageID - interrupt message ID
+ Reserved -
+
+Return Values:
+ TRUE if interrupt recognized, else FALSE.
+
+-- */
+
+{
+
+ UNREFERENCED_PARAMETER(MessageID);
+ UNREFERENCED_PARAMETER(Reserved);
+
+ IWDFDevice* pWdfDevice = NULL;
+ CSimdevice* pMyDevice = NULL;
+ HRESULT hr;
+
+ hr = pInterrupt->RetrieveContext((void**)&pMyDevice);
+
+ if (FAILED(hr)) {
+ pWdfDevice = pInterrupt->GetDevice();
+ pWdfDevice->SetPnpState(WdfPnpStateFailed, WdfTrue);
+ pWdfDevice->CommitPnpState();
+ }
+
+ //
+ // The sample driver always returns TRUE (e.g. claiming the interrupt)
+ // from its ISR. In reality, the driver needs to do whatever necessary to
+ // quiesce the interrupt before claiming the interrupt.
+ // If additional work needs to be done at , schedule a work item (as we do here).
+ //
+
+ pInterrupt->QueueWorkItemForIsr();
+
+ return TRUE;
+}
+
+VOID
+CSimdevice::OnInterruptWorkItem(
+ _In_ IWDFInterrupt* pInterrupt,
+ _In_ IWDFObject* AssociatedObject
+ )
+
+/* ++
+
+Routine Description:
+
+ This method is called on behalf of an interrupt to defer processing.
+ It retrieves latest data and posts it.
+
+Arguments:
+ pInterrupt - pointer to the interrupt object
+ AssociatedObject - pointer to the associated object
+
+Return Values:
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(AssociatedObject);
+
+ IWDFDevice* pWdfDevice = NULL;
+ CSimdevice* pMyDevice;
+ HRESULT hr;
+
+ hr = pInterrupt->RetrieveContext((void**)&pMyDevice);
+
+ if (FAILED(hr)) {
+ pWdfDevice = pInterrupt->GetDevice();
+ pWdfDevice->SetPnpState(WdfPnpStateFailed, WdfTrue);
+ pWdfDevice->CommitPnpState();
+ }
+
+
+ //
+ // The sample driver does nothing in the work item routine. The real driver
+ // can add code here to accomplish all that is required to complete the serving
+ // of the interrupt
+ //
+
+ return;
+}
+
+