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; }
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 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; }
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; }
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)); }