/*++
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:
--*/
{
WUDF_TEST_DRIVER_ASSERT(m_Device);
m_Device->Release();
}
//
// Initialize
HRESULT
CMyQueue::CreateInstance(
__in CMyDevice *pDevice,
__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(pDevice);
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;
IUnknown *unknown = NULL;
HRESULT hr;
//
// Initialize ring buffer
//
hr = m_RingBuffer.Initialize(DATA_BUFFER_SIZE);
if (FAILED(hr))
{
goto Exit;
}
unknown = QueryIUnknown();
//
// Create the default queue
//
{
hr = FxDevice->CreateIoQueue(unknown,
TRUE,
WdfIoQueueDispatchParallel,
TRUE,
FALSE,
&fxQueue);
}
if (FAILED(hr))
{
goto Exit;
}
m_FxQueue = fxQueue;
fxQueue->Release();
//
// Create a manual queue to hold pending read requests. By keeping
// them in the queue, framework takes care of cancelling them if the app
// exits
//
{
hr = FxDevice->CreateIoQueue(NULL,
FALSE,
WdfIoQueueDispatchManual,
TRUE,
FALSE,
&fxQueue);
}
if (FAILED(hr))
{
goto Exit;
}
m_FxReadQueue = fxQueue;
fxQueue->Release();
Exit:
SAFE_RELEASE(unknown);
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(OutputBufferSizeInBytes);
UNREFERENCED_PARAMETER(InputBufferSizeInBytes);
UNREFERENCED_PARAMETER(pWdfQueue);
HRESULT hr = S_OK;
SIZE_T reqCompletionInfo = 0;
IWDFMemory *inputMemory = NULL;
IWDFMemory *outputMemory = NULL;
UINT i;
WUDF_TEST_DRIVER_ASSERT(pWdfRequest);
WUDF_TEST_DRIVER_ASSERT(m_Device);
switch (ControlCode)
{
case IOCTL_SERIAL_SET_BAUD_RATE:
{
//
// This is a driver for a virtual serial port. Since there is no
// actual hardware, we just store the baud rate and don't do
// anything with it.
//
SERIAL_BAUD_RATE baudRateBuffer;
ZeroMemory(&baudRateBuffer, sizeof(SERIAL_BAUD_RATE));
pWdfRequest->GetInputMemory(&inputMemory);
if (NULL == inputMemory)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (SUCCEEDED(hr))
{
hr = inputMemory->CopyToBuffer(0,
(void*) &baudRateBuffer,
sizeof(SERIAL_BAUD_RATE));
}
if (SUCCEEDED(hr))
{
m_Device->SetBaudRate(baudRateBuffer.BaudRate);
}
break;
}
case IOCTL_SERIAL_GET_BAUD_RATE:
{
SERIAL_BAUD_RATE baudRateBuffer;
ZeroMemory(&baudRateBuffer, sizeof(SERIAL_BAUD_RATE));
baudRateBuffer.BaudRate = m_Device->GetBaudRate();
pWdfRequest->GetOutputMemory(&outputMemory);
if (NULL == outputMemory)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (SUCCEEDED(hr))
{
hr = outputMemory->CopyFromBuffer(0,
(void*) &baudRateBuffer,
sizeof(SERIAL_BAUD_RATE));
}
if (SUCCEEDED(hr))
{
reqCompletionInfo = sizeof(SERIAL_BAUD_RATE);
}
break;
}
case IOCTL_SERIAL_SET_MODEM_CONTROL:
{
//
// This is a driver for a virtual serial port. Since there is no
// actual hardware, we just store the modem control register
// configuration and don't do anything with it.
//
ULONG *pModemControlRegister = NULL;
pWdfRequest->GetInputMemory(&inputMemory);
if (NULL == inputMemory)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (SUCCEEDED(hr))
{
pModemControlRegister = m_Device->GetModemControlRegisterPtr();
WUDF_TEST_DRIVER_ASSERT(pModemControlRegister);
hr = inputMemory->CopyToBuffer(0,
(void*) pModemControlRegister,
sizeof(ULONG));
}
break;
}
case IOCTL_SERIAL_GET_MODEM_CONTROL:
{
ULONG *pModemControlRegister = NULL;
pWdfRequest->GetOutputMemory(&outputMemory);
if (NULL == outputMemory)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
if (SUCCEEDED(hr))