summaryrefslogtreecommitdiff
path: root/biometrics/driver/Device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'biometrics/driver/Device.cpp')
-rw-r--r--biometrics/driver/Device.cpp1834
1 files changed, 1834 insertions, 0 deletions
diff --git a/biometrics/driver/Device.cpp b/biometrics/driver/Device.cpp
new file mode 100644
index 00000000..8f8dd6b4
--- /dev/null
+++ b/biometrics/driver/Device.cpp
@@ -0,0 +1,1834 @@
+/*++
+
+ 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.
+
+ Copyright (c) Microsoft Corporation. All rights reserved
+
+Module Name:
+
+ Device.cpp
+
+Abstract:
+
+ This module contains the implementation of the Biometric
+ device driver.
+
+Environment:
+
+ Windows User-Mode Driver Framework (WUDF)
+
+--*/
+#include "internal.h"
+#include "device.tmh"
+
+#pragma warning(disable : 4189)
+
+DWORD WINAPI
+CaptureSleepThread(
+ LPVOID lpParam
+ )
+{
+ CBiometricDevice *device = (CBiometricDevice *) lpParam;
+ PCAPTURE_SLEEP_PARAMS sleepParams = device->GetCaptureSleepParams();
+
+ //
+ // Make sure it is less than or equal to 1 minute.
+ //
+ if (sleepParams->SleepValue > 60)
+ {
+ sleepParams->SleepValue = 60;
+ }
+
+ Sleep(sleepParams->SleepValue * 1000);
+
+ device->CompletePendingRequest(sleepParams->Hr, sleepParams->Information);
+
+ return 0;
+}
+
+
+HRESULT
+CBiometricDevice::CreateInstanceAndInitialize(
+ _In_ IWDFDriver *FxDriver,
+ _In_ IWDFDeviceInitialize * FxDeviceInit,
+ _Out_ CBiometricDevice **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
+
+--*/
+{
+ //
+ // Create a new instance of the device class
+ //
+ CComObject<CBiometricDevice> *pMyDevice = NULL;
+ HRESULT hr = CComObject<CBiometricDevice>::CreateInstance( &pMyDevice );
+
+ if (SUCCEEDED(hr))
+ {
+
+ //
+ // Initialize the instance. This calls the WUDF framework,
+ // which keeps a reference to the device interface for the lifespan
+ // of the device.
+ //
+ if (NULL != pMyDevice)
+ {
+ hr = pMyDevice->Initialize(FxDriver, FxDeviceInit);
+
+ if (FAILED(hr))
+ {
+ BiometricSafeRelease(pMyDevice);
+ }
+
+ }
+
+ *Device = pMyDevice;
+
+ }
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::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;
+ HRESULT hr = S_OK;
+ IUnknown *unknown = NULL;
+
+ //
+ // Configure things like the locking model before we go to create our
+ // partner device.
+ //
+
+ //
+ // Set the locking model.
+ //
+
+ FxDeviceInit->SetLockingConstraint(WdfDeviceLevel);
+
+ //
+ // 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.
+ //
+
+ //
+ // We pass an IUnknown reference to CreateDevice, which takes its own
+ // reference if everything works.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = this->QueryInterface(__uuidof(IUnknown), (void **)&unknown);
+
+ }
+
+ if (SUCCEEDED(hr))
+ {
+
+ hr = FxDriver->CreateDevice(FxDeviceInit, unknown, &fxDevice);
+ BiometricSafeRelease(unknown);
+ }
+
+ //
+ // 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.
+ //
+
+ BiometricSafeRelease(fxDevice);
+ }
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::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
+
+--*/
+{
+
+ HRESULT hr = S_OK;
+
+ //
+ // Create the I/O queue
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = CBiometricIoQueue::CreateInstanceAndInitialize(m_FxDevice, this, &m_IoQueue);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_IoQueue->Configure();
+ }
+ }
+
+ //
+ // Create Device Interface
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->CreateDeviceInterface(&GUID_DEVINTERFACE_BIOMETRIC_READER,
+ NULL);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->AssignDeviceInterfaceState(&GUID_DEVINTERFACE_BIOMETRIC_READER,
+ NULL,
+ TRUE);
+ }
+
+ //
+ // TODO - this is where additional interfaces can be exposed.
+ //
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::OnPrepareHardware(
+ _In_ IWDFDevice * /* FxDevice */
+ )
+/*++
+
+Routine Description:
+
+ This routine is invoked to ready the driver
+ to talk to hardware. It opens the handle to the
+ device and talks to it using the WINUSB interface.
+ It invokes WINUSB to discver the interfaces and stores
+ the information related to bulk endpoints.
+
+Arguments:
+
+ FxDevice : Pointer to the WDF device interface
+
+Return Value:
+
+ HRESULT
+
+--*/
+{
+ PWSTR deviceName = NULL;
+ DWORD deviceNameCch = 0;
+
+ HRESULT hr;
+
+ //
+ // Get the device name.
+ // Get the length to allocate first
+ //
+
+ hr = m_FxDevice->RetrieveDeviceName(NULL, &deviceNameCch);
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cannot get device name %!hresult!",
+ hr
+ );
+ }
+
+ //
+ // Allocate the buffer
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ deviceName = (PWSTR) malloc(deviceNameCch * sizeof (WCHAR));
+
+ if (deviceName == NULL)
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ }
+
+ //
+ // Get the actual name
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_FxDevice->RetrieveDeviceName(deviceName, &deviceNameCch);
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cannot get device name %!hresult!",
+ hr
+ );
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Device name %S",
+ deviceName
+ );
+ }
+
+ //
+ // Create USB I/O Targets and configure them
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateUsbIoTargets();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ ULONG length = sizeof(m_Speed);
+
+ hr = m_pIUsbTargetDevice->RetrieveDeviceInformation(DEVICE_SPEED,
+ &length,
+ &m_Speed);
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cannot get usb device speed information %!HRESULT!",
+ hr
+ );
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Speed - %x\n",
+ m_Speed
+ );
+ }
+
+ //
+ // Setup power-management settings on the device.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ hr = SetPowerManagement();
+ }
+
+ //
+ // We have non-power managed queues so we Stop them in OnReleaseHardware
+ // and start them in OnPrepareHardware
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ m_IoQueue->Start();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // If the device stack allows read to remain pending across power-down
+ // and up, it can be initiated during OnPrepareHardware
+ //
+ // If the device stack doesn't allow the read to remain pending (i.e. it
+ // cancels the pending read during power transition) driver will have to
+ // stop sending pending read during D0Exit and re-initiate it during
+ // D0Entry
+ //
+ // USB core actually doesn't allow read to remain pending across power
+ // transition but WinUSB does. Since we are layered above WinUSB we don't
+ // need to manage pending read across power transitions.
+ //
+
+ hr = InitiatePendingRead();
+ }
+
+ if (deviceName)
+ {
+ free(deviceName);
+ deviceName = NULL;
+ }
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::OnReleaseHardware(
+ _In_ IWDFDevice * /* FxDevice */
+ )
+/*++
+
+Routine Description:
+
+ This routine is invoked when the device is being removed or stopped
+ It releases all resources allocated for this device.
+
+Arguments:
+
+ FxDevice - Pointer to the Device object.
+
+Return Value:
+
+ HRESULT - Always succeeds.
+
+--*/
+{
+ //
+ // Cancel the pending data collection I/O, if one exists.
+ //
+ CompletePendingRequest(HRESULT_FROM_WIN32(ERROR_CANCELLED), 0);
+
+ //
+ // Since we have non-power managed queues, we need to Stop them
+ // explicitly
+ //
+ // We need to stop them before deleting I/O targets otherwise we
+ // will continue to get I/O and our I/O processing will try to access
+ // freed I/O targets
+ //
+ // We initialize queues in CMyDevice::Initialize so we can't get
+ // here with queues being NULL and don't need to guard against that
+ //
+
+ m_IoQueue->StopSynchronously();
+
+ //
+ // Delete USB Target Device WDF Object, this will in turn
+ // delete all the children - interface and the pipe objects
+ //
+ // This makes sure that
+ // 1. We drain the I/O before releasing the targets
+ // a. We always need to do that for the pending read which does
+ // not come from an I/O queue
+ // b. We need to do this even for I/O coming from I/O queues because
+ // we set them to non-power managed queues (to leverage wait/wake
+ // from WinUsb.sys)
+ // 2. We remove USB target objects from object tree (and thereby free them)
+ // before any potential subsequent OnPrepareHardware creates new ones
+ //
+ // m_pIUsbTargetDevice could be NULL if OnPrepareHardware failed so we need
+ // to guard against that
+ //
+
+ if (m_pIUsbTargetDevice)
+ {
+ m_pIUsbTargetDevice->DeleteWdfObject();
+ }
+
+ //
+ // This sample has a thread that will sleep for 5 seconds before
+ // completing a capture request.
+ //
+ if (m_SleepThread != INVALID_HANDLE_VALUE)
+ {
+ WaitForSingleObject(m_SleepThread, INFINITE);
+ CloseHandle(m_SleepThread);
+ m_SleepThread = INVALID_HANDLE_VALUE;
+ }
+
+ return S_OK;
+}
+
+HRESULT
+CBiometricDevice::CreateUsbIoTargets(
+ )
+/*++
+
+Routine Description:
+
+ This routine creates Usb device, interface and pipe objects
+
+Arguments:
+
+ None
+
+Return Value:
+
+ HRESULT
+--*/
+{
+ HRESULT hr;
+ UCHAR NumEndPoints = 0;
+ IWDFUsbTargetFactory * pIUsbTargetFactory = NULL;
+ IWDFUsbTargetDevice * pIUsbTargetDevice = NULL;
+ IWDFUsbInterface * pIUsbInterface = NULL;
+ IWDFUsbTargetPipe * pIUsbPipe = NULL;
+
+ hr = m_FxDevice->QueryInterface(IID_PPV_ARGS(&pIUsbTargetFactory));
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cannot get usb target factory %!HRESULT!",
+ hr
+ );
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pIUsbTargetFactory->CreateUsbTargetDevice(
+ &pIUsbTargetDevice);
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Unable to create USB Device I/O Target %!HRESULT!",
+ hr
+ );
+ }
+ else
+ {
+ m_pIUsbTargetDevice = pIUsbTargetDevice;
+
+ //
+ // Release the creation reference as object tree will maintain a reference
+ //
+
+ BiometricSafeRelease(pIUsbTargetDevice);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ UCHAR NumInterfaces = pIUsbTargetDevice->GetNumInterfaces();
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Found %u interfaces",
+ NumInterfaces
+ );
+
+ hr = pIUsbTargetDevice->RetrieveUsbInterface(0, &pIUsbInterface);
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Unable to retrieve USB interface from USB Device I/O Target %!HRESULT!",
+ hr
+ );
+ }
+ else
+ {
+ m_pIUsbInterface = pIUsbInterface;
+
+ BiometricSafeRelease(pIUsbInterface); // release creation reference
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ NumEndPoints = pIUsbInterface->GetNumEndPoints();
+
+ if (NumEndPoints != NUM_WBDI_ENDPOINTS)
+ {
+ hr = E_UNEXPECTED;
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Has %d endpoints, expected %d, returning %!HRESULT! ",
+ NumEndPoints,
+ NUM_WBDI_ENDPOINTS,
+ hr
+ );
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ for (UCHAR PipeIndex = 0; PipeIndex < NumEndPoints; PipeIndex++)
+ {
+ hr = pIUsbInterface->RetrieveUsbPipeObject(PipeIndex,
+ &pIUsbPipe);
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Unable to retrieve USB Pipe for PipeIndex %d, %!HRESULT!",
+ PipeIndex,
+ hr
+ );
+ }
+ else
+ {
+ if ( pIUsbPipe->IsInEndPoint() )
+ {
+ if ( UsbdPipeTypeInterrupt == pIUsbPipe->GetType() )
+ {
+ m_pIUsbInterruptPipe = pIUsbPipe;
+ }
+ else if ( UsbdPipeTypeBulk == pIUsbPipe->GetType() )
+ {
+ m_pIUsbInputPipe = pIUsbPipe;
+ }
+ else
+ {
+ pIUsbPipe->DeleteWdfObject();
+ }
+ }
+ else if ( pIUsbPipe->IsOutEndPoint() && (UsbdPipeTypeBulk == pIUsbPipe->GetType()) )
+ {
+ m_pIUsbOutputPipe = pIUsbPipe;
+ }
+ else
+ {
+ pIUsbPipe->DeleteWdfObject();
+ }
+
+ BiometricSafeRelease(pIUsbPipe); //release creation reference
+ }
+ }
+
+ if (NULL == m_pIUsbInputPipe || NULL == m_pIUsbOutputPipe)
+ {
+ hr = E_UNEXPECTED;
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Input or output pipe not found, returning %!HRESULT!",
+ hr
+ );
+ }
+ }
+
+ BiometricSafeRelease(pIUsbTargetFactory);
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::SetPowerManagement(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This method enables the WinUSB driver to power the device down when it is
+ idle.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ Status
+
+--*/
+{
+
+ HRESULT hr = S_OK;
+ ULONG value = WBDI_SUSPEND_DELAY;
+
+ hr = m_pIUsbTargetDevice->SetPowerPolicy( SUSPEND_DELAY,
+ sizeof(ULONG),
+ (PVOID) &value );
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Unable to set power policy (SUSPEND_DELAY) for the device %!HRESULT!",
+ hr
+ );
+ }
+
+
+ //
+ // Finally enable auto-suspend.
+ //
+
+ if (SUCCEEDED(hr))
+ {
+ BOOL AutoSuspsend = TRUE;
+
+ hr = m_pIUsbTargetDevice->SetPowerPolicy( AUTO_SUSPEND,
+ sizeof(BOOL),
+ (PVOID) &AutoSuspsend );
+ }
+
+ if (FAILED(hr))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Unable to set power policy (AUTO_SUSPEND) for the device %!HRESULT!",
+ hr
+ );
+ }
+
+ return hr;
+}
+
+HRESULT
+CBiometricDevice::SendControlTransferSynchronously(
+ _In_ PWINUSB_SETUP_PACKET SetupPacket,
+ _Inout_updates_(BufferLength) PBYTE Buffer,
+ _In_ ULONG BufferLength,
+ _Out_ PULONG LengthTransferred
+ )
+/*++
+
+ Routine Description:
+
+ This method synchronously sends a control transfer request to
+ the USB I/O target.
+
+ Arguments:
+
+ SetupPacket - The command parameter structure
+
+ Buffer - The data to transfer
+
+ BufferLength - The size of the data buffer to transfer
+
+ LengthTransferred - Contains the actual number of bytes transferred.
+
+ Return Value:
+
+ HRESULT
+
+--*/
+{
+ HRESULT hr = S_OK;
+ IWDFIoRequest *pWdfRequest = NULL;
+ IWDFDriver * FxDriver = NULL;
+ IWDFMemory * FxMemory = NULL;
+ IWDFRequestCompletionParams * FxComplParams = NULL;
+ IWDFUsbRequestCompletionParams * FxUsbComplParams = NULL;
+
+ *LengthTransferred = 0;
+
+ hr = m_FxDevice->CreateRequest( NULL, //pCallbackInterface
+ NULL, //pParentObject
+ &pWdfRequest);
+
+ if (SUCCEEDED(hr))
+ {
+ m_FxDevice->GetDriver(&FxDriver);
+
+ hr = FxDriver->CreatePreallocatedWdfMemory( Buffer,
+ BufferLength,
+ NULL, //pCallbackInterface
+ pWdfRequest, //pParetObject
+ &FxMemory );
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pIUsbTargetDevice->FormatRequestForControlTransfer( pWdfRequest,
+ SetupPacket,
+ FxMemory,
+ NULL); //TransferOffset
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pWdfRequest->Send( m_pIUsbTargetDevice,
+ WDF_REQUEST_SEND_OPTION_SYNCHRONOUS,
+ 0); //Timeout
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ pWdfRequest->GetCompletionParams(&FxComplParams);
+
+ hr = FxComplParams->GetCompletionStatus();
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ HRESULT hrQI = FxComplParams->QueryInterface(IID_PPV_ARGS(&FxUsbComplParams));
+ if (SUCCEEDED(hrQI))
+ {
+ FxUsbComplParams->GetDeviceControlTransferParameters( NULL,
+ LengthTransferred,
+ NULL,
+ NULL );
+ }
+ }
+
+ BiometricSafeRelease(FxUsbComplParams);
+ BiometricSafeRelease(FxComplParams);
+ BiometricSafeRelease(FxMemory);
+
+ pWdfRequest->DeleteWdfObject();
+ BiometricSafeRelease(pWdfRequest);
+
+ BiometricSafeRelease(FxDriver);
+
+ return hr;
+}
+
+WDF_IO_TARGET_STATE
+CBiometricDevice::GetTargetState(
+ IWDFIoTarget * pTarget
+ )
+/*++
+
+ Routine Description:
+
+ This method gets the state of the I/O target
+
+ Arguments:
+
+ pTarget - A pointer to the I/O target
+
+ Return Value:
+
+ WDF_IO_TARGET_STATE
+
+--*/
+{
+ IWDFIoTargetStateManagement * pStateMgmt = NULL;
+ WDF_IO_TARGET_STATE state = WdfIoTargetStateUndefined;
+
+ HRESULT hrQI = pTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
+ if (FAILED(hrQI))
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cannot query interface %!HRESULT!",
+ hrQI
+ );
+
+ return state;
+ }
+
+ state = pStateMgmt->GetState();
+
+ BiometricSafeRelease(pStateMgmt);
+
+ return state;
+}
+
+HRESULT
+CBiometricDevice::InitiatePendingRead(
+ VOID
+ )
+/*++
+
+ Routine Description:
+
+ This routine starts up a cycling read on the interrupt pipe. As each
+ read completes it will start up the next one.
+
+ Arguments:
+
+ None
+
+ Return Value:
+
+ Status
+
+--*/
+{
+ HRESULT hr = S_OK;
+ IWDFIoRequest * FxRequest = NULL;
+ IWDFMemory * FxMemory = NULL;
+ IWDFDriver * FxDriver = NULL;
+ IRequestCallbackRequestCompletion * FxComplCallback = NULL;
+
+ hr = m_FxDevice->CreateRequest(NULL, NULL, &FxRequest);
+
+ if (SUCCEEDED(hr))
+ {
+ m_FxDevice->GetDriver(&FxDriver);
+
+ hr = FxDriver->CreatePreallocatedWdfMemory( (PBYTE) &m_InterruptMessage,
+ sizeof(m_InterruptMessage),
+ NULL, //pCallbackInterface
+ FxRequest, //pParetObject
+ &FxMemory );
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pIUsbInterruptPipe->FormatRequestForRead(FxRequest,
+ NULL, //pFile - IoTarget would apply its file
+ FxMemory,
+ NULL, //Memory offset
+ NULL); //Device offset
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ hr = this->QueryInterface(IID_PPV_ARGS(&FxComplCallback));
+ if (SUCCEEDED(hr))
+ {
+ FxRequest->SetCompletionCallback(FxComplCallback, NULL);
+
+ hr = FxRequest->Send(m_pIUsbInterruptPipe, 0, 0);
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ m_InterruptReadProblem = hr;
+
+ if (FxRequest)
+ {
+ FxRequest->DeleteWdfObject();
+ }
+ }
+
+ BiometricSafeRelease(FxRequest);
+ BiometricSafeRelease(FxMemory);
+ BiometricSafeRelease(FxDriver);
+ BiometricSafeRelease(FxComplCallback);
+
+ return hr;
+}
+
+VOID
+CBiometricDevice::OnCompletion(
+ _In_ IWDFIoRequest* FxRequest,
+ _In_ IWDFIoTarget* pIoTarget,
+ _In_ IWDFRequestCompletionParams* pParams,
+ _In_ PVOID pContext
+ )
+/*++
+
+ Routine Description:
+
+ This method is called when the asynchronous pending
+ read on the interrupt pipe completes.
+
+ Arguments:
+
+ FxRequest - The request object
+
+ pIoTarget - The I/O target for the request
+
+ pParams - The completion parameters
+
+ pContext - Optional context
+
+ Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER(pIoTarget);
+ UNREFERENCED_PARAMETER(pContext);
+
+ IWDFUsbRequestCompletionParams * pUsbComplParams = NULL;
+ IWDFMemory * FxMemory = NULL;
+ SIZE_T bytesRead = 0;
+ HRESULT hrCompletion = pParams->GetCompletionStatus();
+
+ TraceEvents(TRACE_LEVEL_INFORMATION,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Pending read completed with %!hresult!",
+ hrCompletion
+ );
+
+ if (FAILED(hrCompletion))
+ {
+ m_InterruptReadProblem = hrCompletion;
+ }
+ else
+ {
+ //
+ // Get the interrupt message
+ //
+
+ HRESULT hrQI = pParams->QueryInterface(IID_PPV_ARGS(&pUsbComplParams));
+ if (SUCCEEDED(hrQI))
+ {
+ pUsbComplParams->GetPipeReadParameters(&FxMemory, &bytesRead, NULL);
+ if (bytesRead == sizeof(INTERRUPT_MESSAGE))
+ {
+
+ PVOID pBuff = FxMemory->GetDataBuffer(NULL);
+ CopyMemory(&m_InterruptMessage, pBuff, sizeof(m_InterruptMessage));
+
+ //
+ // TODO: Parse m_InterruptMessage
+ //
+ }
+ }
+ }
+
+ //
+ // Don't complete the request since we created it, just delete it.
+ //
+
+ FxRequest->DeleteWdfObject();
+
+ //
+ // Re-initiate pending read if I/O Target is not stopped/removed
+ //
+
+ if (WdfIoTargetStarted == GetTargetState(m_pIUsbInterruptPipe))
+ {
+ int numRetries = 0;
+ HRESULT hr = InitiatePendingRead();
+
+ //
+ // If we fail here, the device will become unresponsive.
+ // Re-issue the request until it succeeds.
+ //
+ for (numRetries = 0; FAILED(hr) && numRetries < 3; ++numRetries)
+ {
+ hr = InitiatePendingRead();
+ }
+ }
+
+ BiometricSafeRelease(pUsbComplParams);
+ BiometricSafeRelease(FxMemory);
+}
+
+
+//
+// I/O handlers
+//
+
+void
+CBiometricDevice::GetIoRequestParams(
+ _In_ IWDFIoRequest *FxRequest,
+ _Out_ ULONG *MajorControlCode,
+ _Outptr_result_bytebuffer_(*InputBufferSizeInBytes) PUCHAR *InputBuffer,
+ _Out_ SIZE_T *InputBufferSizeInBytes,
+ _Outptr_result_bytebuffer_(*OutputBufferSizeInBytes) PUCHAR *OutputBuffer,
+ _Out_ SIZE_T *OutputBufferSizeInBytes
+ )
+/*++
+
+ Routine Description:
+
+ This method retrieves the input and output buffers associated with the request.
+
+ Arguments:
+
+ FxRequest - The WDF request oject
+
+ MajorControlCode - Contains the control code for the I/O request
+
+ InputBuffer - Contains the input buffer pointer
+
+ InputBufferSizeInBytes - Contains the size of the input buffer
+
+ OutputBuffer - Contains the output buffer pointer
+
+ OutputBufferSizeInBytes - Contains the size of the output buffer
+
+ Return Value:
+
+ None
+
+--*/
+{
+ //
+ // Get main parameters
+ //
+ FxRequest->GetDeviceIoControlParameters(MajorControlCode,
+ InputBufferSizeInBytes,
+ OutputBufferSizeInBytes);
+
+ // Get pointer to input buffer
+ IWDFMemory *fxMemory = NULL;
+ FxRequest->GetInputMemory(&fxMemory);
+ if (fxMemory)
+ {
+ *InputBuffer = (PUCHAR) fxMemory->GetDataBuffer(InputBufferSizeInBytes);
+ BiometricSafeRelease(fxMemory);
+ }
+
+ // Save pointer to reply buffer
+ fxMemory = NULL;
+ FxRequest->GetOutputMemory(&fxMemory);
+ if (fxMemory)
+ {
+ *OutputBuffer = (PUCHAR) fxMemory->GetDataBuffer(OutputBufferSizeInBytes);
+ BiometricSafeRelease(fxMemory);
+ }
+}
+
+void
+CBiometricDevice::OnGetAttributes(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_GET_ATTRIBUTES command is called.
+
+ Arguments:
+
+ FxRequest - The output for this request is a PWINBIO_SENSOR_ATTRIBUTES.
+
+ Return Value:
+
+ None
+
+--*/
+{
+ CRequestHelper MyRequest(FxRequest); // RAII helper class
+ ULONG controlCode = 0;
+ PUCHAR inputBuffer= NULL;
+ SIZE_T inputBufferSize = 0;
+ PWINBIO_SENSOR_ATTRIBUTES sensorAttributes = NULL;
+ SIZE_T outputBufferSize;
+
+ //
+ // Get the request parameters
+ //
+ GetIoRequestParams(FxRequest,
+ &controlCode,
+ &inputBuffer,
+ &inputBufferSize,
+ (PUCHAR *)&sensorAttributes,
+ &outputBufferSize);
+
+ //
+ // Make sure we have an output buffer big enough
+ //
+ if (sensorAttributes == NULL || outputBufferSize < sizeof(DWORD))
+ {
+ // We cannot return size information.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Output buffer NULL or too small to return size information.");
+ MyRequest.SetCompletionHr(E_INVALIDARG);
+ return;
+ }
+
+ // We only have one supported format, so sizeof (WINBIO_SENSOR_ATTRIBUTES) is sufficient.
+ if (outputBufferSize < sizeof(WINBIO_SENSOR_ATTRIBUTES))
+ {
+ // Buffer too small.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_SENSOR_ATTRIBUTES));
+ sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);
+ MyRequest.SetInformation(sizeof(DWORD));
+ MyRequest.SetCompletionHr(S_OK);
+ return;
+ }
+
+ //
+ // Fill in the attribute payload structure
+ //
+ RtlZeroMemory(sensorAttributes, outputBufferSize);
+ sensorAttributes->PayloadSize = (DWORD) sizeof(WINBIO_SENSOR_ATTRIBUTES);
+ sensorAttributes->WinBioHresult = S_OK;
+ sensorAttributes->WinBioVersion.MajorVersion = WINBIO_WBDI_MAJOR_VERSION;
+ sensorAttributes->WinBioVersion.MinorVersion = WINBIO_WBDI_MINOR_VERSION;
+ sensorAttributes->SensorType = WINBIO_TYPE_FINGERPRINT;
+ sensorAttributes->SensorSubType = WINBIO_FP_SENSOR_SUBTYPE_SWIPE;
+ sensorAttributes->Capabilities = WINBIO_CAPABILITY_SENSOR;
+ sensorAttributes->SupportedFormatEntries = 1;
+ sensorAttributes->SupportedFormat[0].Owner = WINBIO_ANSI_381_FORMAT_OWNER;
+ sensorAttributes->SupportedFormat[0].Type= WINBIO_ANSI_381_FORMAT_TYPE;
+ RtlCopyMemory(sensorAttributes->ManufacturerName, SAMPLE_MANUFACTURER_NAME, (wcslen(SAMPLE_MANUFACTURER_NAME)+1)*sizeof(WCHAR));
+ RtlCopyMemory(sensorAttributes->ModelName, SAMPLE_MODEL_NAME, (wcslen(SAMPLE_MODEL_NAME)+1)*sizeof(WCHAR));
+ RtlCopyMemory(sensorAttributes->SerialNumber, SAMPLE_SERIAL_NUMBER, (wcslen(SAMPLE_SERIAL_NUMBER)+1)*sizeof(WCHAR));
+ sensorAttributes->FirmwareVersion.MajorVersion = 1;
+ sensorAttributes->FirmwareVersion.MinorVersion = 0;
+
+ MyRequest.SetInformation(sensorAttributes->PayloadSize);
+ MyRequest.SetCompletionHr(S_OK);
+}
+
+
+void
+CBiometricDevice::OnReset(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_RESET command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ CRequestHelper MyRequest(FxRequest); // RAII helper class
+ ULONG controlCode = 0;
+ PUCHAR inputBuffer= NULL;
+ SIZE_T inputBufferSize = 0;
+ PWINBIO_BLANK_PAYLOAD blankPayload = NULL;
+ SIZE_T outputBufferSize;
+
+ //
+ // Get the request parameters
+ //
+ GetIoRequestParams(FxRequest,
+ &controlCode,
+ &inputBuffer,
+ &inputBufferSize,
+ (PUCHAR *)&blankPayload,
+ &outputBufferSize);
+
+ //
+ // Make sure we have an output buffer big enough
+ //
+ if (blankPayload== NULL || outputBufferSize < sizeof(DWORD))
+ {
+ // We cannot return size information.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Output buffer NULL or too small to return size information.");
+ MyRequest.SetInformation(sizeof(DWORD));
+ MyRequest.SetCompletionHr(S_OK);
+ MyRequest.SetCompletionHr(E_INVALIDARG);
+ return;
+ }
+
+ if (outputBufferSize < sizeof(WINBIO_BLANK_PAYLOAD))
+ {
+ // Buffer too small.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_DIAGNOSTICS));
+ MyRequest.SetInformation(sizeof(DWORD));
+ MyRequest.SetCompletionHr(S_OK);
+ return;
+ }
+
+ //
+ // This is a simulated device. Nothing to do here except cancel the pending data
+ // collection I/O, if one exists.
+ //
+ CompletePendingRequest(HRESULT_FROM_WIN32(ERROR_CANCELLED), 0);
+
+ //
+ // Fill in the OUT payload structure
+ //
+ RtlZeroMemory(blankPayload, outputBufferSize);
+ blankPayload->PayloadSize = (DWORD) sizeof(WINBIO_BLANK_PAYLOAD);
+ blankPayload->WinBioHresult = S_OK;
+
+ FxRequest->SetInformation(blankPayload->PayloadSize);
+ MyRequest.SetCompletionHr(S_OK);
+
+}
+
+void
+CBiometricDevice::OnCalibrate(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_CALIBRATE command is called.
+
+ Arguments:
+
+ FxRequest -
+ IN - blank payload
+ OUT - PWINBIO_CALIBRATION_INFO
+
+ Return Value:
+
+ None
+
+--*/
+{
+ CRequestHelper MyRequest(FxRequest); // RAII helper class
+ ULONG controlCode = 0;
+ PUCHAR inputBuffer= NULL;
+ SIZE_T inputBufferSize = 0;
+ PWINBIO_CALIBRATION_INFO calibrationInfo = NULL;
+ SIZE_T outputBufferSize;
+
+ //
+ // Get the request parameters
+ //
+ GetIoRequestParams(FxRequest,
+ &controlCode,
+ &inputBuffer,
+ &inputBufferSize,
+ (PUCHAR *)&calibrationInfo,
+ &outputBufferSize);
+
+ //
+ // Make sure we have an output buffer big enough
+ //
+ if (calibrationInfo == NULL || outputBufferSize < sizeof(DWORD))
+ {
+ // We cannot return size information.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Output buffer NULL or too small to return size information.");
+ MyRequest.SetCompletionHr(E_INVALIDARG);
+ return;
+ }
+
+ if (outputBufferSize < sizeof(WINBIO_CALIBRATION_INFO))
+ {
+ // Buffer too small.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_DIAGNOSTICS));
+ calibrationInfo->PayloadSize = (DWORD) sizeof(WINBIO_CALIBRATION_INFO);
+ MyRequest.SetInformation(sizeof(DWORD));
+ MyRequest.SetCompletionHr(S_OK);
+ return;
+ }
+
+ //
+ // This is where code to calibrate the device goes.
+ //
+
+ //
+ // Fill in the OUT payload structure
+ //
+ RtlZeroMemory(calibrationInfo, outputBufferSize);
+ calibrationInfo->PayloadSize = (DWORD) sizeof(WINBIO_CALIBRATION_INFO);
+ calibrationInfo->WinBioHresult = S_OK;
+
+ MyRequest.SetInformation(calibrationInfo->PayloadSize);
+ MyRequest.SetCompletionHr(S_OK);
+}
+
+
+void
+CBiometricDevice::OnGetSensorStatus(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_GET_SENSOR_STATUS command is called.
+
+ Arguments:
+
+ FxRequest -
+ IN payload: none
+ OUT payload: PWINBIO_DIAGNOSTICS
+
+ Return Value:
+
+ None
+
+--*/
+{
+ CRequestHelper MyRequest(FxRequest); // RAII helper class
+ ULONG controlCode = 0;
+ PUCHAR inputBuffer= NULL;
+ SIZE_T inputBufferSize = 0;
+ PWINBIO_DIAGNOSTICS diagnostics = NULL;
+ SIZE_T outputBufferSize;
+
+ //
+ // Get the request parameters
+ //
+ GetIoRequestParams(FxRequest,
+ &controlCode,
+ &inputBuffer,
+ &inputBufferSize,
+ (PUCHAR *)&diagnostics,
+ &outputBufferSize);
+
+ //
+ // Make sure we have an output buffer big enough
+ //
+ if (diagnostics == NULL || outputBufferSize < sizeof(DWORD))
+ {
+ // We cannot return size information.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Output buffer NULL or too small to return size information.");
+ MyRequest.SetCompletionHr(E_INVALIDARG);
+ return;
+ }
+
+ if (outputBufferSize < sizeof(WINBIO_DIAGNOSTICS))
+ {
+ // Buffer too small.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Buffer too small - return size necessary in PayloadSize - 0x%x.", sizeof(WINBIO_DIAGNOSTICS));
+ diagnostics->PayloadSize = (DWORD) sizeof(WINBIO_DIAGNOSTICS);
+ MyRequest.SetInformation(sizeof(DWORD));
+ MyRequest.SetCompletionHr(S_OK);
+ return;
+ }
+
+ //
+ // Fill in the OUT payload structure
+ //
+ RtlZeroMemory(diagnostics, outputBufferSize);
+ diagnostics->PayloadSize = (DWORD) sizeof(WINBIO_DIAGNOSTICS);
+ diagnostics->WinBioHresult = S_OK;
+ diagnostics->SensorStatus = WINBIO_SENSOR_READY;
+
+ MyRequest.SetInformation(diagnostics->PayloadSize);
+ MyRequest.SetCompletionHr(S_OK);
+}
+
+
+void
+CBiometricDevice::OnCaptureData(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_CAPTURE_DATA command is called.
+
+ Arguments:
+
+ FxRequest -
+ IN payload: PWINBIO_CAPTURE_PARAMETERS
+ OUT payload: PWINBIO_CAPTURE_DATA
+
+ Return Value:
+
+ None
+
+--*/
+{
+ ULONG controlCode = 0;
+ PWINBIO_CAPTURE_PARAMETERS captureParams = NULL;
+ SIZE_T inputBufferSize = 0;
+ PWINBIO_CAPTURE_DATA captureData = NULL;
+ SIZE_T outputBufferSize = 0;
+
+ //
+ // We can only have one outstanding data capture request at a time.
+ // Check to see if we have a request pending.
+ //
+ bool requestPending = false;
+
+ EnterCriticalSection(&m_RequestLock);
+
+ if (m_PendingRequest == NULL)
+ {
+ //
+ // See if we have an active sleep thread.
+ // If so, tell it to exit.
+ // Wait for it to exit.
+ //
+ if (m_SleepThread != INVALID_HANDLE_VALUE)
+ {
+ LeaveCriticalSection(&m_RequestLock);
+
+ // TODO: Add code to signal thread to exit.
+
+ // NOTE: Sleeping for INFINITE time is dangerous. A real driver
+ // should be able to handle the case where the thread does
+ // not exit.
+ WaitForSingleObject(m_SleepThread, INFINITE);
+ CloseHandle(m_SleepThread);
+ m_SleepThread = INVALID_HANDLE_VALUE;
+
+ EnterCriticalSection(&m_RequestLock);
+ }
+
+ //
+ // We might have had to leave the CS to wait for the sleep thread.
+ // Double check that the pending request is still NULL.
+ //
+ if (m_PendingRequest == NULL)
+ {
+ // Save the request.
+ m_PendingRequest = FxRequest;
+
+ // Mark the request as cancellable.
+ m_PendingRequest->MarkCancelable(this);
+ }
+ else
+ {
+ requestPending = true;
+ }
+
+ }
+ else
+ {
+ requestPending = true;
+ }
+
+ LeaveCriticalSection(&m_RequestLock);
+
+ if (requestPending)
+ {
+ // Complete the request to tell the app that there is already
+ // a pending data collection request.
+ FxRequest->Complete(WINBIO_E_DATA_COLLECTION_IN_PROGRESS);
+ return;
+ }
+
+ //
+ // Get the request parameters
+ //
+ GetIoRequestParams(FxRequest,
+ &controlCode,
+ (PUCHAR *)&captureParams,
+ &inputBufferSize,
+ (PUCHAR *)&captureData,
+ &outputBufferSize);
+
+ //
+ // Check input parameters.
+ //
+ if (inputBufferSize < sizeof (WINBIO_CAPTURE_PARAMETERS))
+ {
+ // Invalid arguments
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Invalid argument(s).");
+ CompletePendingRequest(E_INVALIDARG, 0);
+ return;
+ }
+
+ //
+ // Make sure we have an output buffer big enough
+ //
+ if (outputBufferSize < sizeof(DWORD))
+ {
+ // We cannot return size information.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Output buffer NULL or too small to return size information.");
+ CompletePendingRequest(E_INVALIDARG, 0);
+ return;
+ }
+
+ //
+ // Check output buffer size.
+ //
+ if (outputBufferSize < sizeof (WINBIO_CAPTURE_DATA))
+ {
+ // Buffer too small.
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC!Buffer too small - must be at least 0x%x.", sizeof (WINBIO_CAPTURE_DATA));
+ //
+ // NOTE: The output buffer size necessary for this sample is sizeof(WINBIO_CAPTURE_DATA).
+ // Real devices will need additional space to handle a typical capture.
+ // The value that should be returned here is sizeof(WINBIO_CAPTURE_DATA) + CaptureBufferSize.
+ //
+ captureData->PayloadSize = (DWORD) sizeof(WINBIO_CAPTURE_DATA);
+ CompletePendingRequest(S_OK, sizeof(DWORD));
+ return;
+ }
+
+ //
+ // NOTE: This call always fails in this sample since it is not
+ // written for a real device.
+ //
+
+ //
+ // Set default values in output buffer.
+ //
+ captureData->PayloadSize = (DWORD) sizeof (WINBIO_CAPTURE_DATA);
+ captureData->WinBioHresult = WINBIO_E_NO_CAPTURE_DATA;
+ captureData->SensorStatus = WINBIO_SENSOR_FAILURE;
+ captureData->RejectDetail= 0;
+ captureData->CaptureData.Size = 0;
+
+ //
+ // Check purpose, format and type.
+ //
+ if (captureParams->Purpose == WINBIO_NO_PURPOSE_AVAILABLE)
+ {
+ captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_PURPOSE;
+ }
+ else if ((captureParams->Format.Type != WINBIO_ANSI_381_FORMAT_TYPE) ||
+ (captureParams->Format.Owner != WINBIO_ANSI_381_FORMAT_OWNER))
+ {
+ captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_FORMAT;
+ }
+ else if (captureParams->Flags != WINBIO_DATA_FLAG_RAW)
+ {
+ captureData->WinBioHresult = WINBIO_E_UNSUPPORTED_DATA_TYPE;
+ }
+
+ //
+ // NOTE: This sample completes the request after
+ // sleeping for 5 seconds. A real driver would
+ // program the device for capture mode, and then
+ // return from this callback. The request would
+ // remain pending until cancelled, or until the
+ // driver detects a capture is complete.
+ //
+ // The construct of m_PendingRequest will allow
+ // a driver to have only one pending request at any
+ // time, which can be cancelled in a Reset IOCTL, or
+ // by calling CancelIoEx.
+ //
+
+ //
+ // Create thread to sleep 5 seconds before completing the request.
+ //
+ m_SleepParams.SleepValue = 5;
+ m_SleepParams.Hr = S_OK;
+ m_SleepParams.Information = captureData->PayloadSize;
+ m_SleepThread = CreateThread(NULL, // default security attributes
+ 0, // use default stack size
+ CaptureSleepThread, // thread function name
+ this, // argument to thread function
+ 0, // use default creation flags
+ NULL); // returns the thread identifier
+}
+
+
+void
+CBiometricDevice::OnUpdateFirmware(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_UPDATE_FIRMWARE command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FxRequest->Complete(E_NOTIMPL);
+}
+
+void
+CBiometricDevice::OnGetSupportedAlgorithms(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_GET_SUPPORTED_ALGORITHMS command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FxRequest->Complete(E_NOTIMPL);
+}
+
+void
+CBiometricDevice::OnGetIndicator(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_GET_INDICATOR command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FxRequest->Complete(E_NOTIMPL);
+}
+
+
+void
+CBiometricDevice::OnSetIndicator(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_SET_INDICATOR command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FxRequest->Complete(E_NOTIMPL);
+}
+
+void
+CBiometricDevice::OnControlUnit(
+ _Inout_ IWDFIoRequest *FxRequest
+ )
+/*++
+
+ Routine Description:
+
+ This method is invoked when the IOCTL_BIOMETRIC_CONTROL_UNIT command is called.
+
+ Arguments:
+
+ FxRequest -
+
+ Return Value:
+
+ None
+
+--*/
+{
+ FxRequest->Complete(E_NOTIMPL);
+}
+
+
+VOID
+CBiometricDevice::CompletePendingRequest(
+ HRESULT hr,
+ DWORD information
+ )
+{
+ EnterCriticalSection(&m_RequestLock);
+
+ if (m_PendingRequest)
+ {
+ //
+ // Only complete the request if we weren't cancelled. Otherwise, the
+ // OnCancel callback will complete the request.
+ //
+ HRESULT hrUnmark = m_PendingRequest->UnmarkCancelable();
+ if (HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED) != hrUnmark)
+ {
+ m_PendingRequest->SetInformation(information);
+ m_PendingRequest->Complete(hr);
+ m_PendingRequest = NULL;
+ }
+ }
+
+ LeaveCriticalSection(&m_RequestLock);
+}
+
+VOID
+STDMETHODCALLTYPE
+CBiometricDevice::OnCancel(
+ _In_ IWDFIoRequest *pWdfRequest
+ )
+{
+ EnterCriticalSection(&m_RequestLock);
+
+ if (m_PendingRequest != pWdfRequest)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Cancelled request does not match pending request.");
+ }
+
+ //
+ // TODO: In a real driver, the device would be reset so that it is no longer in capture mode.
+ // Add your code to do so here.
+ //
+
+ if (m_PendingRequest == NULL)
+ {
+ TraceEvents(TRACE_LEVEL_ERROR,
+ BIOMETRIC_TRACE_DEVICE,
+ "%!FUNC! Pending request is NULL.");
+ }
+ else
+ {
+ m_PendingRequest->Complete(HRESULT_FROM_WIN32(ERROR_OPERATION_ABORTED));
+ m_PendingRequest = NULL;
+ }
+
+ LeaveCriticalSection(&m_RequestLock);
+}