summaryrefslogtreecommitdiff
path: root/spb/SkeletonI2C/device.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'spb/SkeletonI2C/device.cpp')
-rw-r--r--spb/SkeletonI2C/device.cpp2268
1 files changed, 0 insertions, 2268 deletions
diff --git a/spb/SkeletonI2C/device.cpp b/spb/SkeletonI2C/device.cpp
deleted file mode 100644
index 7b6747e2..00000000
--- a/spb/SkeletonI2C/device.cpp
+++ /dev/null
@@ -1,2268 +0,0 @@
-/*++
-
-Copyright (c) Microsoft Corporation. All rights reserved.
-
-Module Name:
-
- device.cpp
-
-Abstract:
-
- This module contains WDF device initialization
- and SPB callback functions for the controller driver.
-
-Environment:
-
- kernel-mode only
-
-Revision History:
-
---*/
-
-#include "internal.h"
-#include "device.h"
-#include "controller.h"
-
-#include "device.tmh"
-
-
-/////////////////////////////////////////////////
-//
-// WDF and SPB DDI callbacks.
-//
-/////////////////////////////////////////////////
-
-NTSTATUS
-OnPrepareHardware(
- _In_ WDFDEVICE FxDevice,
- _In_ WDFCMRESLIST FxResourcesRaw,
- _In_ WDFCMRESLIST FxResourcesTranslated
- )
-/*++
-
- Routine Description:
-
- This routine maps the hardware resources to the SPB
- controller register structure.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
- FxResourcesRaw - list of translated hardware resources that
- the PnP manager has assigned to the device
- FxResourcesTranslated - list of raw hardware resources that
- the PnP manager has assigned to the device
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
- NT_ASSERT(pDevice != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- UNREFERENCED_PARAMETER(FxResourcesRaw);
-
- //
- // Get the register base for the I2C controller.
- //
-
- {
- ULONG resourceCount = WdfCmResourceListGetCount(FxResourcesTranslated);
-
- for(ULONG i = 0; i < resourceCount; i++)
- {
- PCM_PARTIAL_RESOURCE_DESCRIPTOR res;
-
- res = WdfCmResourceListGetDescriptor(FxResourcesTranslated, i);
-
- if (res->Type == CmResourceTypeMemory)
- {
- pDevice->pRegisters =
- (PSKELETONI2C_REGISTERS) MmMapIoSpaceEx(
- res->u.Memory.Start,
- res->u.Memory.Length,
- PAGE_NOCACHE | PAGE_READWRITE);
-
- pDevice->RegistersCb = res->u.Memory.Length;
-
- if (pDevice->pRegisters == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
-
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_WDFLOADING,
- "Error mapping controller registers (PA:%I64x, length:%d) "
- "for WDFDEVICE %p - %!STATUS!",
- res->u.Memory.Start.QuadPart,
- res->u.Memory.Length,
- pDevice->FxDevice,
- status);
-
- NT_ASSERT(pDevice->pRegisters != NULL);
-
- goto exit;
- }
-
- //
- // Save the physical address to help identify
- // the underlying controller while debugging.
- //
-
- pDevice->pRegistersPhysicalAddress = res->u.Memory.Start;
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_WDFLOADING,
- "I2C controller @ paddr %I64x vaddr @ %p for WDFDEVICE %p",
- pDevice->pRegistersPhysicalAddress.QuadPart,
- pDevice->pRegisters,
- pDevice->FxDevice);
- }
- }
- }
-
-exit:
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return status;
-}
-
-NTSTATUS
-OnReleaseHardware(
- _In_ WDFDEVICE FxDevice,
- _In_ WDFCMRESLIST FxResourcesTranslated
- )
-/*++
-
- Routine Description:
-
- This routine unmaps the SPB controller register structure.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
- FxResourcesRaw - list of translated hardware resources that
- the PnP manager has assigned to the device
- FxResourcesTranslated - list of raw hardware resources that
- the PnP manager has assigned to the device
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
- NT_ASSERT(pDevice != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- UNREFERENCED_PARAMETER(FxResourcesTranslated);
-
- if (pDevice->pRegisters != NULL)
- {
- MmUnmapIoSpace(pDevice->pRegisters, pDevice->RegistersCb);
-
- pDevice->pRegisters = NULL;
- pDevice->RegistersCb = 0;
- }
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return status;
-}
-
-NTSTATUS
-OnD0Entry(
- _In_ WDFDEVICE FxDevice,
- _In_ WDF_POWER_DEVICE_STATE FxPreviousState
- )
-/*++
-
- Routine Description:
-
- This routine allocates objects needed by the driver
- and initializes the controller hardware.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
- FxPreviousState - previous power state
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
- NT_ASSERT(pDevice != NULL);
-
- UNREFERENCED_PARAMETER(FxPreviousState);
-
- //
- // Initialize controller.
- //
-
- pDevice->pCurrentTarget = NULL;
-
- ControllerInitialize(pDevice);
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-OnD0Exit(
- _In_ WDFDEVICE FxDevice,
- _In_ WDF_POWER_DEVICE_STATE FxPreviousState
- )
-/*++
-
- Routine Description:
-
- This routine destroys objects needed by the driver
- and uninitializes the controller hardware.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
- FxPreviousState - previous power state
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
- NT_ASSERT(pDevice != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- UNREFERENCED_PARAMETER(FxPreviousState);
-
- //
- // Uninitialize controller.
- //
-
- ControllerUninitialize(pDevice);
-
- pDevice->pCurrentTarget = NULL;
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return status;
-}
-
-NTSTATUS
-OnSelfManagedIoInit(
- _In_ WDFDEVICE FxDevice
- )
-/*++
-
- Routine Description:
-
- Initializes and starts the device's self-managed I/O operations.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
-
- Return Value:
-
- None
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
- NTSTATUS status;
-
- //
- // Register for monitor power setting callback. This will be
- // used to dynamically set the idle timeout delay according
- // to the monitor power state.
- //
-
- NT_ASSERT(pDevice->pMonitorPowerSettingHandle == NULL);
-
- status = PoRegisterPowerSettingCallback(
- WdfDeviceWdmGetDeviceObject(pDevice->FxDevice),
- &GUID_MONITOR_POWER_ON,
- OnMonitorPowerSettingCallback,
- (PVOID)pDevice->FxDevice,
- &pDevice->pMonitorPowerSettingHandle);
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_WDFLOADING,
- "Failed to register monitor power setting callback - %!STATUS!",
- status);
-
- goto exit;
- }
-
-exit:
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return status;
-}
-
-VOID
-OnSelfManagedIoCleanup(
- _In_ WDFDEVICE FxDevice
- )
-/*++
-
- Routine Description:
-
- Cleanup for the device's self-managed I/O operations.
-
- Arguments:
-
- FxDevice - a handle to the framework device object
-
- Return Value:
-
- None
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- PPBC_DEVICE pDevice = GetDeviceContext(FxDevice);
-
- //
- // Unregister for monitor power setting callback.
- //
-
- if (pDevice->pMonitorPowerSettingHandle != NULL)
- {
- PoUnregisterPowerSettingCallback(pDevice->pMonitorPowerSettingHandle);
- pDevice->pMonitorPowerSettingHandle = NULL;
- }
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-}
-
-__drv_functionClass(POWER_SETTING_CALLBACK)
-_IRQL_requires_same_
-NTSTATUS
-OnMonitorPowerSettingCallback(
- _In_ LPCGUID SettingGuid,
- _In_reads_bytes_(ValueLength) PVOID Value,
- _In_ ULONG ValueLength,
- _Inout_opt_ PVOID Context
- )
-/*++
-
- Routine Description:
-
- This routine updates the idle timeout delay according
- to the current monitor power setting.
-
- Arguments:
-
- SettingGuid - the setting GUID
- Value - pointer to the new value of the power setting that changed
- ValueLength - value of type ULONG that specifies the size, in bytes,
- of the new power setting value
- Context - the WDFDEVICE pointer context
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_WDFLOADING);
-
- UNREFERENCED_PARAMETER(ValueLength);
-
- WDFDEVICE Device;
- WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings;
- BOOLEAN isMonitorOff;
- NTSTATUS status = STATUS_SUCCESS;
-
- if (Context == NULL)
- {
- status = STATUS_INVALID_PARAMETER;
-
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_WDFLOADING,
- "%!FUNC! parameter Context is NULL - %!STATUS!",
- status);
-
- goto exit;
- }
-
- Device = (WDFDEVICE)Context;
-
- //
- // We only expect GUID_MONITOR_POWER_ON notifications
- // in this callback, but let's check just to be sure.
- //
-
- if (IsEqualGUID(*SettingGuid, GUID_MONITOR_POWER_ON))
- {
- NT_ASSERT(Value != NULL);
- NT_ASSERT(ValueLength == sizeof(ULONG));
-
- //
- // Determine power setting.
- //
-
- isMonitorOff = ((*(PULONG)Value) == MONITOR_POWER_OFF);
-
- //
- // Update the idle timeout delay.
- //
-
- WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(
- &idleSettings,
- IdleCannotWakeFromS0);
-
- idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint;
-
- if (isMonitorOff)
- {
- idleSettings.IdleTimeout = IDLE_TIMEOUT_MONITOR_OFF;
- }
- else
- {
- idleSettings.IdleTimeout = IDLE_TIMEOUT_MONITOR_ON;
-
- }
-
- status = WdfDeviceAssignS0IdleSettings(
- Device,
- &idleSettings);
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_WDFLOADING,
- "Failed to assign S0 idle settings - %!STATUS!",
- status);
-
- goto exit;
- }
- }
-
-exit:
-
- FuncExit(TRACE_FLAG_WDFLOADING);
-
- return status;
-}
-
-NTSTATUS
-OnTargetConnect(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget
- )
-/*++
-
- Routine Description:
-
- This routine is invoked whenever a peripheral driver opens
- a target. It retrieves target-specific settings from the
- Resource Hub and saves them in the target's context.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- PPBC_DEVICE pDevice = GetDeviceContext(SpbController);
- PPBC_TARGET pTarget = GetTargetContext(SpbTarget);
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- //
- // Get target connection parameters.
- //
-
- SPB_CONNECTION_PARAMETERS params;
- SPB_CONNECTION_PARAMETERS_INIT(&params);
-
- SpbTargetGetConnectionParameters(SpbTarget, &params);
-
- //
- // Retrieve target settings.
- //
-
- status = PbcTargetGetSettings(pDevice,
- params.ConnectionParameters,
- &pTarget->Settings
- );
-
- //
- // Initialize target context.
- //
-
- if (NT_SUCCESS(status))
- {
- pTarget->SpbTarget = SpbTarget;
- pTarget->pCurrentRequest = NULL;
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Connected to SPBTARGET %p at address 0x%lx from WDFDEVICE %p",
- pTarget->SpbTarget,
- pTarget->Settings.Address,
- pDevice->FxDevice);
- }
-
- FuncExit(TRACE_FLAG_SPBDDI);
-
- return status;
-}
-
-VOID
-OnControllerLock(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest
- )
-/*++
-
- Routine Description:
-
- This routine is invoked whenever the controller is to
- be locked for a single target. The request is only completed
- if there is an error configuring the transfer.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
-
- Return Value:
-
- None. The request is completed synchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- PPBC_DEVICE pDevice = GetDeviceContext(SpbController);
- PPBC_TARGET pTarget = GetTargetContext(SpbTarget);
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Assign current target.
- //
-
- NT_ASSERT(pDevice->pCurrentTarget == NULL);
-
- pDevice->pCurrentTarget = pTarget;
-
- WdfSpinLockRelease(pDevice->Lock);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Controller locked for SPBTARGET %p at address 0x%lx (WDFDEVICE %p)",
- pTarget->SpbTarget,
- pTarget->Settings.Address,
- pDevice->FxDevice);
-
- //
- // Complete lock request.
- //
-
- SpbRequestComplete(SpbRequest, STATUS_SUCCESS);
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnControllerUnlock(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest
- )
-/*++
-
- Routine Description:
-
- This routine is invoked whenever the controller is to
- be unlocked for a single target. The request is only completed
- if there is an error configuring the transfer.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- PPBC_DEVICE pDevice = GetDeviceContext(SpbController);
- PPBC_TARGET pTarget = GetTargetContext(SpbTarget);
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- // TODO: Check if there is an active sequence
- // and if so perform any action necessary
- // to stop the transfer in process.
-
- //
- // Remove current target.
- //
-
- NT_ASSERT(pDevice->pCurrentTarget == pTarget);
-
- pDevice->pCurrentTarget = NULL;
-
- WdfSpinLockRelease(pDevice->Lock);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Controller unlocked for SPBTARGET %p at address 0x%lx (WDFDEVICE %p)",
- pTarget->SpbTarget,
- pTarget->Settings.Address,
- pDevice->FxDevice);
-
- //
- // Complete lock request.
- //
-
- SpbRequestComplete(SpbRequest, STATUS_SUCCESS);
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnRead(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest,
- _In_ size_t Length
- )
-/*++
-
- Routine Description:
-
- This routine sets up a read from the target device using
- the supplied buffers. The request is only completed
- if there is an error configuring the transfer.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
- Length - the number of bytes to read from the target
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Received read request %p of length %Iu for SPBTARGET %p "
- "(WDFDEVICE %p)",
- SpbRequest,
- Length,
- SpbTarget,
- SpbController);
-
- PbcRequestConfigureForNonSequence(
- SpbController,
- SpbTarget,
- SpbRequest,
- Length);
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnWrite(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest,
- _In_ size_t Length
- )
-/*++
-
- Routine Description:
-
- This routine sets up a write to the target device using
- the supplied buffers. The request is only completed
- if there is an error configuring the transfer.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
- Length - the number of bytes to write to the target
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Received write request %p of length %Iu for SPBTARGET %p "
- "(WDFDEVICE %p)",
- SpbRequest,
- Length,
- SpbTarget,
- SpbController);
-
- PbcRequestConfigureForNonSequence(
- SpbController,
- SpbTarget,
- SpbRequest,
- Length);
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnSequence(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest,
- _In_ ULONG TransferCount
- )
-/*++
-
- Routine Description:
-
- This routine sets up a sequence of reads and writes. It
- validates parameters as necessary. The request is only
- completed if there is an error configuring the transfer.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
- TransferCount - number of individual transfers in the sequence
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- PPBC_DEVICE pDevice = GetDeviceContext(SpbController);
- PPBC_TARGET pTarget = GetTargetContext(SpbTarget);
- PPBC_REQUEST pRequest = GetRequestContext(SpbRequest);
- BOOLEAN completeRequest = FALSE;
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
- NT_ASSERT(pRequest != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- //
- // Get request parameters.
- //
-
- SPB_REQUEST_PARAMETERS params;
- SPB_REQUEST_PARAMETERS_INIT(&params);
- SpbRequestGetParameters(SpbRequest, &params);
-
- NT_ASSERT(params.Position == SpbRequestSequencePositionSingle);
- NT_ASSERT(params.Type == SpbRequestTypeSequence);
-
- //
- // Initialize request context.
- //
-
- pRequest->SpbRequest = SpbRequest;
- pRequest->Type = params.Type;
- pRequest->TotalInformation = 0;
- pRequest->TransferCount = TransferCount;
- pRequest->TransferIndex = 0;
- pRequest->bIoComplete = FALSE;
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_SPBDDI,
- "Received sequence request %p with transfer count %d for SPBTARGET %p "
- "(WDFDEVICE %p)",
- pRequest->SpbRequest,
- pRequest->TransferCount,
- SpbTarget,
- SpbController);
-
- //
- // Validate the request before beginning the transfer.
- //
-
- status = PbcRequestValidate(pRequest);
-
- if (!NT_SUCCESS(status))
- {
- goto exit;
- }
-
- //
- // Configure the request.
- //
-
- status = PbcRequestConfigureForIndex(pRequest, 0);
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_SPBDDI,
- "Error configuring request context for SPBREQUEST %p "
- "(SPBTARGET %p) - %!STATUS!",
- pRequest->SpbRequest,
- SpbTarget,
- status);
-
- goto exit;
- }
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Mark request cancellable (if cancellation supported).
- //
-
- status = WdfRequestMarkCancelableEx(
- pRequest->SpbRequest, OnCancel);
-
- if (!NT_SUCCESS(status))
- {
- //
- // WdfRequestMarkCancelableEx should only fail if the request
- // has already been cancelled. If it does fail the request
- // must be completed with the corresponding status.
- //
-
- NT_ASSERTMSG("WdfRequestMarkCancelableEx should only fail if the request has already been cancelled",
- status == STATUS_CANCELLED);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Failed to mark SPBREQUEST %p cancellable - %!STATUS!",
- pRequest->SpbRequest,
- status);
-
- WdfSpinLockRelease(pDevice->Lock);
- goto exit;
- }
-
- //
- // Update device and target contexts.
- //
-
- NT_ASSERT(pDevice->pCurrentTarget == NULL);
- NT_ASSERT(pTarget->pCurrentRequest == NULL);
-
- pDevice->pCurrentTarget = pTarget;
- pTarget->pCurrentRequest = pRequest;
-
- //
- // Configure controller and kick-off read.
- // Request will be completed asynchronously.
- //
-
- PbcRequestDoTransfer(pDevice, pRequest);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (pRequest->bIoComplete)
- {
- completeRequest = TRUE;
- }
-
- WdfSpinLockRelease(pDevice->Lock);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (completeRequest)
- {
- PbcRequestComplete(pRequest);
- }
-
-exit:
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_SPBDDI,
- "Error configuring sequence, completing "
- "SPBREQUEST %p synchronously - %!STATUS!",
- pRequest->SpbRequest,
- status);
-
- SpbRequestComplete(SpbRequest, status);
- }
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnOtherInCallerContext(
- _In_ WDFDEVICE SpbController,
- _In_ WDFREQUEST FxRequest
- )
-/*++
-
- Routine Description:
-
- This routine preprocesses custom IO requests before the framework
- places them in an IO queue. For requests using the SPB transfer list
- format, it calls SpbRequestCaptureIoOtherTransferList to capture the
- client's buffers.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbRequest - a handle to the SPBREQUEST object
-
- Return Value:
-
- None. The request is either completed or enqueued asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- NTSTATUS status;
-
- //
- // Check for custom IOCTLs that this driver handles. If
- // unrecognized mark as STATUS_NOT_SUPPORTED and complete.
- //
-
- WDF_REQUEST_PARAMETERS fxParams;
- WDF_REQUEST_PARAMETERS_INIT(&fxParams);
-
- WdfRequestGetParameters(FxRequest, &fxParams);
-
- if ((fxParams.Type != WdfRequestTypeDeviceControl) &&
- (fxParams.Type != WdfRequestTypeDeviceControlInternal))
- {
- status = STATUS_NOT_SUPPORTED;
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_SPBDDI,
- "FxRequest %p is of unsupported request type - %!STATUS!",
- FxRequest,
- status
- );
- goto exit;
- }
-
- //
- // TODO: verify the driver supports this DeviceIoContol code,
- // otherwise mark as STATUS_NOT_SUPPORTED and complete.
- //
-
- //
- // For custom IOCTLs that use the SPB transfer list format
- // (i.e. sequence formatting), call SpbRequestCaptureIoOtherTransferList
- // so that the driver can leverage other SPB DDIs for this request.
- //
-
- status = SpbRequestCaptureIoOtherTransferList((SPBREQUEST)FxRequest);
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_SPBDDI,
- "Failed to capture transfer list for custom SpbRequest %p"
- " - %!STATUS!",
- FxRequest,
- status
- );
- goto exit;
- }
-
- //
- // Preprocessing has succeeded, enqueue the request.
- //
-
- status = WdfDeviceEnqueueRequest(SpbController, FxRequest);
-
- if (!NT_SUCCESS(status))
- {
- goto exit;
- }
-
-exit:
-
- if (!NT_SUCCESS(status))
- {
- WdfRequestComplete(FxRequest, status);
- }
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnOther(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest,
- _In_ size_t OutputBufferLength,
- _In_ size_t InputBufferLength,
- _In_ ULONG IoControlCode
- )
-/*++
-
- Routine Description:
-
- This routine processes custom IO requests that are not natively
- supported by the SPB framework extension. For requests using the
- SPB transfer list format, SpbRequestCaptureIoOtherTransferList
- must have been called in the driver's OnOtherInCallerContext routine.
-
- Arguments:
-
- SpbController - a handle to the framework device object
- representing an SPB controller
- SpbTarget - a handle to the SPBTARGET object
- SpbRequest - a handle to the SPBREQUEST object
- OutputBufferLength - the request's output buffer length
- InputBufferLength - the requests input buffer length
- IoControlCode - the device IO control code
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_SPBDDI);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- UNREFERENCED_PARAMETER(SpbController);
- UNREFERENCED_PARAMETER(SpbTarget);
- UNREFERENCED_PARAMETER(SpbRequest);
- UNREFERENCED_PARAMETER(OutputBufferLength);
- UNREFERENCED_PARAMETER(InputBufferLength);
- UNREFERENCED_PARAMETER(IoControlCode);
-
- //
- // TODO: the driver should take the following steps
- //
- // 1. Verify this specific DeviceIoContol code is supported,
- // otherwise mark as STATUS_NOT_SUPPORTED and complete.
- //
- // 2. If this IOCTL uses SPB_TRANSFER_LIST and the driver has
- // called SpbRequestCaptureIoOtherTransferList previously,
- // validate the request format. The driver can make use of
- // SpbRequestGetTransferParameters to retrieve each transfer
- // descriptor.
- //
- // If this IOCTL uses some proprietary buffer formating
- // instead of SPB_TRANSFER_LIST, validate appropriately.
- //
- // 3. Setup the device, target, and request contexts as necessary,
- // and program the hardware for the transfer.
- //
-
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. Note this must be done outside
- // of any locked code.
- SpbRequestComplete(SpbRequest, status);
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-VOID
-OnCancel(
- _In_ WDFREQUEST FxRequest
-)
-
-/*++
-
- Routine Description:
-
- This routine cancels an outstanding request. It
- must synchronize with other driver callbacks.
-
- Arguments:
-
- wdfRequest - a handle to the WDFREQUEST object
-
- Return Value:
-
- None. The request is completed with status.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- SPBREQUEST spbRequest = (SPBREQUEST) FxRequest;
- PPBC_DEVICE pDevice;
- PPBC_TARGET pTarget;
- PPBC_REQUEST pRequest;
- BOOLEAN bTransferCompleted = FALSE;
-
- //
- // Get the contexts.
- //
-
- pDevice = GetDeviceContext(SpbRequestGetController(spbRequest));
- pTarget = GetTargetContext(SpbRequestGetTarget(spbRequest));
- pRequest = GetRequestContext(spbRequest);
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
- NT_ASSERT(pRequest != NULL);
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Make sure the current target and request
- // are valid.
- //
-
- if (pTarget != pDevice->pCurrentTarget)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "Cancel callback without a valid current target for WDFDEVICE %p, "
- "this should only occur if SPBREQUEST %p was already completed",
- pDevice->FxDevice,
- spbRequest
- );
-
- goto exit;
- }
-
- if (pRequest != pTarget->pCurrentRequest)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "Cancel callback without a valid current request for SPBTARGET %p, "
- "this should only occur if SPBREQUEST %p was already completed",
- pTarget->SpbTarget,
- spbRequest);
-
- goto exit;
- }
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Cancel callback with outstanding SPBREQUEST %p, "
- "stop IO and complete it",
- spbRequest);
-
- //
- // Stop delay timer.
- //
-
- if(WdfTimerStop(pDevice->DelayTimer, FALSE))
- {
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Delay timer previously schedule, now stopped");
- }
-
- //
- // Disable interrupts and clear saved stat for DPC.
- // Must synchronize with ISR.
- //
-
- NT_ASSERT(pDevice->InterruptObject != NULL);
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptAcquireLock(pDevice->InterruptObject);
-
- ControllerDisableInterrupts(pDevice);
- pDevice->InterruptStatus = 0;
-
- //
- // TODO: Implement any necessary logic to abort the
- // current IO operation. For I2C this requires
- // driving a stop bit on the bus.
- //
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptReleaseLock(pDevice->InterruptObject);
-
- //
- // Mark request as cancelled and complete.
- //
-
- pRequest->Status = STATUS_CANCELLED;
-
- ControllerCompleteTransfer(pDevice, pRequest, TRUE);
- NT_ASSERT(pRequest->bIoComplete == TRUE);
- bTransferCompleted = TRUE;
-
-exit:
-
- //
- // Release the device lock.
- //
-
- WdfSpinLockRelease(pDevice->Lock);
-
- //
- // Complete the request. There shouldn't be more IO.
- // This must be done outside of the locked code.
- //
-
- if (bTransferCompleted)
- {
- PbcRequestComplete(pRequest);
- }
-
- FuncExit(TRACE_FLAG_SPBDDI);
-}
-
-
-/////////////////////////////////////////////////
-//
-// Interrupt handling functions.
-//
-/////////////////////////////////////////////////
-
-BOOLEAN
-OnInterruptIsr(
- _In_ WDFINTERRUPT Interrupt,
- _In_ ULONG MessageID
- )
-/*++
-
- Routine Description:
-
- This routine responds to interrupts generated by the
- controller. If one is recognized, it queues a DPC for
- processing. The interrupt is acknowledged and subsequent
- interrupts are temporarily disabled.
-
- Arguments:
-
- Interrupt - a handle to a framework interrupt object
- MessageID - message number identifying the device's
- hardware interrupt message (if using MSI)
-
- Return Value:
-
- TRUE if interrupt recognized.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- BOOLEAN interruptRecognized = FALSE;
- ULONG stat;
- PPBC_DEVICE pDevice = GetDeviceContext(
- WdfInterruptGetDevice(Interrupt));
-
- UNREFERENCED_PARAMETER(MessageID);
-
- NT_ASSERT(pDevice != NULL);
-
- //
- // Queue a DPC if the device's interrupt
- // is enabled and active.
- //
-
- stat = ControllerGetInterruptStatus(
- pDevice,
- PbcDeviceGetInterruptMask(pDevice));
-
- if (stat > 0)
- {
- Trace(
- TRACE_LEVEL_VERBOSE,
- TRACE_FLAG_TRANSFER,
- "Interrupt with status 0x%lx for WDFDEVICE %p",
- stat,
- pDevice->FxDevice);
-
- //
- // Save the interrupt status and disable all other
- // interrupts for now. They will be re-enabled
- // in OnInterruptDpc. Queue the DPC.
- //
-
- interruptRecognized = TRUE;
-
- pDevice->InterruptStatus |= (stat);
- ControllerDisableInterrupts(pDevice);
-
- if(!WdfInterruptQueueDpcForIsr(Interrupt))
- {
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Interrupt with status 0x%lx occurred with "
- "DPC already queued for WDFDEVICE %p",
- stat,
- pDevice->FxDevice);
- }
- }
-
- FuncExit(TRACE_FLAG_TRANSFER);
-
- return interruptRecognized;
-}
-
-VOID
-OnInterruptDpc(
- _In_ WDFINTERRUPT Interrupt,
- _In_ WDFOBJECT WdfDevice
- )
-/*++
-
- Routine Description:
-
- This routine processes interrupts from the controller.
- When finished it reenables interrupts as appropriate.
-
- Arguments:
-
- Interrupt - a handle to a framework interrupt object
- WdfDevice - a handle to the framework device object
-
- Return Value:
-
- None.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- PPBC_DEVICE pDevice;
- PPBC_TARGET pTarget;
- PPBC_REQUEST pRequest = NULL;
- ULONG stat;
- BOOLEAN bInterruptsProcessed = FALSE;
- BOOLEAN completeRequest = FALSE;
-
- UNREFERENCED_PARAMETER(Interrupt);
-
- pDevice = GetDeviceContext(WdfDevice);
- NT_ASSERT(pDevice != NULL);
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Make sure the target and request are
- // still valid.
- //
-
- pTarget = pDevice->pCurrentTarget;
-
- if (pTarget == NULL)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "DPC scheduled without a valid current target for WDFDEVICE %p, "
- "this should only occur if the request was already cancelled",
- pDevice->FxDevice);
-
- goto exit;
- }
-
- pRequest = pTarget->pCurrentRequest;
-
- if (pRequest == NULL)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "DPC scheduled without a valid current request for SPBTARGET %p, "
- "this should only occur if the request was already cancelled",
- pTarget->SpbTarget);
-
- goto exit;
- }
-
- NT_ASSERT(pRequest->SpbRequest != NULL);
-
- //
- // Synchronize shared data buffers with ISR.
- // Copy interrupt status and clear shared buffer.
- // If there is a current target and request,
- // a DPC should never occur with interrupt status 0.
- //
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptAcquireLock(Interrupt);
-
- stat = pDevice->InterruptStatus;
- pDevice->InterruptStatus = 0;
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptReleaseLock(Interrupt);
-
- if (stat == 0)
- {
- goto exit;
- }
-
- Trace(
- TRACE_LEVEL_VERBOSE,
- TRACE_FLAG_TRANSFER,
- "DPC for interrupt with status 0x%lx for WDFDEVICE %p",
- stat,
- pDevice->FxDevice);
-
- //
- // Acknowledge and process interrupts.
- //
-
- ControllerAcknowledgeInterrupts(pDevice, stat);
-
- ControllerProcessInterrupts(pDevice, pRequest, stat);
- bInterruptsProcessed = TRUE;
- if (pRequest->bIoComplete)
- {
- completeRequest = TRUE;
- }
-
- //
- // Re-enable interrupts if necessary. Synchronize with ISR.
- //
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptAcquireLock(Interrupt);
-
- ULONG mask = PbcDeviceGetInterruptMask(pDevice);
-
- if (mask > 0)
- {
- Trace(
- TRACE_LEVEL_VERBOSE,
- TRACE_FLAG_TRANSFER,
- "Re-enable interrupts with mask 0x%lx for WDFDEVICE %p",
- mask,
- pDevice->FxDevice);
-
- ControllerEnableInterrupts(pDevice, mask);
- }
-
- // TODO: Uncomment when using interrupts.
- //WdfInterruptReleaseLock(Interrupt);
-
-exit:
-
- //
- // Release the device lock.
- //
-
- WdfSpinLockRelease(pDevice->Lock);
-
- //
- // Complete the request if necessary.
- // This must be done outside of the locked code.
- //
-
- if (bInterruptsProcessed)
- {
- if (completeRequest)
- {
- PbcRequestComplete(pRequest);
- }
- }
-
- FuncExit(TRACE_FLAG_TRANSFER);
-}
-
-
-/////////////////////////////////////////////////
-//
-// PBC functions.
-//
-/////////////////////////////////////////////////
-
-NTSTATUS
-PbcTargetGetSettings(
- _In_ PPBC_DEVICE pDevice,
- _In_ PVOID ConnectionParameters,
- _Out_ PPBC_TARGET_SETTINGS pSettings
- )
-/*++
-
- Routine Description:
-
- This routine populates the target's settings.
-
- Arguments:
-
- pDevice - a pointer to the PBC device context
- ConnectionParameters - a pointer to a blob containing the
- connection parameters
- Settings - a pointer the the target's settings
-
- Return Value:
-
- Status
-
---*/
-{
- FuncEntry(TRACE_FLAG_PBCLOADING);
-
- UNREFERENCED_PARAMETER(pDevice);
-
- NT_ASSERT(ConnectionParameters != nullptr);
- NT_ASSERT(pSettings != nullptr);
-
- PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER connection;
- PPNP_SERIAL_BUS_DESCRIPTOR descriptor;
- PPNP_I2C_SERIAL_BUS_DESCRIPTOR i2cDescriptor;
-
- connection = (PRH_QUERY_CONNECTION_PROPERTIES_OUTPUT_BUFFER)
- ConnectionParameters;
-
- if (connection->PropertiesLength < sizeof(PNP_SERIAL_BUS_DESCRIPTOR))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_PBCLOADING,
- "Invalid connection properties (length = %lu, "
- "expected = %Iu)",
- connection->PropertiesLength,
- sizeof(PNP_SERIAL_BUS_DESCRIPTOR));
-
- return STATUS_INVALID_PARAMETER;
- }
-
- descriptor = (PPNP_SERIAL_BUS_DESCRIPTOR)
- connection->ConnectionProperties;
-
- if (descriptor->SerialBusType != I2C_SERIAL_BUS_TYPE)
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_PBCLOADING,
- "Bus type %c not supported, only I2C",
- descriptor->SerialBusType);
-
- return STATUS_INVALID_PARAMETER;
- }
-
- i2cDescriptor = (PPNP_I2C_SERIAL_BUS_DESCRIPTOR)
- connection->ConnectionProperties;
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_PBCLOADING,
- "I2C Connection Descriptor %p "
- "ConnectionSpeed:%lu "
- "Address:0x%hx",
- i2cDescriptor,
- i2cDescriptor->ConnectionSpeed,
- i2cDescriptor->SlaveAddress);
-
- // Target address
- pSettings->Address = (ULONG)i2cDescriptor->SlaveAddress;
-
- // Address mode
- USHORT i2cFlags = i2cDescriptor->SerialBusDescriptor.TypeSpecificFlags;
- pSettings->AddressMode =
- ((i2cFlags & I2C_SERIAL_BUS_SPECIFIC_FLAG_10BIT_ADDRESS) == 0) ?
- AddressMode7Bit : AddressMode10Bit;
-
- // Clock speed
- pSettings->ConnectionSpeed = i2cDescriptor->ConnectionSpeed;
-
- FuncExit(TRACE_FLAG_PBCLOADING);
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-PbcRequestValidate(
- _In_ PPBC_REQUEST pRequest)
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- SPB_TRANSFER_DESCRIPTOR descriptor;
- NTSTATUS status = STATUS_SUCCESS;
-
- //
- // Validate each transfer descriptor.
- //
-
- for (ULONG i = 0; i < pRequest->TransferCount; i++)
- {
- //
- // Get transfer parameters for index.
- //
-
- SPB_TRANSFER_DESCRIPTOR_INIT(&descriptor);
-
- SpbRequestGetTransferParameters(
- pRequest->SpbRequest,
- i,
- &descriptor,
- nullptr);
-
- //
- // Validate the transfer length.
- //
-
- if (descriptor.TransferLength > SI2C_MAX_TRANSFER_LENGTH)
- {
- status = STATUS_INVALID_PARAMETER;
-
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_TRANSFER,
- "Transfer length %Iu is too large for controller driver, "
- "max supported is %d (SPBREQUEST %p, index %lu) - %!STATUS!",
- descriptor.TransferLength,
- SI2C_MAX_TRANSFER_LENGTH,
- pRequest->SpbRequest,
- i,
- status);
-
- goto exit;
- }
- }
-
-exit:
-
- FuncExit(TRACE_FLAG_TRANSFER);
-
- return status;
-}
-
-VOID
-PbcRequestConfigureForNonSequence(
- _In_ WDFDEVICE SpbController,
- _In_ SPBTARGET SpbTarget,
- _In_ SPBREQUEST SpbRequest,
- _In_ size_t Length
- )
-/*++
-
- Routine Description:
-
- This is a generic helper routine used to configure
- the request context and controller hardware for a non-
- sequence SPB request. It validates parameters and retrieves
- the transfer buffer as necessary.
-
- Arguments:
-
- pDevice - a pointer to the PBC device context
- pTarget - a pointer to the PBC target context
- pRequest - a pointer to the PBC request context
- Length - the number of bytes to read from the target
- Direction - direction of the transfer
-
- Return Value:
-
- STATUS
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- PPBC_DEVICE pDevice = GetDeviceContext(SpbController);
- PPBC_TARGET pTarget = GetTargetContext(SpbTarget);
- PPBC_REQUEST pRequest = GetRequestContext(SpbRequest);
- BOOLEAN completeRequest = FALSE;
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pTarget != NULL);
- NT_ASSERT(pRequest != NULL);
-
- UNREFERENCED_PARAMETER(Length);
-
- NTSTATUS status;
-
- //
- // Get the request parameters.
- //
-
- SPB_REQUEST_PARAMETERS params;
- SPB_REQUEST_PARAMETERS_INIT(&params);
- SpbRequestGetParameters(SpbRequest, &params);
-
- //
- // Initialize request context.
- //
-
- pRequest->SpbRequest = SpbRequest;
- pRequest->Type = params.Type;
- pRequest->SequencePosition = params.Position;
- pRequest->TotalInformation = 0;
- pRequest->TransferCount = 1;
- pRequest->TransferIndex = 0;
- pRequest->bIoComplete = FALSE;
-
- //
- // Validate the request before beginning the transfer.
- //
-
- status = PbcRequestValidate(pRequest);
-
- if (!NT_SUCCESS(status))
- {
- goto exit;
- }
-
- //
- // Configure the request.
- //
-
- status = PbcRequestConfigureForIndex(
- pRequest,
- pRequest->TransferIndex);
-
- if (!NT_SUCCESS(status))
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_SPBDDI,
- "Error configuring request context for SPBREQUEST %p (SPBTARGET %p)"
- "- %!STATUS!",
- pRequest->SpbRequest,
- SpbTarget,
- status);
-
- goto exit;
- }
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Mark request cancellable (if cancellation supported).
- //
-
- status = WdfRequestMarkCancelableEx(
- pRequest->SpbRequest, OnCancel);
-
- if (!NT_SUCCESS(status))
- {
- //
- // WdfRequestMarkCancelableEx should only fail if the request
- // has already been cancelled. If it does fail the request
- // must be completed with the corresponding status.
- //
-
- NT_ASSERTMSG("WdfRequestMarkCancelableEx should only fail if the request has already been cancelled",
- status == STATUS_CANCELLED);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Failed to mark SPBREQUEST %p cancellable - %!STATUS!",
- pRequest->SpbRequest,
- status);
-
- WdfSpinLockRelease(pDevice->Lock);
- goto exit;
- }
-
- //
- // If sequence position is...
- // - single: ensure there is not a current target
- // - not single: ensure that the current target is the
- // same as this target
- //
-
- if (params.Position == SpbRequestSequencePositionSingle)
- {
- NT_ASSERT(pDevice->pCurrentTarget == NULL);
- }
- else
- {
- NT_ASSERT(pDevice->pCurrentTarget == pTarget);
- }
-
- //
- // Ensure there is not a current request.
- //
-
- NT_ASSERT(pTarget->pCurrentRequest == NULL);
-
- //
- // Update the device and target contexts.
- //
-
- if (pRequest->SequencePosition == SpbRequestSequencePositionSingle)
- {
- pDevice->pCurrentTarget = pTarget;
- }
-
- pTarget->pCurrentRequest = pRequest;
-
- //
- // Configure controller and kick-off read.
- // Request will be completed asynchronously.
- //
-
- PbcRequestDoTransfer(pDevice, pRequest);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (pRequest->bIoComplete)
- {
- completeRequest = TRUE;
- }
-
- WdfSpinLockRelease(pDevice->Lock);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (completeRequest)
- {
- PbcRequestComplete(pRequest);
- }
-
-exit:
-
- if (!NT_SUCCESS(status))
- {
- SpbRequestComplete(SpbRequest, status);
- }
-
- FuncExit(TRACE_FLAG_TRANSFER);
-}
-
-NTSTATUS
-PbcRequestConfigureForIndex(
- _Inout_ PPBC_REQUEST pRequest,
- _In_ ULONG Index
- )
-/*++
-
- Routine Description:
-
- This is a helper routine used to configure the request
- context and controller hardware for a transfer within a
- sequence. It validates parameters and retrieves
- the transfer buffer as necessary.
-
- Arguments:
-
- pRequest - a pointer to the PBC request context
- Index - index of the transfer within the sequence
-
- Return Value:
-
- STATUS
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- NT_ASSERT(pRequest != NULL);
-
- NTSTATUS status = STATUS_SUCCESS;
-
- //
- // Get transfer parameters for index.
- //
-
- SPB_TRANSFER_DESCRIPTOR descriptor;
- PMDL pMdl;
-
- SPB_TRANSFER_DESCRIPTOR_INIT(&descriptor);
-
- SpbRequestGetTransferParameters(
- pRequest->SpbRequest,
- Index,
- &descriptor,
- &pMdl);
-
- NT_ASSERT(pMdl != NULL);
-
- //
- // Configure request context.
- //
-
- pRequest->pMdlChain = pMdl;
- pRequest->Length = descriptor.TransferLength;
- pRequest->Information = 0;
- pRequest->Direction = descriptor.Direction;
- pRequest->DelayInUs = descriptor.DelayInUs;
-
- //
- // Update sequence position if request is type sequence.
- //
-
- if (pRequest->Type == SpbRequestTypeSequence)
- {
- if (pRequest->TransferCount == 1)
- {
- pRequest->SequencePosition = SpbRequestSequencePositionSingle;
- }
- else if (Index == 0)
- {
- pRequest->SequencePosition = SpbRequestSequencePositionFirst;
- }
- else if (Index == (pRequest->TransferCount - 1))
- {
- pRequest->SequencePosition = SpbRequestSequencePositionLast;
- }
- else
- {
- pRequest->SequencePosition = SpbRequestSequencePositionContinue;
- }
- }
-
- PPBC_TARGET pTarget = GetTargetContext(SpbRequestGetTarget(pRequest->SpbRequest));
- NT_ASSERT(pTarget != NULL);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Request context configured for %s (index %lu) "
- "to address 0x%lx (SPBTARGET %p)",
- pRequest->Direction == SpbTransferDirectionFromDevice ? "read" : "write",
- Index,
- pTarget->Settings.Address,
- pTarget->SpbTarget);
-
- FuncExit(TRACE_FLAG_TRANSFER);
-
- return status;
-}
-
-VOID
-PbcRequestDoTransfer(
- _In_ PPBC_DEVICE pDevice,
- _In_ PPBC_REQUEST pRequest
- )
-/*++
-
- Routine Description:
-
- This routine either starts the delay timer or
- kicks off the transfer depending on the request
- parameters.
-
- Arguments:
-
- pDevice - a pointer to the PBC device context
- pRequest - a pointer to the PBC request context
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- NT_ASSERT(pDevice != NULL);
- NT_ASSERT(pRequest != NULL);
-
- //
- // Start delay timer if necessary for this request,
- // otherwise continue transfer.
- //
- // NOTE: Note using a timer to implement IO delay is only
- // applicable for sufficiently long delays (> 15ms).
- // For shorter delays, especially on the order of
- // microseconds, consider using a different mechanism.
- //
-
- if (pRequest->DelayInUs > 0)
- {
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Delaying %lu us before configuring transfer for WDFDEVICE %p",
- pRequest->DelayInUs,
- pDevice->FxDevice);
-
- BOOLEAN bTimerAlreadyStarted;
-
- bTimerAlreadyStarted = WdfTimerStart(
- pDevice->DelayTimer,
- WDF_REL_TIMEOUT_IN_US(pRequest->DelayInUs));
-
- //
- // There should never be another request
- // scheduled for delay.
- //
-
- if (bTimerAlreadyStarted == TRUE)
- {
- Trace(
- TRACE_LEVEL_ERROR,
- TRACE_FLAG_TRANSFER,
- "The delay timer should not be started");
- }
- }
- else
- {
- ControllerConfigureForTransfer(pDevice, pRequest);
- }
-
- FuncExit(TRACE_FLAG_TRANSFER);
-}
-
-VOID
-OnDelayTimerExpired(
- _In_ WDFTIMER Timer
- )
-/*++
-
- Routine Description:
-
- This routine is invoked whenever the driver's delay
- timer expires. It kicks off the transfer for the request.
-
- Arguments:
-
- Timer - a handle to a framework timer object
-
- Return Value:
-
- None.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- WDFDEVICE fxDevice;
- PPBC_DEVICE pDevice;
- PPBC_TARGET pTarget = NULL;
- PPBC_REQUEST pRequest = NULL;
- BOOLEAN completeRequest = FALSE;
-
- fxDevice = (WDFDEVICE) WdfTimerGetParentObject(Timer);
- pDevice = GetDeviceContext(fxDevice);
-
- NT_ASSERT(pDevice != NULL);
-
- //
- // Acquire the device lock.
- //
-
- WdfSpinLockAcquire(pDevice->Lock);
-
- //
- // Make sure the target and request are
- // still valid.
- //
-
- pTarget = pDevice->pCurrentTarget;
-
- if (pTarget == NULL)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "Delay timer expired without a valid current target for WDFDEVICE %p, "
- "this should only occur if the request was already completed",
- pDevice->FxDevice);
-
- goto exit;
- }
-
- pRequest = pTarget->pCurrentRequest;
-
- if (pRequest == NULL)
- {
- Trace(
- TRACE_LEVEL_WARNING,
- TRACE_FLAG_TRANSFER,
- "Delay timer expired without a valid current request for SPBTARGET %p, "
- "this should only occur if the request was already cancelled",
- pTarget->SpbTarget);
-
- goto exit;
- }
-
- NT_ASSERT(pRequest->SpbRequest != NULL);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Delay timer expired, ready to configure transfer for WDFDEVICE %p",
- pDevice->FxDevice);
-
- ControllerConfigureForTransfer(pDevice, pRequest);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (pRequest->bIoComplete)
- {
- completeRequest = TRUE;
- }
-
-exit:
-
- //
- // Release the device lock.
- //
-
- WdfSpinLockRelease(pDevice->Lock);
-
- // TODO: Remove this block. For the purpose of this
- // skeleton sample, simply complete the request
- // synchronously. This must be done outside of
- // the locked code.
- if (completeRequest)
- {
- PbcRequestComplete(pRequest);
- }
-
- FuncExit(TRACE_FLAG_TRANSFER);
-}
-
-VOID
-PbcRequestComplete(
- _In_ PPBC_REQUEST pRequest
- )
-/*++
-
- Routine Description:
-
- This routine completes the SpbRequest associated with
- the PBC_REQUEST context.
-
- Arguments:
-
- pRequest - a pointer to the PBC request context
-
- Return Value:
-
- None. The request is completed asynchronously.
-
---*/
-{
- FuncEntry(TRACE_FLAG_TRANSFER);
-
- NT_ASSERT(pRequest != NULL);
-
- Trace(
- TRACE_LEVEL_INFORMATION,
- TRACE_FLAG_TRANSFER,
- "Completing SPBREQUEST %p with %!STATUS!, transferred %Iu bytes",
- pRequest->SpbRequest,
- pRequest->Status,
- pRequest->TotalInformation);
-
- WdfRequestSetInformation(
- pRequest->SpbRequest,
- pRequest->TotalInformation);
-
- SpbRequestComplete(
- pRequest->SpbRequest,
- pRequest->Status);
-
- FuncExit(TRACE_FLAG_TRANSFER);
-}