Beispiel #1
0
VOID
STDMETHODCALLTYPE
CMyControlQueue::OnDeviceIoControl(
    __in IWDFIoQueue *FxQueue,
    __in IWDFIoRequest *FxRequest,
    __in ULONG ControlCode,
    __in SIZE_T InputBufferSizeInBytes,
    __in SIZE_T OutputBufferSizeInBytes
    )
/*++

Routine Description:


    DeviceIoControl dispatch routine

Aruments:
    
    FxQueue - Framework Queue instance
    FxRequest - Framework Request  instance
    ControlCode - IO Control Code
    InputBufferSizeInBytes - Lenth of input buffer
    OutputBufferSizeInBytes - Lenth of output buffer

    Always succeeds DeviceIoIoctl
Return Value:

    VOID

--*/
{
    UNREFERENCED_PARAMETER(FxQueue);
    
    IWDFMemory *memory = NULL;
    PVOID buffer;

    SIZE_T bigBufferCb;

    ULONG information = 0;

    bool completeRequest = true;

    HRESULT hr = S_OK;

    switch (ControlCode)
    {
        case IOCTL_OSRUSBFX2_GET_CONFIG_DESCRIPTOR:
        {
            //
            // Get the output buffer.
            //

            FxRequest->GetOutputMemory(&memory );

            //
            // request the descriptor.
            //

            ULONG bufferCb;

            //
            // Get the buffer address then release the memory object.
            // The memory object remains valid until the request is 
            // completed.
            //

            buffer = memory->GetDataBuffer(&bigBufferCb);
            memory->Release();

            if (bigBufferCb > ULONG_MAX)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
                break;
            }
            else
            {
                bufferCb = (ULONG) bigBufferCb;
            }

            hr = m_Device->GetUsbTargetDevice()->RetrieveDescriptor(                
                        USB_CONFIGURATION_DESCRIPTOR_TYPE,
                        0,
                        0,
                        &bufferCb,
                        (PUCHAR) buffer
                        );

            if (SUCCEEDED(hr))
            {
                information = bufferCb;
            }

            break;
        }

        case IOCTL_OSRUSBFX2_GET_BAR_GRAPH_DISPLAY:
        {
            //
            // Make sure the buffer is big enough to hold the result of the
            // control transfer.
            //

            if (OutputBufferSizeInBytes < sizeof(BAR_GRAPH_STATE))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetOutputMemory(&memory );
            }

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();

                hr = m_Device->GetBarGraphDisplay((PBAR_GRAPH_STATE) buffer);
            }

            //
            // If that worked then record how many bytes of data we're 
            // returning.
            //

            if (SUCCEEDED(hr)) 
            {
                information = sizeof(BAR_GRAPH_STATE);
            }

            break;
        }

        case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY:
        {
            //
            // Make sure the buffer is big enough to hold the input for the
            // control transfer.
            //

            if (InputBufferSizeInBytes < sizeof(BAR_GRAPH_STATE))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetInputMemory(&memory);
            }

            //
            // Get the data buffer and use it to set the bar graph on the
            // device.
            //

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();

                hr = m_Device->SetBarGraphDisplay((PBAR_GRAPH_STATE) buffer);
            }

            break;
        }

        case IOCTL_OSRUSBFX2_GET_7_SEGMENT_DISPLAY:
        {
            //
            // Make sure the buffer is big enough to hold the result of the
            // control transfer.
            //

            if (OutputBufferSizeInBytes < sizeof(SEVEN_SEGMENT))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetOutputMemory(&memory );
            }

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();
                hr = m_Device->GetSevenSegmentDisplay((PSEVEN_SEGMENT) buffer);
            }

            //
            // If that worked then record how many bytes of data we're 
            // returning.
            //

            if (SUCCEEDED(hr)) 
            {
                information = sizeof(SEVEN_SEGMENT);
            }

            break;
        }

        case IOCTL_OSRUSBFX2_SET_7_SEGMENT_DISPLAY:
        {
            //
            // Make sure the buffer is big enough to hold the input for the
            // control transfer.
            //

            if (InputBufferSizeInBytes < sizeof(SEVEN_SEGMENT))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetInputMemory(&memory );
            }

            //
            // Get the data buffer and use it to set the bar graph on the
            // device.
            //

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();

                hr = m_Device->SetSevenSegmentDisplay((PSEVEN_SEGMENT) buffer);
            }
            break;
        }

        case IOCTL_OSRUSBFX2_READ_SWITCHES: 
        {
            //
            // Make sure the buffer is big enough to hold the input for the
            // control transfer.
            //

            if (OutputBufferSizeInBytes < sizeof(SWITCH_STATE))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                FxRequest->GetOutputMemory(&memory );
            }

            //
            // Get the data buffer and use it to set the bar graph on the
            // device.
            //

            if (SUCCEEDED(hr)) 
            {
                buffer = memory->GetDataBuffer(&bigBufferCb);
                memory->Release();

                hr = m_Device->ReadSwitchState((PSWITCH_STATE) buffer);
            }

            if (SUCCEEDED(hr)) 
            {
                information = sizeof(SWITCH_STATE);
            }

            break;
        }

        case IOCTL_OSRUSBFX2_GET_INTERRUPT_MESSAGE: 
        {
            //
            // Make sure the buffer is big enough to hold the switch
            // state.
            //

            if (OutputBufferSizeInBytes < sizeof(SWITCH_STATE))
            {
                hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
            }
            else
            {
                //
                // Forward the request to the switch state change queue.
                //

                hr = FxRequest->ForwardToIoQueue(
                                    m_Device->GetSwitchChangeQueue()
                                    );

                if (SUCCEEDED(hr))
                {
                    completeRequest = false;
                }
            }

            break;
        }

        case IOCTL_OSRUSBFX2_RESET_DEVICE:
        case IOCTL_OSRUSBFX2_REENUMERATE_DEVICE:
        {
            //
            // WinUSB does not allow us to reset or re-enumerate the device.
            // Return not-supported for the error in both of these cases.
            //

            hr = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
            break;
        }


        default:
        {
            hr = HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
            break;
        }
    }

    if (completeRequest)
    {
        FxRequest->CompleteWithInformation(hr, information);
    }

    return;
}
Beispiel #2
0
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;
    SIZE_T BytesCopied = 0;
    HRESULT     hr;

    UNREFERENCED_PARAMETER(pWdfQueue);

    //
    // Get memory object
    //
    pWdfRequest->GetOutputMemory(&pRequestMemory);

    hr = m_RingBuffer.Read((PBYTE)pRequestMemory->GetDataBuffer(NULL),
                            SizeInBytes,
                            &BytesCopied);

    //
    // Release memory object.
    //
    SAFE_RELEASE(pRequestMemory);

    if (FAILED(hr))
    {
        //
        // Error reading buffer
        //
        pWdfRequest->Complete(hr);
        goto Exit;
    }

    if (BytesCopied > 0)
    {
        //
        // Data was read from buffer succesfully
        //
        pWdfRequest->CompleteWithInformation(hr, BytesCopied);
    }
    else
    {
        //
        // No data to read. Queue the request for later processing.
        //
        pWdfRequest->ForwardToIoQueue(m_FxReadQueue);
    }

Exit:
    return;
}
VOID
STDMETHODCALLTYPE
CVDevParallelQueue::OnDeviceIoControl (
                                       __in IWDFIoQueue *FxQueue,
                                       __in IWDFIoRequest *wdfRequest,
                                       __in ULONG ControlCode,
                                       __in SIZE_T InputBufferSizeInBytes,
                                       __in SIZE_T OutputBufferSizeInBytes)
/*++

Routine Description:

    DeviceIoControl dispatch routine

Arguments:

    FxQueue - Framework Queue instance
    wdfRequest - Framework Request  instance
    ControlCode - IO Control Code
    InputBufferSizeInBytes - Length of input buffer
    OutputBufferSizeInBytes - Length of output buffer

Return Value:

    VOID

--*/
{
    HRESULT hr = S_OK;  
    HRESULT hrSend = S_OK;
    SIZE_T bufSize = 0;

    //
    // More often than not these will be the same block of memory
    // but to display support for more diverse scenarios, 
    // we'll loosely treat input and output buffers as different blocks.
    //
    IWDFMemory * memory = NULL;
    IWDFMemory * outputMemory = NULL;

    UNREFERENCED_PARAMETER (FxQueue);

    switch (ControlCode)
    {
    case IOCTL_ASYNC_LOCK:
        {
            if ((sizeof (ASYNC_LOCK) > InputBufferSizeInBytes) ||
                (sizeof (ASYNC_LOCK) > OutputBufferSizeInBytes))
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ASYNC_LOCK));
            }
            else
            {
                IRequestCallbackRequestCompletion * completionRoutine = \
                    RequestCompletion ();

                wdfRequest->SetCompletionCallback (
                    completionRoutine,
                    (PVOID) &ControlCode);

                completionRoutine->Release ();


                hrSend = SubmitAsyncRequestToLower (wdfRequest);
                if (FAILED (hrSend))
                {
                    wdfRequest->Complete (hrSend);
                }
            } // else
        }// case IOCTL_ASYNC_LOCK
        break;

    case IOCTL_ASYNC_READ:
        {
            PASYNC_READ AsyncRead;

            if (sizeof (ASYNC_READ) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ASYNC_READ));
            }
            else
            {
                wdfRequest->GetInputMemory (&memory);
                memory->Release ();

                wdfRequest->GetOutputMemory (&outputMemory);
                outputMemory->Release ();

                AsyncRead = (PASYNC_READ) outputMemory->GetDataBuffer (&bufSize);

                if ((sizeof (ASYNC_READ) > OutputBufferSizeInBytes) ||
                    ((OutputBufferSizeInBytes - sizeof (ASYNC_READ)) > 
                    AsyncRead->nNumberOfBytesToRead))
                {
                    wdfRequest->CompleteWithInformation (
                        HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                        (sizeof (ASYNC_READ) + AsyncRead->nNumberOfBytesToRead));
                }
                else if (0 == AsyncRead->nNumberOfBytesToRead)
                {
                    wdfRequest->Complete (
                        HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER));
                }
                else
                {
                    IRequestCallbackRequestCompletion * completionRoutine = \
                        RequestCompletion ();

                    wdfRequest->SetCompletionCallback (
                        completionRoutine,
                        (PVOID) &ControlCode);

                    completionRoutine->Release ();

                    hrSend = SubmitAsyncRequestToLower (wdfRequest);
                    if (FAILED (hrSend))
                    {
                        wdfRequest->Complete (hrSend);
                    }
                } // else
            } // else
        } // case IOCTL_ASYNC_READ
        break;

    case IOCTL_ASYNC_STREAM:
        {
            PASYNC_STREAM AsyncStream;

            if (sizeof (ASYNC_STREAM) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ASYNC_STREAM));
            }
            else
            {
                wdfRequest->GetInputMemory (&memory);
                memory->Release ();

                AsyncStream = (PASYNC_STREAM) memory->GetDataBuffer (&bufSize);

                if ((OutputBufferSizeInBytes - sizeof (ASYNC_STREAM)) > 
                    AsyncStream->nNumberOfBytesToStream)
                {
                    wdfRequest->CompleteWithInformation (
                        HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                        (sizeof (ASYNC_STREAM) + 
                        AsyncStream->nNumberOfBytesToStream));
                }
                else if (0 == AsyncStream->nNumberOfBytesToStream)
                {
                    wdfRequest->Complete (
                        HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER));
                }
                else
                {
                    IRequestCallbackRequestCompletion * completionRoutine = \
                        RequestCompletion ();

                    wdfRequest->SetCompletionCallback (
                        completionRoutine,
                        (PVOID) &ControlCode);

                    completionRoutine->Release ();

                    hrSend = SubmitAsyncRequestToLower (wdfRequest);
                    if (FAILED (hrSend))
                    {
                        wdfRequest->Complete (hrSend);
                    }
                } // else
            } // else
        } // case IOCTL_ASYNC_STREAM
        break;

    case IOCTL_ASYNC_WRITE:
        {
            PASYNC_WRITE AsyncWrite;

            if (sizeof (ASYNC_WRITE) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ASYNC_WRITE));
            }
            else
            {
                wdfRequest->GetInputMemory (&memory);
                memory->Release ();

                AsyncWrite = (PASYNC_WRITE) memory->GetDataBuffer(&bufSize);

                if ((InputBufferSizeInBytes - sizeof (ASYNC_WRITE)) > 
                    AsyncWrite->nNumberOfBytesToWrite)
                {
                    wdfRequest->CompleteWithInformation (
                        HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                        (sizeof (ASYNC_WRITE) + AsyncWrite->nNumberOfBytesToWrite));
                }
                else if (0 == AsyncWrite->nNumberOfBytesToWrite)
                {
                    wdfRequest->Complete (
                        HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER));
                }
                else
                {
                    IRequestCallbackRequestCompletion * completionRoutine = \
                        RequestCompletion ();

                    wdfRequest->SetCompletionCallback (
                        completionRoutine,
                        (PVOID) &ControlCode);

                    completionRoutine->Release();

                    hrSend = SubmitAsyncRequestToLower (wdfRequest);
                    if (FAILED (hrSend))
                    {
                        wdfRequest->Complete (hrSend);
                    }
                }
            } // else                   
        } // case IOCTL_ASYNC_WRITE
        break;

    case IOCTL_BUS_RESET:
        {
            if (sizeof (ULONG) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ULONG));
            }
            else
            {
                IRequestCallbackRequestCompletion * completionRoutine = \
                    RequestCompletion ();

                wdfRequest->SetCompletionCallback (
                    completionRoutine,
                    (PVOID) &ControlCode);

                completionRoutine->Release();

                hrSend = SubmitAsyncRequestToLower (wdfRequest);             
                if (FAILED (hrSend))
                {
                    wdfRequest->Complete (hrSend);
                }

            }
        } // case IOCTL_BUS_RESET
        break;

    case IOCTL_BUS_RESET_NOTIFICATION:
        {
            if (sizeof (ULONG) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ULONG));
            }
            else
            {
                IRequestCallbackRequestCompletion * completionRoutine = \
                    RequestCompletion ();

                wdfRequest->SetCompletionCallback (
                    completionRoutine,
                    (PVOID) &ControlCode);

                completionRoutine->Release();

                hrSend = SubmitAsyncRequestToLower (wdfRequest);
                if (FAILED (hrSend))
                {
                    wdfRequest->Complete (hrSend);
                }
            }
        } // case IOCTL_BUS_RESET_NOTIFICATION
        break;

    case IOCTL_GET_ADDRESS_DATA :
        {
            //
            //    
            PGET_ADDRESS_DATA InputGetAddrData, OutputGetAddrData;

            if ((sizeof (GET_ADDRESS_DATA) > InputBufferSizeInBytes) ||
                (sizeof (GET_ADDRESS_DATA) > OutputBufferSizeInBytes))
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (GET_ADDRESS_DATA));
            }
            else
            {
                wdfRequest->GetInputMemory (&memory);
                memory->Release ();

                wdfRequest->GetOutputMemory (&outputMemory);
                outputMemory->Release ();

                InputGetAddrData = \
                    (PGET_ADDRESS_DATA) memory->GetDataBuffer (&bufSize);

                OutputGetAddrData = \
                    (PGET_ADDRESS_DATA) outputMemory->GetDataBuffer (&bufSize);

                if ((InputBufferSizeInBytes - sizeof (GET_ADDRESS_DATA) <  
                    InputGetAddrData->nLength) ||
                    (OutputBufferSizeInBytes - sizeof (GET_ADDRESS_DATA) < 
                    OutputGetAddrData->nLength))
                {
                    wdfRequest->CompleteWithInformation (
                        HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                        (InputGetAddrData->nLength + sizeof (GET_ADDRESS_DATA)));
                }
                else if (0 == InputGetAddrData->nLength || 
                    0 == OutputGetAddrData->nLength)
                {
                    wdfRequest->Complete (
                        HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER));
                }
                else
                {
                    IRequestCallbackRequestCompletion * completionRoutine = \
                        RequestCompletion ();

                    wdfRequest->SetCompletionCallback (
                        completionRoutine,
                        (PVOID) &ControlCode);

                    completionRoutine->Release();

                    hrSend = SubmitAsyncRequestToLower (wdfRequest);
                    if (FAILED (hrSend))
                    {
                        wdfRequest->Complete (hrSend);
                    }
                }
            } // else               
        } // case IOCTL_GET_ADDRESS_DATA 
        break;

    case IOCTL_SET_ADDRESS_DATA:
        {
            PSET_ADDRESS_DATA SetAddrData; 

            if (sizeof (SET_ADDRESS_DATA) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (SET_ADDRESS_DATA));
            }
            else
            {
                wdfRequest->GetInputMemory (&memory);
                memory->Release();

                SetAddrData = \
                    (PSET_ADDRESS_DATA) memory->GetDataBuffer (&bufSize);

                if ((InputBufferSizeInBytes - sizeof (SET_ADDRESS_DATA)) < 
                    SetAddrData->nLength)
                {
                    wdfRequest->CompleteWithInformation (
                        HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                        (sizeof (SET_ADDRESS_DATA) + SetAddrData->nLength));
                }
                else if (0 == SetAddrData->nLength)
                {
                    wdfRequest->Complete (
                        HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER));
                }
                else
                {
                    IRequestCallbackRequestCompletion * completionRoutine = \
                        RequestCompletion ();

                    
                    wdfRequest->SetCompletionCallback (
                        completionRoutine,
                        (PVOID) &ControlCode);

                    completionRoutine->Release ();

                    hrSend = SubmitAsyncRequestToLower (wdfRequest);
                    if (FAILED (hrSend))
                    {
                        wdfRequest->Complete (hrSend);
                    }
                }
            } // else
        } // case IOCTL_SET_ADDRESS_DATA
        break;

    case IOCTL_FREE_ADDRESS_RANGE:
        {
            if (sizeof (HANDLE) > InputBufferSizeInBytes)
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (HANDLE));
            }
            else
            {                               
                IRequestCallbackRequestCompletion * completionRoutine = \
                    RequestCompletion ();

                wdfRequest->SetCompletionCallback (
                    completionRoutine,
                    (PVOID) &ControlCode);

                completionRoutine->Release ();

                hrSend = SubmitAsyncRequestToLower (wdfRequest);
                if (FAILED (hrSend))
                {
                    wdfRequest->Complete (hrSend);
                }
            } 
        } // case IOCTL_FREE_ADDRESS_RANGE
        break;

    case IOCTL_ALLOCATE_ADDRESS_RANGE:
        {

            if ((sizeof (ALLOCATE_ADDRESS_RANGE) > InputBufferSizeInBytes) ||
                (sizeof (ALLOCATE_ADDRESS_RANGE) > OutputBufferSizeInBytes))
            {
                wdfRequest->CompleteWithInformation (
                    HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER),
                    sizeof (ALLOCATE_ADDRESS_RANGE));
            }
            else
            {
                IRequestCallbackRequestCompletion * completionRoutine = \
                    RequestCompletion ();
                
                wdfRequest->SetCompletionCallback (
                    completionRoutine,
                    (PVOID) &ControlCode);

                completionRoutine->Release ();
                
                hrSend = SubmitAsyncRequestToLower (wdfRequest);
                if (FAILED (hrSend))
                {
                    wdfRequest->Complete (hrSend);
                }
            }
        } // case IOCTL_ALLOCATE_ADDRESS_RANGE
        break;

    default:
        {
            // 
            // This isn't a request for this queue to handle, 
            // so we'll forward it on to the Serialzed queue
            //
            wdfRequest->ForwardToIoQueue (
                m_VdevDevice->GetSequentialQueue()->GetFxQueue());
            if (FAILED (hrSend))
            {
                wdfRequest->Complete (hr);
            }
        }
        break;
    } // switch

    return;
}
Beispiel #4
0
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

--*/
{
    IWDFMemory* pRequestMemory = NULL;
    IWDFIoRequest* pSavedRequest = NULL;
    SIZE_T availableData = 0;
    SIZE_T savedRequestBufferSize = 0;
    HRESULT hr = S_OK;

    UNREFERENCED_PARAMETER(pWdfQueue);

    //
    // Get memory object
    //

    pWdfRequest->GetInputMemory(&pRequestMemory);

    //
    // Process input
    //

    ProcessWriteBytes((PUCHAR)pRequestMemory->GetDataBuffer(NULL), BytesToWrite);

    //
    // Release memory object and complete request
    //
    SAFE_RELEASE(pRequestMemory);
    pWdfRequest->CompleteWithInformation(hr, BytesToWrite);

    //
    // Get the amount of data available in the ring buffer
    //
    m_RingBuffer.GetAvailableData(&availableData);

    if (availableData > 0)
    {
        //
        // Continue with the next request, if there is one pending
        //
        hr = m_FxReadQueue->RetrieveNextRequest(&pSavedRequest);
        if ((pSavedRequest == NULL) || (FAILED(hr)))
        {
            goto Exit;
        }

        pSavedRequest->GetReadParameters(&savedRequestBufferSize, NULL, NULL);

        OnRead(m_FxQueue,
               pSavedRequest,
               savedRequestBufferSize);

        //
        // RetrieveNextRequest from a manual queue increments the reference
        // counter by 1. We need to decrement it, otherwise the request will
        // not be released and there will be an object leak.
        //
        SAFE_RELEASE(pSavedRequest);
    }

Exit:
    return;
}