Sample Code
Windows Driver Samples/ SpbTestTool/ C++/ sys/ peripheral.cpp/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: peripheral.cpp Abstract: This module contains the function for interaction with the SPB API. Environment: kernel-mode only Revision History: --*/ #include "internal.h" #include "peripheral.h" #include "peripheral.tmh" NTSTATUS SpbPeripheralOpen( _In_ PDEVICE_CONTEXT pDevice ) /*++ Routine Description: This routine opens a handle to the SPB controller. Arguments: pDevice - a pointer to the device context Return Value: Status --*/ { FuncEntry(TRACE_FLAG_SPBAPI); WDF_IO_TARGET_OPEN_PARAMS openParams; NTSTATUS status; // // Create the device path using the connection ID. // DECLARE_UNICODE_STRING_SIZE(DevicePath, RESOURCE_HUB_PATH_SIZE); RESOURCE_HUB_CREATE_PATH_FROM_ID( &DevicePath, pDevice->PeripheralId.LowPart, pDevice->PeripheralId.HighPart); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Opening handle to SPB target via %wZ", &DevicePath); // // Open a handle to the SPB controller. // WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, &DevicePath, (GENERIC_READ | GENERIC_WRITE)); openParams.ShareAccess = 0; openParams.CreateDisposition = FILE_OPEN; openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL; status = WdfIoTargetOpen( pDevice->SpbController, &openParams); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to open SPB target - %!STATUS!", status); } FuncExit(TRACE_FLAG_SPBAPI); return status; } NTSTATUS SpbPeripheralClose( _In_ PDEVICE_CONTEXT pDevice ) /*++ Routine Description: This routine closes a handle to the SPB controller. Arguments: pDevice - a pointer to the device context Return Value: Status --*/ { FuncEntry(TRACE_FLAG_SPBAPI); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Closing handle to SPB target"); WdfIoTargetClose(pDevice->SpbController); FuncExit(TRACE_FLAG_SPBAPI); return STATUS_SUCCESS; } VOID SpbPeripheralLock( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends a lock command to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_LOCK_CONTROLLER", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for lock and send. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_LOCK_CONTROLLER, nullptr, nullptr, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_LOCK_CONTROLLER - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralUnlock( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends an unlock command to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_UNLOCK_CONTROLLER", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for unlock and send. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_UNLOCK_CONTROLLER, nullptr, nullptr, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_UNLOCK_CONTROLLER - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralLockConnection( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends a lock connection command to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_LOCK_CONNECTION", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for lock and send. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_LOCK_CONNECTION, nullptr, nullptr, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_LOCK_CONNECTION - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralUnlockConnection( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends an unlock connection command to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_UNLOCK_CONNECTION", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for unlock and send. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_UNLOCK_CONNECTION, nullptr, nullptr, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_UNLOCK_CONNECTION - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralRead( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine reads from the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); WDFMEMORY memory = nullptr; NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for read", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for read and send. // status = WdfRequestRetrieveOutputMemory( FxRequest, &memory); if (NT_SUCCESS(status)) { status = WdfIoTargetFormatRequestForRead( pDevice->SpbController, pDevice->SpbRequest, memory, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "read - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralWrite( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine writes to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); WDFMEMORY memory = nullptr; NTSTATUS status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for write", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Initialize the SPB request for write and send. // status = WdfRequestRetrieveInputMemory( FxRequest, &memory); if (NT_SUCCESS(status)) { status = WdfIoTargetFormatRequestForWrite( pDevice->SpbController, pDevice->SpbRequest, memory, nullptr, nullptr); if (NT_SUCCESS(status)) { status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); } } if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "write - %!STATUS!", pDevice->SpbRequest, status); SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralWriteRead( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends a write-read sequence to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); PVOID pInputBuffer = nullptr; PVOID pOutputBuffer = nullptr; size_t inputBufferLength = 0; size_t outputBufferLength = 0; WDF_OBJECT_ATTRIBUTES attributes; PREQUEST_CONTEXT pRequest; NTSTATUS status; pRequest = GetRequestContext(pDevice->SpbRequest); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_EXECUTE_SEQUENCE", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Get input and output buffers. // status = WdfRequestRetrieveInputBuffer( FxRequest, 0, &pInputBuffer, &inputBufferLength); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to retrieve input buffer - %!STATUS!", status); goto Done; } status = WdfRequestRetrieveOutputBuffer( FxRequest, 0, &pOutputBuffer, &outputBufferLength); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to retrieve output buffer - %!STATUS!", status); goto Done; } // // Build SPB sequence. // const ULONG transfers = 2; SPB_TRANSFER_LIST_AND_ENTRIES(transfers) seq; SPB_TRANSFER_LIST_INIT(&(seq.List), transfers); { // // PreFAST cannot figure out the SPB_TRANSFER_LIST_ENTRY // "struct hack" size but using an index variable quiets // the warning. This is a false positive from OACR. // ULONG index = 0; seq.List.Transfers[index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE( SpbTransferDirectionToDevice, 0, pInputBuffer, (ULONG)inputBufferLength); seq.List.Transfers[index + 1] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE( SpbTransferDirectionFromDevice, 0, pOutputBuffer, (ULONG)outputBufferLength); } // // Create preallocated WDFMEMORY. The IOCTL is METHOD_BUFFERED, // so the memory doesn't have to persist until the request is // completed. // NT_ASSERT(pDevice->InputMemory == WDF_NO_HANDLE); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); status = WdfMemoryCreatePreallocated( &attributes, (PVOID)&seq, sizeof(seq), &pDevice->InputMemory); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to create WDFMEMORY - %!STATUS!", status); goto Done; } Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Built write-read sequence %p with byte length=%lu", &seq, (ULONG)(inputBufferLength + outputBufferLength)); // // Send sequence IOCTL. // // // Mark SPB request as sequence and save length. // These will be used in the completion callback // to complete the client request with the correct // number of bytes // pRequest->IsSpbSequenceRequest = TRUE; pRequest->SequenceWriteLength = (ULONG_PTR)inputBufferLength; // // Format and send the SPB sequence request. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_EXECUTE_SEQUENCE, pDevice->InputMemory, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to format request - %!STATUS!", status); goto Done; } status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_EXECUTE_SEQUENCE - %!STATUS!", pDevice->SpbRequest, status); goto Done; } Done: if (!NT_SUCCESS(status)) { SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralFullDuplex( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine sends a full duplex transfer to the SPB controller. Arguments: pDevice - a pointer to the device context FxRequest - the framework request object Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxRequest); PVOID pInputBuffer = nullptr; PVOID pOutputBuffer = nullptr; size_t inputBufferLength = 0; size_t outputBufferLength = 0; WDF_OBJECT_ATTRIBUTES attributes; PREQUEST_CONTEXT pRequest; NTSTATUS status; pRequest = GetRequestContext(pDevice->SpbRequest); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Formatting SPB request %p for IOCTL_SPB_FULL_DUPLEX", pDevice->SpbRequest); // // Save the client request. // pDevice->ClientRequest = FxRequest; // // Get input and output buffers. // status = WdfRequestRetrieveInputBuffer( FxRequest, 0, &pInputBuffer, &inputBufferLength); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to retrieve input buffer - %!STATUS!", status); goto Done; } status = WdfRequestRetrieveOutputBuffer( FxRequest, 0, &pOutputBuffer, &outputBufferLength); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to retrieve output buffer - %!STATUS!", status); goto Done; } // // Build full duplex transfer using SPB transfer list. // const ULONG transfers = 2; SPB_TRANSFER_LIST_AND_ENTRIES(transfers) seq; SPB_TRANSFER_LIST_INIT(&(seq.List), transfers); { // // PreFAST cannot figure out the SPB_TRANSFER_LIST_ENTRY // "struct hack" size but using an index variable quiets // the warning. This is a false positive from OACR. // ULONG index = 0; seq.List.Transfers[index] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE( SpbTransferDirectionToDevice, 0, pInputBuffer, (ULONG)inputBufferLength); seq.List.Transfers[index + 1] = SPB_TRANSFER_LIST_ENTRY_INIT_SIMPLE( SpbTransferDirectionFromDevice, 0, pOutputBuffer, (ULONG)outputBufferLength); } // // Create preallocated WDFMEMORY. The IOCTL is METHOD_BUFFERED, // so the memory doesn't have to persist until the request is // completed. // NT_ASSERT(pDevice->InputMemory == WDF_NO_HANDLE); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); status = WdfMemoryCreatePreallocated( &attributes, (PVOID)&seq, sizeof(seq), &pDevice->InputMemory); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to create WDFMEMORY - %!STATUS!", status); goto Done; } Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Built full duplex transfer %p with byte length=%lu", &seq, (ULONG)(inputBufferLength + outputBufferLength)); // // Send full duplex IOCTL. // // // Mark SPB request as full duplex (sequence format) // and save length. These will be used in the completion // callback to complete the client request with the correct // number of bytes // pRequest->IsSpbSequenceRequest = TRUE; pRequest->SequenceWriteLength = (ULONG_PTR)inputBufferLength; // // Format and send the full duplex request. // status = WdfIoTargetFormatRequestForIoctl( pDevice->SpbController, pDevice->SpbRequest, IOCTL_SPB_FULL_DUPLEX, pDevice->InputMemory, nullptr, nullptr, nullptr); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to format request - %!STATUS!", status); goto Done; } status = SpbPeripheralSendRequest( pDevice, pDevice->SpbRequest, FxRequest); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p for " "IOCTL_SPB_FULL_DUPLEX - %!STATUS!", pDevice->SpbRequest, status); goto Done; } Done: if (!NT_SUCCESS(status)) { SpbPeripheralCompleteRequestPair( pDevice, status, 0); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralSignalInterrupt( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine signals the interrupt service routine to continue. Arguments: pDevice - the device context FxRequest - the framework request object Return Value: None. --*/ { FuncEntry(TRACE_FLAG_SPBAPI); NTSTATUS status = STATUS_SUCCESS; if (pDevice->Interrupt != nullptr) { // // Signal ISR to continue. // KeSetEvent( &pDevice->IsrWaitEvent, IO_NO_INCREMENT, FALSE); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Setting ISR wait event"); } else { status = STATUS_NOT_FOUND; Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_SPBAPI, "No interrupt object found, ignoring - %!STATUS!", status); } WdfRequestComplete(FxRequest, status); FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralWaitOnInterrupt( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This routine pends the WaitOnInterrupt request. Arguments: pDevice - the device context FxRequest - the framework request object Return Value: None. --*/ { FuncEntry(TRACE_FLAG_SPBAPI); PREQUEST_CONTEXT pRequest = GetRequestContext(FxRequest); NTSTATUS status = STATUS_SUCCESS; if (pDevice->WaitOnInterruptRequest == nullptr) { // // Mark request cancellable. // pRequest->FxDevice = pDevice->FxDevice; status = WdfRequestMarkCancelableEx( FxRequest, SpbPeripheralOnWaitOnInterruptCancel); if (!NT_SUCCESS(status)) { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to mark WaitOnInterrupt request %p cancellable - %!STATUS!", FxRequest, status); } // // Pend the WaitOnInterrupt request. // if (NT_SUCCESS(status)) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "WaitOnInterrupt request %p pended", FxRequest); pDevice->WaitOnInterruptRequest = FxRequest; } } else { status = STATUS_INVALID_DEVICE_STATE; Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_SPBAPI, "Cannont pend multiple WaitOnInterrupt requests, ignoring - %!STATUS!", status); } if (!NT_SUCCESS(status)) { WdfRequestComplete(FxRequest, status); } FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralOnWaitOnInterruptCancel( _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This event is called when the WaitOnInterrupt request is cancelled. Arguments: FxRequest - the framework request object Return Value: VOID --*/ { FuncEntry(TRACE_FLAG_SPBAPI); PREQUEST_CONTEXT pRequest; PDEVICE_CONTEXT pDevice; pRequest = GetRequestContext(FxRequest); pDevice = GetDeviceContext(pRequest->FxDevice); // // Complete the request as cancelled // if (FxRequest == pDevice->WaitOnInterruptRequest) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "WaitOnInterrupt request %p cancelled", FxRequest); pDevice->WaitOnInterruptRequest = nullptr; WdfRequestComplete(FxRequest, STATUS_CANCELLED); } else { Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_SPBAPI, "Cancel for WDFREQUEST %p without WaitOnInterrupt request pended," "will complete as cancelled anyway", FxRequest); WdfRequestComplete(FxRequest, STATUS_CANCELLED); } FuncExit(TRACE_FLAG_SPBAPI); } BOOLEAN SpbPeripheralInterruptNotify( _In_ PDEVICE_CONTEXT pDevice ) /*++ Routine Description: This routine completes the pending WaitOnInterrupt request. Arguments: pDevice - the device context Return Value: TRUE if notification sent, false otherwise. --*/ { FuncEntry(TRACE_FLAG_SPBAPI); WDFREQUEST request; BOOLEAN fNotificationSent = FALSE; NTSTATUS status; if (pDevice->WaitOnInterruptRequest != nullptr) { // // Complete the WaitOnInterrupt request. // request = pDevice->WaitOnInterruptRequest; pDevice->WaitOnInterruptRequest = nullptr; status = WdfRequestUnmarkCancelable(request); if (NT_SUCCESS(status)) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Interrupt detected, WaitOnInterrupt request %p completed", pDevice->WaitOnInterruptRequest); WdfRequestComplete(request, STATUS_SUCCESS); fNotificationSent = TRUE; } else if (status == STATUS_CANCELLED) { Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Interrupt detected with WaitOnInterrupt request %p " "already completed - %!STATUS!", pDevice->WaitOnInterruptRequest, status); } else { Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Interrupt detected but failed to unmark WaitOnInterrupt " "request %p as cancellable - %!STATUS!", pDevice->WaitOnInterruptRequest, status); } } else { Trace( TRACE_LEVEL_WARNING, TRACE_FLAG_SPBAPI, "Interrupt detected without a pended WaitOnInterrupt request"); } FuncExit(TRACE_FLAG_SPBAPI); return fNotificationSent; } NTSTATUS SpbPeripheralSendRequest( _In_ PDEVICE_CONTEXT pDevice, _In_ WDFREQUEST SpbRequest, _In_ WDFREQUEST ClientRequest ) /*++ Routine Description: This routine sends a write-read sequence to the SPB controller. Arguments: pDevice - a pointer to the device context SpbRequest - the SPB request object ClientRequest - the client request object Return Value: Status --*/ { FuncEntry(TRACE_FLAG_SPBAPI); PREQUEST_CONTEXT pRequest = GetRequestContext(ClientRequest); NTSTATUS status = STATUS_SUCCESS; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Saving client request %p, and " "sending SPB request %p", ClientRequest, SpbRequest); // // Init client request context. // pRequest->FxDevice = pDevice->FxDevice; pRequest->IsSpbSequenceRequest = FALSE; pRequest->SequenceWriteLength = 0; // // Mark the client request as cancellable. // if (NT_SUCCESS(status)) { status = WdfRequestMarkCancelableEx( ClientRequest, SpbPeripheralOnCancel); } // // Send the SPB request. // if (NT_SUCCESS(status)) { WdfRequestSetCompletionRoutine( SpbRequest, SpbPeripheralOnCompletion, GetRequestContext(SpbRequest)); BOOLEAN fSent = WdfRequestSend( SpbRequest, pDevice->SpbController, WDF_NO_SEND_OPTIONS); if (!fSent) { status = WdfRequestGetStatus(SpbRequest); Trace( TRACE_LEVEL_ERROR, TRACE_FLAG_SPBAPI, "Failed to send SPB request %p - %!STATUS!", SpbRequest, status); NTSTATUS cancelStatus; cancelStatus = WdfRequestUnmarkCancelable(ClientRequest); if (!NT_SUCCESS(cancelStatus)) { NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if request has already been cancelled", cancelStatus == STATUS_CANCELLED); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Client request %p has already been cancelled - " "%!STATUS!", ClientRequest, cancelStatus); } } } FuncExit(TRACE_FLAG_SPBAPI); return status; } VOID SpbPeripheralOnCompletion( _In_ WDFREQUEST FxRequest, _In_ WDFIOTARGET FxTarget, _In_ PWDF_REQUEST_COMPLETION_PARAMS Params, _In_ WDFCONTEXT Context ) /*++ Routine Description: This routine is called when a request completes. Arguments: FxRequest - the framework request object FxTarget - the framework IO target object Params - a pointer to the request completion parameters Context - the request context Return Value: None --*/ { FuncEntry(TRACE_FLAG_SPBAPI); UNREFERENCED_PARAMETER(FxTarget); UNREFERENCED_PARAMETER(Context); PREQUEST_CONTEXT pRequest; PDEVICE_CONTEXT pDevice; NTSTATUS status; NTSTATUS cancelStatus; ULONG_PTR bytesCompleted; pRequest = GetRequestContext(FxRequest); pDevice = GetDeviceContext(pRequest->FxDevice); status = Params->IoStatus.Status; Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Completion callback received for SPB request %p with %!STATUS!", FxRequest, status); // // Unmark the client request as cancellable // cancelStatus = WdfRequestUnmarkCancelable(pDevice->ClientRequest); if (!NT_SUCCESS(cancelStatus)) { NT_ASSERTMSG("WdfRequestUnmarkCancelable should only fail if request has already been cancelled", cancelStatus == STATUS_CANCELLED); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Client request %p has already been cancelled - %!STATUS!", pDevice->ClientRequest, cancelStatus); } // // Complete the request pair // if (pRequest->IsSpbSequenceRequest == TRUE) { // // The client DeviceIoControl should only be // completed with bytesReturned and not total // bytes transferred. Here we infer the number // of bytes read by substracting the write // length from the total. // bytesCompleted = Params->IoStatus.Information < pRequest->SequenceWriteLength ? 0 : Params->IoStatus.Information - pRequest->SequenceWriteLength; } else { bytesCompleted = Params->IoStatus.Information; } SpbPeripheralCompleteRequestPair( pDevice, status, bytesCompleted); FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralOnCancel( _In_ WDFREQUEST FxRequest ) /*++ Routine Description: This event is called when the client request is cancelled. Arguments: FxRequest - the framework request object Return Value: VOID --*/ { FuncEntry(TRACE_FLAG_SPBAPI); PREQUEST_CONTEXT pRequest; PDEVICE_CONTEXT pDevice; pRequest = GetRequestContext(FxRequest); pDevice = GetDeviceContext(pRequest->FxDevice); // // Attempt to cancel the SPB request // Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Cancel received for client request %p, " "attempting to cancel SPB request %p", FxRequest, pDevice->SpbRequest); WdfRequestCancelSentRequest(pDevice->SpbRequest); FuncExit(TRACE_FLAG_SPBAPI); } VOID SpbPeripheralCompleteRequestPair( _In_ PDEVICE_CONTEXT pDevice, _In_ NTSTATUS status, _In_ ULONG_PTR bytesCompleted ) /*++ Routine Description: This routine marks the SpbRequest as reuse and completes the client request. Arguments: pDevice - the device context status - the client completion status bytesCompleted - the number of bytes completed for the client request Return Value: VOID --*/ { FuncEntry(TRACE_FLAG_SPBAPI); PREQUEST_CONTEXT pRequest; pRequest = GetRequestContext(pDevice->SpbRequest); Trace( TRACE_LEVEL_INFORMATION, TRACE_FLAG_SPBAPI, "Marking SPB request %p for reuse, and completing " "client request %p with %!STATUS! and bytes=%lu", pDevice->SpbRequest, pDevice->ClientRequest, status, (ULONG)bytesCompleted); // // Mark the SPB request as reuse // pRequest->IsSpbSequenceRequest = FALSE; pRequest->SequenceWriteLength = 0; WDF_REQUEST_REUSE_PARAMS params; WDF_REQUEST_REUSE_PARAMS_INIT( ¶ms, WDF_REQUEST_REUSE_NO_FLAGS, STATUS_SUCCESS); WdfRequestReuse(pDevice->SpbRequest, ¶ms); if (pDevice->InputMemory != WDF_NO_HANDLE) { WdfObjectDelete(pDevice->InputMemory); pDevice->InputMemory = WDF_NO_HANDLE; } // // Complete the client request // if (pDevice->ClientRequest != nullptr) { WDFREQUEST clientRequest = pDevice->ClientRequest; pDevice->ClientRequest = nullptr; // // In order to satisfy SDV, assume clientRequest // is equal to pDevice->ClientRequest. This suppresses // a warning in the driver's cancellation path. // // Typically when WdfRequestUnmarkCancelable returns // STATUS_CANCELLED a driver does not go on to complete // the request in that context. This sample, however, // driver has handled this condition appropriately by // not completing the cancelled request in its // EvtRequestCancel callback. Developers should be // cautious when copying code from this sample, paying // close attention to the cancellation logic. // _Analysis_assume_(clientRequest == pDevice->ClientRequest); WdfRequestCompleteWithInformation( clientRequest, status, bytesCompleted); } FuncExit(TRACE_FLAG_SPBAPI); }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials