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;
}
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;
}
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 #5
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;
}
Beispiel #6
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;
}
Beispiel #7
0
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 = {0};

            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 = {0};

            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))
            {
                pModemControlRegister = m_Device->GetModemControlRegisterPtr();
                WUDF_TEST_DRIVER_ASSERT(pModemControlRegister);

                hr = outputMemory->CopyFromBuffer(0,
                                                  (void*) pModemControlRegister,
                                                  sizeof(ULONG));
            }

            if (SUCCEEDED(hr))
            {
                reqCompletionInfo = sizeof(ULONG);
            }

            break;
        }
        case IOCTL_SERIAL_SET_FIFO_CONTROL:
        {
            //
            // This is a driver for a virtual serial port. Since there is no
            // actual hardware, we just store the FIFO control register
            // configuration and don't do anything with it.
            //
            ULONG *pFifoControlRegister = NULL;

            pWdfRequest->GetInputMemory(&inputMemory);
            if (NULL == inputMemory)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
            }

            if (SUCCEEDED(hr))
            {
                pFifoControlRegister = m_Device->GetFifoControlRegisterPtr();

                hr = inputMemory->CopyToBuffer(0,
                                               (void*) pFifoControlRegister,
                                               sizeof(ULONG));
            }

            break;
        }
        case IOCTL_SERIAL_GET_LINE_CONTROL:
        {
            ULONG *pLineControlRegister = NULL;
            SERIAL_LINE_CONTROL lineControl = {0};
            ULONG lineControlSnapshot;

            pLineControlRegister = m_Device->GetLineControlRegisterPtr();
            WUDF_TEST_DRIVER_ASSERT(pLineControlRegister);

            //
            // Take a snapshot of the line control register variable
            //
            lineControlSnapshot = *pLineControlRegister;

            //
            // Decode the word length
            //
            if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_5_DATA)
            {
                lineControl.WordLength = 5;
            }
            else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_6_DATA)
            {
                lineControl.WordLength = 6;
            }
            else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_7_DATA)
            {
                lineControl.WordLength = 7;
            }
            else if ((lineControlSnapshot & SERIAL_DATA_MASK) == SERIAL_8_DATA)
            {
                lineControl.WordLength = 8;
            }

            //
            // Decode the parity
            //
            if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_NONE_PARITY)
            {
                lineControl.Parity = NO_PARITY;
            }
            else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_ODD_PARITY)
            {
                lineControl.Parity = ODD_PARITY;
            }
            else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_EVEN_PARITY)
            {
                lineControl.Parity = EVEN_PARITY;
            }
            else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_MARK_PARITY)
            {
                lineControl.Parity = MARK_PARITY;
            }
            else if ((lineControlSnapshot & SERIAL_PARITY_MASK) == SERIAL_SPACE_PARITY)
            {
                lineControl.Parity = SPACE_PARITY;
            }

            //
            // Decode the length of the stop bit
            //
            if (lineControlSnapshot & SERIAL_2_STOP)
            {
                if (lineControl.WordLength == 5)
                {
                    lineControl.StopBits = STOP_BITS_1_5;
                }
                else
                {
                    lineControl.StopBits = STOP_BITS_2;
                }
            }
            else
            {
                lineControl.StopBits = STOP_BIT_1;
            }

            //
            // Copy the information that was decoded to the caller's buffer
            //
            pWdfRequest->GetOutputMemory(&outputMemory);
            if (NULL == outputMemory)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
            }

            if (SUCCEEDED(hr))
            {
                hr = outputMemory->CopyFromBuffer(0,
                                                  (void*) &lineControl,
                                                  sizeof(SERIAL_LINE_CONTROL));
            }

            if (SUCCEEDED(hr))
            {
                reqCompletionInfo = sizeof(SERIAL_LINE_CONTROL);
            }

            break;
        }
        case IOCTL_SERIAL_SET_LINE_CONTROL:
        {
            ULONG *pLineControlRegister = NULL;
            SERIAL_LINE_CONTROL lineControl = {0};
            UCHAR lineControlData = 0;
            UCHAR lineControlStop = 0;
            UCHAR lineControlParity = 0;
            ULONG lineControlSnapshot;
            ULONG lineControlNew;
            ULONG lineControlPrevious;

            pLineControlRegister = m_Device->GetLineControlRegisterPtr();
            WUDF_TEST_DRIVER_ASSERT(pLineControlRegister);

            //
            // This is a driver for a virtual serial port. Since there is no
            // actual hardware, we just store the line control register
            // configuration and don't do anything with it.
            //
            pWdfRequest->GetInputMemory(&inputMemory);
            if (NULL == inputMemory)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
            }

            if (SUCCEEDED(hr))
            {
                hr = inputMemory->CopyToBuffer(0,
                                               (void*) &lineControl,
                                               sizeof(SERIAL_LINE_CONTROL));
            }

            //
            // Bits 0 and 1 of the line control register
            //
            if (SUCCEEDED(hr))
            {
                switch (lineControl.WordLength)
                {
                    case 5:
                        lineControlData = SERIAL_5_DATA;
                        m_Device->SetValidDataMask(0x1f);
                        break;

                    case 6:
                        lineControlData = SERIAL_6_DATA;
                        m_Device->SetValidDataMask(0x3f);
                        break;

                    case 7:
                        lineControlData = SERIAL_7_DATA;
                        m_Device->SetValidDataMask(0x7f);
                        break;

                    case 8:
                        lineControlData = SERIAL_8_DATA;
                        m_Device->SetValidDataMask(0xff);
                        break;

                    default:
                        hr = E_INVALIDARG;
                }
            }

            //
            // Bit 2 of the line control register
            //
            if (SUCCEEDED(hr))
            {
                switch (lineControl.StopBits)
                {
                    case STOP_BIT_1:
                        lineControlStop = SERIAL_1_STOP;
                        break;

                    case STOP_BITS_1_5:
                        if (lineControlData != SERIAL_5_DATA)
                        {
                            hr = E_INVALIDARG;
                            break;
                        }
                        lineControlStop = SERIAL_1_5_STOP;
                        break;

                    case STOP_BITS_2:
                        if (lineControlData == SERIAL_5_DATA)
                        {
                            hr = E_INVALIDARG;
                            break;
                        }
                        lineControlStop = SERIAL_2_STOP;
                        break;

                    default:
                        hr = E_INVALIDARG;
                }
            }

            //
            // Bits 3, 4 and 5 of the line control register
            //
            if (SUCCEEDED(hr))
            {
                switch (lineControl.Parity)
                {
                    case NO_PARITY:
                        lineControlParity = SERIAL_NONE_PARITY;
                        break;

                    case EVEN_PARITY:
                        lineControlParity = SERIAL_EVEN_PARITY;
                        break;

                    case ODD_PARITY:
                        lineControlParity = SERIAL_ODD_PARITY;
                        break;

                    case SPACE_PARITY:
                        lineControlParity = SERIAL_SPACE_PARITY;
                        break;

                    case MARK_PARITY:
                        lineControlParity = SERIAL_MARK_PARITY;
                        break;

                    default:
                        hr = E_INVALIDARG;
                }
            }

            //
            // Update our line control register variable atomically
            //
            i=0;
            do
            {
                i++;
                if ((i & 0xf) == 0)
                {
                    //
                    // We've been spinning in a loop for a while trying to
                    // update the line control register variable atomically.
                    // Yield the CPU for other threads for a while.
                    //
                    SwitchToThread();
                }

                lineControlSnapshot = *pLineControlRegister;

                lineControlNew = (lineControlSnapshot & SERIAL_LCR_BREAK) |
                                    (lineControlData |
                                     lineControlParity |
                                     lineControlStop);

                lineControlPrevious = InterlockedCompareExchange((LONG *) pLineControlRegister,
                                                                 lineControlNew,
                                                                 lineControlSnapshot);

            } while (lineControlPrevious != lineControlSnapshot);

            break;
        }
        case IOCTL_SERIAL_GET_TIMEOUTS:
        {
            SERIAL_TIMEOUTS timeoutValues = {0};

            pWdfRequest->GetOutputMemory(&outputMemory);
            if (NULL == outputMemory)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
            }

            if (SUCCEEDED(hr))
            {
                m_Device->GetTimeouts(&timeoutValues);

                hr = outputMemory->CopyFromBuffer(0,
                                                  (void*) &timeoutValues,
                                                  sizeof(timeoutValues));
            }

            if (SUCCEEDED(hr))
            {
                reqCompletionInfo = sizeof(SERIAL_TIMEOUTS);
            }

            break;
        }
        case IOCTL_SERIAL_SET_TIMEOUTS:
        {
            SERIAL_TIMEOUTS timeoutValues = {0};

            pWdfRequest->GetInputMemory(&inputMemory);
            if (NULL == inputMemory)
            {
                hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
            }

            if (SUCCEEDED(hr))
            {
                hr = inputMemory->CopyToBuffer(0,
                                               (void*) &timeoutValues,
                                               sizeof(timeoutValues));
            }

            if (SUCCEEDED(hr))
            {
                if ((timeoutValues.ReadIntervalTimeout == MAXULONG) &&
                    (timeoutValues.ReadTotalTimeoutMultiplier == MAXULONG) &&
                    (timeoutValues.ReadTotalTimeoutConstant == MAXULONG))
                {
                    hr = E_INVALIDARG;
                }
            }

            if (SUCCEEDED(hr))
            {
                m_Device->SetTimeouts(timeoutValues);
            }

            break;
        }
        
        case IOCTL_SERIAL_SET_QUEUE_SIZE:
        case IOCTL_SERIAL_SET_DTR:
        case IOCTL_SERIAL_SET_WAIT_MASK:
        case IOCTL_SERIAL_SET_RTS:
        case IOCTL_SERIAL_CLR_RTS:
        case IOCTL_SERIAL_SET_XON:
        case IOCTL_SERIAL_SET_XOFF:
        case IOCTL_SERIAL_SET_CHARS:
        case IOCTL_SERIAL_GET_CHARS:
        case IOCTL_SERIAL_GET_HANDFLOW:
        case IOCTL_SERIAL_SET_HANDFLOW:
        case IOCTL_SERIAL_RESET_DEVICE: 
        {
            //
            // NOTE: The application expects STATUS_SUCCESS for these IOCTLs.
            //  so don't merge this with default.
            //
            break;
        }
        
        default:
        {
            hr = E_INVALIDARG;
        }
    }

    //
    // clean up
    //
    if (inputMemory)
    {
        inputMemory->Release();
    }

    if (outputMemory)
    {
        outputMemory->Release();
    }

    //
    // complete the request
    //
    pWdfRequest->CompleteWithInformation(hr, reqCompletionInfo);

    return;
}
Beispiel #8
0
VOID
CMyDevice::ServiceSwitchChangeQueue(
	_In_ SWITCH_STATE NewState,
	_In_ HRESULT CompletionStatus,
	_In_opt_ IWDFFile *SpecificFile
	)
/*++
 
  Routine Description:

	This method processes switch-state change notification requests as 
	part of reading the OSR device's interrupt pipe.  As each read completes
	this pulls all pending I/O off the switch change queue and completes
	each request with the current switch state.

  Arguments:

	NewState - the state of the switches

	CompletionStatus - all pending operations are completed with this status.

	SpecificFile - if provided only requests for this file object will get
				   completed.

  Return Value:

	None

--*/
{
	IWDFIoRequest *fxRequest;
	HRESULT enumHr = S_OK;

	do 
	{
		HRESULT hr;

		//
		// Get the next request.
		//

		if (NULL != SpecificFile)
		{
			enumHr = m_SwitchChangeQueue->RetrieveNextRequestByFileObject(
											SpecificFile,
											&fxRequest
											);
		}
		else
		{
			enumHr = m_SwitchChangeQueue->RetrieveNextRequest(&fxRequest);
		}

		//
		// If we got one then complete it.
		//

		if (SUCCEEDED(enumHr)) 
		{
			if (SUCCEEDED(CompletionStatus)) 
			{
				IWDFMemory *fxMemory;

				//
				// First copy the result to the request buffer.
				//

				fxRequest->GetOutputMemory(&fxMemory );

				hr = fxMemory->CopyFromBuffer(0, 
											  &NewState, 
											  sizeof(SWITCH_STATE));
				fxMemory->Release();
			}
			else 
			{
				hr = CompletionStatus;
			}

			//
			// Complete the request with the status of the copy (or the completion
			// status if that was an error).
			//

			if (SUCCEEDED(hr)) 
			{
				fxRequest->CompleteWithInformation(hr, sizeof(SWITCH_STATE));
			}
			else
			{
				fxRequest->Complete(hr);
			}

			fxRequest->Release();			
		}
	}
	while (SUCCEEDED(enumHr));
}