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;
}
Beispiel #2
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;
}