diff --git a/src/AmtPtpDeviceSpiKm/Device.c b/src/AmtPtpDeviceSpiKm/Device.c index 3cf4020..03f3975 100644 --- a/src/AmtPtpDeviceSpiKm/Device.c +++ b/src/AmtPtpDeviceSpiKm/Device.c @@ -27,7 +27,9 @@ AmtPtpDeviceSpiKmCreateDevice( ) { WDF_OBJECT_ATTRIBUTES DeviceAttributes; + WDF_OBJECT_ATTRIBUTES TimerAttributes; PDEVICE_CONTEXT pDeviceContext; + WDF_TIMER_CONFIG TimerConfig; WDFDEVICE Device; NTSTATUS Status; @@ -48,6 +50,8 @@ AmtPtpDeviceSpiKmCreateDevice( pnpPowerCallbacks.EvtDevicePrepareHardware = AmtPtpEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceD0Entry = AmtPtpEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = AmtPtpEvtDeviceD0Exit; + pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = AmtPtpEvtDeviceSelfManagedIoInitOrRestart; + pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = AmtPtpEvtDeviceSelfManagedIoInitOrRestart; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // Create WDF device object @@ -95,6 +99,16 @@ AmtPtpDeviceSpiKmCreateDevice( goto exit; } + // + // Create power-on recovery timer + // + WDF_TIMER_CONFIG_INIT(&TimerConfig, AmtPtpPowerRecoveryTimerCallback); + TimerConfig.AutomaticSerialization = TRUE; + WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); + TimerAttributes.ParentObject = Device; + TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; + Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &pDeviceContext->PowerOnRecoveryTimer); + // // Retrieve IO target. // @@ -312,37 +326,11 @@ AmtPtpEvtDeviceD0Entry( pDeviceContext = DeviceGetContext(Device); - // Attempt to enable SPI trackpad - // this might fail but can be retried later - // The state retains unless the power rail of trackpad - // has been cut - Status = AmtPtpSpiSetState( - Device, - TRUE - ); - - if (!NT_SUCCESS(Status)) - { - TraceEvents( - TRACE_LEVEL_ERROR, - TRACE_DRIVER, - "%!FUNC! AmtPtpSpiSetState failed with %!STATUS!. Ignored anyway.", - Status - ); - - // Ignore anyway, but set unconfigured status - pDeviceContext->DeviceStatus = D0ActiveAndUnconfigured; - Status = STATUS_SUCCESS; - } - else - { - pDeviceContext->DeviceStatus = D0ActiveAndConfigured; - } + // We will configure the device in Self Managed IO init / restart routine + pDeviceContext->DeviceStatus = D0ActiveAndUnconfigured; // Set time - KeQueryPerformanceCounter( - &pDeviceContext->LastReportTime - ); + KeQueryPerformanceCounter(&pDeviceContext->LastReportTime); TraceEvents( TRACE_LEVEL_INFORMATION, @@ -397,6 +385,38 @@ AmtPtpEvtDeviceD0Exit( return Status; } +NTSTATUS +AmtPtpEvtDeviceSelfManagedIoInitOrRestart( + _In_ WDFDEVICE Device +) +{ + NTSTATUS Status = STATUS_SUCCESS; + PDEVICE_CONTEXT pDeviceContext; + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + pDeviceContext = DeviceGetContext(Device); + + Status = AmtPtpSpiSetState(Device, TRUE); + if (!NT_SUCCESS(Status)) + { + // In this case, we will retry after 5 seconds. Block any incoming requests. + TraceEvents(TRACE_LEVEL_ERROR, TRACE_DRIVER, "%!FUNC! AmtPtpSpiSetState failed with %!STATUS!. Retry after 5 seconds", Status); + Status = STATUS_SUCCESS; + WdfTimerStart(pDeviceContext->PowerOnRecoveryTimer, WDF_REL_TIMEOUT_IN_SEC(5)); + goto exit; + } + else + { + // Set time and status + pDeviceContext->DeviceStatus = D0ActiveAndConfigured; + KeQueryPerformanceCounter(&pDeviceContext->LastReportTime); + } + +exit: + TraceEvents(TRACE_LEVEL_INFORMATION,TRACE_DRIVER, "%!FUNC! Exit, Status = %!STATUS!", Status); + return Status; +} + PCHAR DbgDevicePowerString( _In_ WDF_POWER_DEVICE_STATE Type @@ -508,3 +528,26 @@ AmtPtpSpiSetState( return Status; } + +void AmtPtpPowerRecoveryTimerCallback( + WDFTIMER Timer +) +{ + WDFDEVICE Device; + PDEVICE_CONTEXT pDeviceContext; + NTSTATUS Status = STATUS_SUCCESS; + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Entry"); + Device = WdfTimerGetParentObject(Timer); + pDeviceContext = DeviceGetContext(Device); + + Status = AmtPtpSpiSetState(Device, TRUE); + if (NT_SUCCESS(Status)) + { + // Triage request and set status + AmtPtpSpiInputIssueRequest(Device); + pDeviceContext->DeviceStatus = D0ActiveAndConfigured; + } + + TraceEvents(TRACE_LEVEL_INFORMATION, TRACE_DRIVER, "%!FUNC! Exit, Status = %!STATUS!", Status); +} diff --git a/src/AmtPtpDeviceSpiKm/Device.h b/src/AmtPtpDeviceSpiKm/Device.h index f078335..a56694b 100644 --- a/src/AmtPtpDeviceSpiKm/Device.h +++ b/src/AmtPtpDeviceSpiKm/Device.h @@ -76,6 +76,7 @@ typedef struct _DEVICE_CONTEXT // Timer LARGE_INTEGER LastReportTime; + WDFTIMER PowerOnRecoveryTimer; // List of buffers WDFLOOKASIDE HidReadBufferLookaside; @@ -111,6 +112,11 @@ EVT_WDF_DEVICE_PREPARE_HARDWARE AmtPtpEvtDevicePrepareHardware; EVT_WDF_DEVICE_D0_ENTRY AmtPtpEvtDeviceD0Entry; EVT_WDF_DEVICE_D0_EXIT AmtPtpEvtDeviceD0Exit; +NTSTATUS +AmtPtpEvtDeviceSelfManagedIoInitOrRestart( + _In_ WDFDEVICE Device +); + PCHAR DbgDevicePowerString( _In_ WDF_POWER_DEVICE_STATE Type @@ -122,4 +128,8 @@ AmtPtpSpiSetState( _In_ BOOLEAN DesiredState ); +void AmtPtpPowerRecoveryTimerCallback( + WDFTIMER Timer +); + EXTERN_C_END diff --git a/src/AmtPtpDeviceSpiKm/Input.c b/src/AmtPtpDeviceSpiKm/Input.c index 090432e..cbba03a 100644 --- a/src/AmtPtpDeviceSpiKm/Input.c +++ b/src/AmtPtpDeviceSpiKm/Input.c @@ -9,25 +9,8 @@ AmtPtpSpiInputRoutineWorker( { NTSTATUS Status; PDEVICE_CONTEXT pDeviceContext; - WDF_OBJECT_ATTRIBUTES Attributes; - BOOLEAN RequestStatus = FALSE; - WDFREQUEST SpiHidReadRequest; - WDFMEMORY SpiHidReadOutputMemory; - PWORKER_REQUEST_CONTEXT RequestContext; pDeviceContext = DeviceGetContext(Device); - // This call is expected to happen after D0 entrance - if (pDeviceContext->DeviceStatus == D3) { - TraceEvents( - TRACE_LEVEL_WARNING, - TRACE_QUEUE, - "%!FUNC! Unexpected call while device is in D3 status" - ); - - WdfRequestComplete(PtpRequest, STATUS_UNSUCCESSFUL); - return; - } - Status = WdfRequestForwardToIoQueue( PtpRequest, pDeviceContext->HidQueue @@ -45,6 +28,27 @@ AmtPtpSpiInputRoutineWorker( return; } + // Only issue request when fully configured. + // Otherwise we will let power recovery process to triage it + if (pDeviceContext->DeviceStatus == D0ActiveAndConfigured) { + AmtPtpSpiInputIssueRequest(Device); + } +} + +VOID +AmtPtpSpiInputIssueRequest( + WDFDEVICE Device +) +{ + NTSTATUS Status; + PDEVICE_CONTEXT pDeviceContext; + WDF_OBJECT_ATTRIBUTES Attributes; + BOOLEAN RequestStatus = FALSE; + WDFREQUEST SpiHidReadRequest; + WDFMEMORY SpiHidReadOutputMemory; + PWORKER_REQUEST_CONTEXT RequestContext; + pDeviceContext = DeviceGetContext(Device); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&Attributes, WORKER_REQUEST_CONTEXT); Attributes.ParentObject = Device; @@ -58,7 +62,7 @@ AmtPtpSpiInputRoutineWorker( { TraceEvents( TRACE_LEVEL_INFORMATION, - TRACE_DRIVER, + TRACE_DEVICE, "%!FUNC! WdfRequestCreate fails, status = %!STATUS!", Status ); @@ -75,7 +79,7 @@ AmtPtpSpiInputRoutineWorker( { TraceEvents( TRACE_LEVEL_INFORMATION, - TRACE_DRIVER, + TRACE_DEVICE, "%!FUNC! WdfMemoryCreateFromLookaside fails, status = %!STATUS!", Status ); @@ -104,7 +108,7 @@ AmtPtpSpiInputRoutineWorker( { TraceEvents( TRACE_LEVEL_INFORMATION, - TRACE_DRIVER, + TRACE_DEVICE, "%!FUNC! WdfIoTargetFormatRequestForInternalIoctl fails, status = %!STATUS!", Status ); @@ -116,7 +120,7 @@ AmtPtpSpiInputRoutineWorker( if (SpiHidReadRequest != NULL) { WdfObjectDelete(SpiHidReadRequest); } - + return; } @@ -136,7 +140,7 @@ AmtPtpSpiInputRoutineWorker( { TraceEvents( TRACE_LEVEL_INFORMATION, - TRACE_DRIVER, + TRACE_DEVICE, "%!FUNC! AmtPtpSpiInputRoutineWorker request failed to sent" ); @@ -204,29 +208,6 @@ AmtPtpRequestCompletionRoutine( SpiRequestLength ); - if (pDeviceContext->DeviceStatus == D0ActiveAndUnconfigured) { - Status = AmtPtpSpiSetState( - pDeviceContext->SpiDevice, - TRUE - ); - - if (!NT_SUCCESS(Status)) - { - TraceEvents( - TRACE_LEVEL_ERROR, - TRACE_DRIVER, - "%!FUNC! AmtPtpSpiSetState failed with %!STATUS!.", - Status - ); - } - else { - pDeviceContext->DeviceStatus = D0ActiveAndConfigured; - AmtPtpSpiInputRoutineWorker(pDeviceContext->SpiDevice, PtpRequest); - // Bypass PTP request completion - goto cleanup; - } - } - Status = STATUS_DEVICE_DATA_ERROR; goto exit; } diff --git a/src/AmtPtpDeviceSpiKm/Input.h b/src/AmtPtpDeviceSpiKm/Input.h index 3a1e093..8c7109d 100644 --- a/src/AmtPtpDeviceSpiKm/Input.h +++ b/src/AmtPtpDeviceSpiKm/Input.h @@ -6,4 +6,9 @@ VOID AmtPtpSpiInputRoutineWorker( WDFDEVICE Device, WDFREQUEST PtpRequest -); \ No newline at end of file +); + +VOID +AmtPtpSpiInputIssueRequest( + WDFDEVICE Device +);