summaryrefslogtreecommitdiff
path: root/wpd/WpdBasicHardwareDriver/RS232Target.cpp
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /wpd/WpdBasicHardwareDriver/RS232Target.cpp
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'wpd/WpdBasicHardwareDriver/RS232Target.cpp')
-rw-r--r--wpd/WpdBasicHardwareDriver/RS232Target.cpp433
1 files changed, 433 insertions, 0 deletions
diff --git a/wpd/WpdBasicHardwareDriver/RS232Target.cpp b/wpd/WpdBasicHardwareDriver/RS232Target.cpp
new file mode 100644
index 00000000..bedfecd2
--- /dev/null
+++ b/wpd/WpdBasicHardwareDriver/RS232Target.cpp
@@ -0,0 +1,433 @@
+#include "stdafx.h"
+
+#include "RS232Target.tmh"
+
+RS232Target::RS232Target() :
+ m_cRef(1), m_pBaseDriver(NULL)
+{
+}
+
+RS232Target::~RS232Target()
+{
+ Delete();
+}
+
+ULONG __stdcall RS232Target::AddRef()
+{
+ InterlockedIncrement((long*) &m_cRef);
+ return m_cRef;
+}
+
+ULONG __stdcall RS232Target::Release()
+{
+ ULONG ulRefCount = m_cRef - 1;
+
+ if (InterlockedDecrement((long*) &m_cRef) == 0)
+ {
+ delete this;
+ return 0;
+ }
+ return ulRefCount;
+}
+
+HRESULT __stdcall RS232Target::QueryInterface(
+ REFIID riid,
+ void** ppv)
+{
+ HRESULT hr = S_OK;
+
+ if(riid == IID_IUnknown)
+ {
+ *ppv = static_cast<IUnknown*>(this);
+ AddRef();
+ }
+ if(riid == __uuidof(IRequestCallbackRequestCompletion))
+ {
+ *ppv = static_cast<IRequestCallbackRequestCompletion*>(this);
+ AddRef();
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+ return hr;
+}
+
+
+
+/**
+ * This method is called to initialize the RS232 I/O Target
+ */
+HRESULT RS232Target::Create(_In_ WpdBaseDriver* pBaseDriver,
+ _In_ IWDFDevice* pDevice,
+ HANDLE hRS232Port)
+{
+ CComPtr<IWDFFileHandleTargetFactory> pFileHandleTargetFactory;
+
+ HRESULT hr = S_OK;
+
+ if (pDevice == NULL)
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "NULL parameter received for IWDFDevice");
+ return hr;
+ }
+
+ m_pWDFDevice = pDevice;
+ m_pBaseDriver = pBaseDriver;
+
+ hr = m_pWDFDevice->QueryInterface(IID_PPV_ARGS(&pFileHandleTargetFactory));
+ CHECK_HR(hr, "QI of IID_IWDFFileHandleTargetFactory failed");
+
+ if (hr == S_OK)
+ {
+ hr = pFileHandleTargetFactory->CreateFileHandleTarget(hRS232Port, &m_pFileTarget);
+ CHECK_HR(hr, "Failed to create an I/O Target for the port file handle");
+ }
+
+ if (hr == S_OK)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE,
+ "%!FUNC! Created win32 I/O target %p for handle %p", m_pFileTarget, hRS232Port);
+ }
+
+ return hr;
+}
+
+/**
+ * This method is called to remove the RS232 I/O Target object
+ * and do any cleanup
+ */
+void RS232Target::Delete()
+{
+ if (m_pFileTarget)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE,
+ "%!FUNC! Deleted win32 I/O target %p", m_pFileTarget);
+ m_pFileTarget = NULL;
+ }
+
+ if (m_pWDFDevice)
+ {
+ m_pWDFDevice = NULL;
+ }
+
+ if (m_pBaseDriver)
+ {
+ m_pBaseDriver = NULL;
+ }
+}
+
+/**
+ * This method is called to start the RS232 I/O Target after it
+ * it has been created
+ */
+HRESULT RS232Target::Start()
+{
+ CComPtr<IWDFIoTargetStateManagement> pStateMgmt;
+
+ HRESULT hr = S_OK;
+
+ if (m_pFileTarget)
+ {
+ hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
+ CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target");
+
+ if (hr == S_OK)
+ {
+ hr = pStateMgmt->Start();
+ CHECK_HR(hr, "Failed to start the I/O target");
+ }
+
+ if (hr == S_OK && IsReady())
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! I/O target ready. Sending read request");
+ hr = SendReadRequest();
+ CHECK_HR(hr, "SendReadRequest failed");
+ }
+ }
+ return hr;
+}
+
+/**
+ * This method is called to stop the RS232 I/O Target
+ * if it is currently running
+ */
+HRESULT RS232Target::Stop()
+{
+ CComPtr<IWDFIoTargetStateManagement> pStateMgmt;
+
+ HRESULT hr = S_OK;
+
+ // Stop the target only if it is started.
+ if (m_pFileTarget && (WdfIoTargetStarted == GetState()))
+ {
+ hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
+ CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target");
+
+ if (hr == S_OK)
+ {
+ // Stop the target, and cancel sent I/O
+ hr = pStateMgmt->Stop(WdfIoTargetCancelSentIo);
+ CHECK_HR(hr, "Failed to stop the I/O target");
+ }
+
+ if (hr == S_OK)
+ {
+ TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_FLAG_DEVICE, "%!FUNC! S_OK");
+ }
+ }
+ return hr;
+}
+
+/**
+ * This method is called to return the current state of the RS232 I/O Target
+ */
+WDF_IO_TARGET_STATE RS232Target::GetState()
+{
+ CComPtr<IWDFIoTargetStateManagement> pStateMgmt;
+
+ WDF_IO_TARGET_STATE State = WdfIoTargetStateUndefined;
+ HRESULT hr = S_OK;
+
+ if (m_pFileTarget)
+ {
+ hr = m_pFileTarget->QueryInterface(IID_PPV_ARGS(&pStateMgmt));
+ CHECK_HR(hr, "Failed to QI IWDFIoTargetStateManagement from the I/O target");
+
+ if (hr == S_OK)
+ {
+ State = pStateMgmt->GetState();
+ }
+ }
+ return State;
+}
+
+
+/**
+ * This method returns TRUE is the target is ready to receive requests
+ */
+BOOL RS232Target::IsReady()
+{
+ if (WdfIoTargetStarted == GetState())
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ * This method is called to dispatch an asynchronous read request to the RS232 I/O Target
+ * with a completion callback
+ */
+HRESULT RS232Target::SendReadRequest()
+{
+ CComPtr<IWDFDriver> pWdfDriver;
+ CComPtr<IWDFFile> pWdfFile;
+ CComPtr<IWDFMemory> pWdfBuffer;
+ CComPtr<IWDFIoRequest> pWdfReadRequest;
+ CComPtr<IRequestCallbackRequestCompletion> pCompletionCallback;
+
+ HRESULT hr = S_OK;
+
+ if (m_pWDFDevice == NULL || m_pFileTarget == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
+ CHECK_HR(hr, "Device is not ready to receive read requests");
+ return hr;
+ }
+
+ m_pWDFDevice->GetDriver(&pWdfDriver);
+
+ ZeroMemory((void*)m_pReadBuffer, sizeof(m_pReadBuffer));
+
+ // Create the WDF memory buffer
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(m_pReadBuffer,
+ sizeof(m_pReadBuffer),
+ NULL, // no object event callback
+ NULL, // driver object as parent
+ &pWdfBuffer);
+ CHECK_HR(hr, "Failed to create the pre-allocaed WDF memory");
+
+ if (hr == S_OK)
+ {
+ hr = m_pWDFDevice->CreateRequest(NULL, // no object event callback
+ m_pWDFDevice, // device object as parent
+ &pWdfReadRequest);
+
+ CHECK_HR(hr, "Failed to create a WDF request");
+ }
+
+ if (hr == S_OK)
+ {
+ // Format the read request
+ m_pFileTarget->GetTargetFile(&pWdfFile);
+
+ hr = m_pFileTarget->FormatRequestForRead(pWdfReadRequest,
+ pWdfFile,
+ pWdfBuffer,
+ NULL, // no memory offset
+ NULL); // no device offset
+
+ CHECK_HR(hr, "Failed to format the WDF request for read");
+ }
+
+ if (hr == S_OK)
+ {
+ this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback));
+
+ // Set the completion callback
+ pWdfReadRequest->SetCompletionCallback(pCompletionCallback, NULL);
+
+ hr = pWdfReadRequest->Send(m_pFileTarget, 0, 0);
+ CHECK_HR(hr, "Failed to send the read request");
+ }
+
+ if (FAILED(hr))
+ {
+ // Cleanup on failure
+ if (pWdfReadRequest)
+ {
+ pWdfReadRequest->DeleteWdfObject();
+ }
+ }
+
+ return hr;
+}
+
+
+/**
+ * This method is called to dispatch an asynchronous write request to the RS232 I/O Target
+ * with a completion callback
+ */
+HRESULT RS232Target::SendWriteRequest(
+ _In_reads_(cbBufferSize) BYTE* pBuffer,
+ size_t cbBufferSize)
+{
+ CComPtr<IWDFDriver> pWdfDriver;
+ CComPtr<IWDFFile> pWdfFile;
+ CComPtr<IWDFMemory> pWdfBuffer;
+ CComPtr<IWDFIoRequest> pWdfWriteRequest;
+ CComPtr<IRequestCallbackRequestCompletion> pCompletionCallback;
+
+ HRESULT hr = S_OK;
+
+ if (pBuffer == NULL)
+ {
+ hr = E_POINTER;
+ CHECK_HR(hr, "A NULL buffer parameter was received");
+ return hr;
+ }
+
+ if (m_pWDFDevice == NULL || m_pFileTarget == NULL)
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
+ CHECK_HR(hr, "Device is not ready to receive write requests");
+ }
+
+ m_pWDFDevice->GetDriver(&pWdfDriver);
+ m_pFileTarget->GetTargetFile(&pWdfFile);
+
+ // Create the WDF memory buffer
+ hr = pWdfDriver->CreatePreallocatedWdfMemory(pBuffer,
+ cbBufferSize,
+ NULL, // no object event callback
+ NULL, // driver object as parent
+ &pWdfBuffer);
+ CHECK_HR(hr, "Failed to create a pre-allocaed Wdf memory buffer from the input buffer of size %d", static_cast<DWORD>(cbBufferSize));
+
+ if (hr == S_OK)
+ {
+ hr = m_pWDFDevice->CreateRequest(NULL, // no object event callback
+ m_pWDFDevice, // device object as parent
+ &pWdfWriteRequest);
+
+ CHECK_HR(hr, "Failed to create a WDF request");
+ }
+
+ if (hr == S_OK)
+ {
+ hr = m_pFileTarget->FormatRequestForWrite(pWdfWriteRequest,
+ pWdfFile,
+ pWdfBuffer,
+ NULL, // no memory offset
+ NULL); // no device offset
+
+ CHECK_HR(hr, "Failed to format the WDF request for write");
+ }
+
+ if (hr == S_OK)
+ {
+ this->QueryInterface(IID_PPV_ARGS(&pCompletionCallback));
+
+ // Set the completion callback
+ pWdfWriteRequest->SetCompletionCallback(pCompletionCallback, NULL);
+
+ hr = pWdfWriteRequest->Send(m_pFileTarget, 0, 0);
+ CHECK_HR(hr, "Failed to send the write request");
+ }
+
+ if (FAILED(hr))
+ {
+ // Cleanup on failure
+ if (pWdfWriteRequest)
+ {
+ pWdfWriteRequest->DeleteWdfObject();
+ }
+ }
+
+ return hr;
+}
+
+
+/**
+ * This callback method is called by UMDF on the completion of the asynchronous reads and writes
+ */
+void RS232Target::OnCompletion(
+ _In_ IWDFIoRequest* pWdfRequest,
+ _In_ IWDFIoTarget* pIoTarget,
+ _In_ IWDFRequestCompletionParams* pParams,
+ _In_ PVOID pContext)
+{
+ UNREFERENCED_PARAMETER(pIoTarget);
+ UNREFERENCED_PARAMETER(pContext);
+ UNREFERENCED_PARAMETER(pParams);
+
+ CComPtr<IWDFRequestCompletionParams> pCompletionParams;
+ HRESULT hr = S_OK;
+
+ // Get the request completion status
+ pWdfRequest->GetCompletionParams(&pCompletionParams);
+
+ HRESULT hrStatus = pCompletionParams->GetCompletionStatus();
+ WDF_REQUEST_TYPE RequestType = pCompletionParams->GetCompletedRequestType();
+
+ if (RequestType == WdfRequestRead)
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DEVICE, "%!FUNC! Read Status %!HRESULT!", hrStatus);
+
+ // Retrieve the data from the completed read request if successful
+ if (SUCCEEDED(hrStatus) && m_pBaseDriver)
+ {
+ m_pBaseDriver->ProcessReadData(m_pReadBuffer, sizeof(m_pReadBuffer));
+ }
+
+ // Send another read request if the target is not stopped or removed
+ if (IsReady())
+ {
+ hr = SendReadRequest();
+ CHECK_HR(hr, "SendReadRequest failed");
+ }
+
+
+ }
+ else if (RequestType == WdfRequestWrite)
+ {
+ TraceEvents(TRACE_LEVEL_VERBOSE, TRACE_FLAG_DEVICE, "%!FUNC! Write Status %!HRESULT!", hrStatus);
+ }
+
+ // Clean up the existing request
+ pWdfRequest->DeleteWdfObject();
+}