diff options
Diffstat (limited to 'gpio/samples/simdeviceumdf/queue.cpp')
| -rw-r--r-- | gpio/samples/simdeviceumdf/queue.cpp | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/gpio/samples/simdeviceumdf/queue.cpp b/gpio/samples/simdeviceumdf/queue.cpp new file mode 100644 index 00000000..4b66a25f --- /dev/null +++ b/gpio/samples/simdeviceumdf/queue.cpp @@ -0,0 +1,529 @@ +/*++ + +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. +// + + +CSimdeviceQueue::~CSimdeviceQueue( + 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 +CSimdeviceQueue::CreateInstance( + _In_ IWDFDevice *FxDevice, + _Out_ PCSimdeviceQueue *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 + +--*/ +{ + CSimdeviceQueue *pMyQueue = new CSimdeviceQueue; + HRESULT hr; + + if (pMyQueue == NULL) { + return E_OUTOFMEMORY; + } + + hr = pMyQueue->Initialize(FxDevice); + + if (SUCCEEDED(hr)) + { + *Queue = pMyQueue; + } + else + { + pMyQueue->Release(); + } + return hr; +} + +HRESULT +CSimdeviceQueue::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 +CSimdeviceQueue::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 +CSimdeviceQueue::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 +CSimdeviceQueue::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; + } + + // Get memory object + hr = pWdfRequest->QueryInterface(IID_PPV_ARGS(&pWdfRequest2)); + + if (FAILED(hr)) { + pWdfRequest->Complete(hr); + 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; + } + + 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; + } + + + // + // 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; + pWdfRequest2 = NULL; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + pWdfRequest2->CompleteWithInformation(hr, 0); + delete [] m_Buffer; + m_Buffer = NULL; + } + + SAFE_RELEASE(pRequestMemory); + SAFE_RELEASE(pWdfRequest2); + + return; +} + +VOID +STDMETHODCALLTYPE +CSimdeviceQueue::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)) { + pWdfRequest->Complete(hr); + return; + } + + + 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; + } + + + // + // Save the information so that we can use it + // to complete the request later. + // + + Lock(); + + m_CurrentRequest = pWdfRequest2; + m_XferredBytes = SizeInBytes; + pWdfRequest2 = NULL; + + Unlock(); + +Exit: + + if (FAILED(hr)) { + pWdfRequest2->CompleteWithInformation(hr, 0); + } + + SAFE_RELEASE(pRequestMemory); + SAFE_RELEASE(pWdfRequest2); + return; +} + +DWORD +CSimdeviceQueue::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 + +--*/ +{ + CSimdeviceQueue *pQueue = (CSimdeviceQueue *)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); + SAFE_RELEASE(request); + } + + // + // If thread needs to be terminated + // + + if (pQueue->m_ExitThread) { + ExitThread(0); + } + + } + +} |
