// This callback is called when the simulator wait time has expired and the simulator // is ready to switch to the next sample. The callback updates the sample index and // schedules the next wake up time. VOID HardwareSimulator::OnTimerExpire( _In_ WDFTIMER Timer) // WDF timer object { HardwareSimulator *pSimulator = nullptr; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); pSimulator = GetHardwareSimulatorContextFromInstance(WdfTimerGetParentObject(Timer)); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("CSTM %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); } if (NT_SUCCESS(Status)) { // Increment the sample index, roll over if the index reach the end of the array WdfWaitLockAcquire(pSimulator->m_Lock, NULL); pSimulator->m_Index++; pSimulator->m_Index = pSimulator->m_Index % ARRAYSIZE(SimulatorData); WdfWaitLockRelease(pSimulator->m_Lock); WdfTimerStart(pSimulator->m_Timer, WDF_REL_TIMEOUT_IN_MS(SIMULATOR_HARDWARE_INTERVAL_MS)); } SENSOR_FunctionExit(Status); }
NTSTATUS TpmEvtDeviceD0Entry( IN WDFDEVICE Device, IN WDF_POWER_DEVICE_STATE PreviousState ) { PTPM_CONTEXT TpmContext; NTSTATUS status; UNREFERENCED_PARAMETER(PreviousState); KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtDeviceD0Entry: Enter\n")); TpmContext = GetTpmContext(Device); TpmContext->AccessRegister = FALSE; TpmContinueSelfTest(TpmContext); #if _NT_TARGET_VERSION >= 0x601 TpmProvideEntropy(TpmContext); if(TpmContext->TimeOutSecond) { WdfTimerStart(TpmContext->timerHandle, WDF_REL_TIMEOUT_IN_MS(TpmContext->TimeOutSecond)); } #endif TpmUpdateTpmState(TpmContext,StAvailable,IdPowerup); return STATUS_SUCCESS; }
// Called by Sensor CLX to begin keeping history NTSTATUS ActivityDevice::OnStartHistory(_In_ SENSOROBJECT sensorInstance) { NTSTATUS status = STATUS_SUCCESS; SENSOR_FunctionEnter(); PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance); if (nullptr == pDevice) { status = STATUS_INVALID_PARAMETER; TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status); } else if (0 == pDevice->m_HistorySizeInRecords) { status = STATUS_NOT_SUPPORTED; TraceError("ACT %!FUNC! Sensor does not support History"); } else if (FALSE == pDevice->m_PoweredOn) { status = STATUS_DEVICE_NOT_READY; TraceError("ACT %!FUNC! Sensor is not powered on! %!STATUS!", status); } else { // Start keeping history pDevice->m_HistoryStarted = TRUE; WdfTimerStart(pDevice->m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_HistoryIntervalInMs)); } SENSOR_FunctionExit(status); return status; }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback reads current value, compare value to threshold, // pushes it up to CLX framework, and schedule next wake up time. VOID ActivityDevice::OnTimerExpire(_In_ WDFTIMER timer) { NTSTATUS status = STATUS_SUCCESS; SENSOR_FunctionEnter(); PActivityDevice pDevice = GetActivityContextFromSensorInstance(WdfTimerGetParentObject(timer)); if (nullptr == pDevice) { status = STATUS_INSUFFICIENT_RESOURCES; TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status); } else { // Get data and push to clx WdfWaitLockAcquire(pDevice->m_Lock, NULL); status = pDevice->GetData(); if (!NT_SUCCESS(status) && STATUS_DATA_NOT_ACCEPTED != status) { TraceError("ACT %!FUNC! GetAccData Failed %!STATUS!", status); } WdfWaitLockRelease(pDevice->m_Lock); // Schedule next wake up time if (Act_Default_MinDataInterval_Ms <= pDevice->m_Interval && FALSE != pDevice->m_PoweredOn && FALSE != pDevice->m_Started) { WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval)); } } SENSOR_FunctionExit(status); }
// Called by Sensor CLX to set sampling rate of the sensor. NTSTATUS CustomSensorDevice::OnSetDataInterval( _In_ SENSOROBJECT SensorInstance, // sensor device object _In_ ULONG DataRateMs // sampling rate in milliseconds ) { PCustomSensorDevice pDevice = GetCustomSensorContextFromSensorInstance(SensorInstance); NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); if (nullptr == pDevice || Cstm_Default_MinDataInterval_Ms > DataRateMs) { Status = STATUS_INVALID_PARAMETER; TraceError("CSTM %!FUNC! Sensor(%08X) parameter is invalid. Failed %!STATUS!", (INT) SensorInstance, Status); goto Exit; } pDevice->m_Interval = DataRateMs; // reschedule sample to return as soon as possible if it's started if (FALSE != pDevice->m_Started) { pDevice->m_Started = FALSE; WdfTimerStop(pDevice->m_Timer, TRUE); pDevice->m_Started = TRUE; pDevice->m_FirstSample = TRUE; WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Cstm_Default_MinDataInterval_Ms)); } Exit: SENSOR_FunctionExit(Status); return Status; }
/*++ Routine Description: Write to mail box in a serialize manner Arguments: DeviceContextPtr - Pointer to device context Channel - Mailbox Channel Value - Value to be written Request - Optional WDF request object associated with this mailbox transaction Return Value: NTSTATUS --*/ _Use_decl_annotations_ NTSTATUS RpiqMailboxWrite ( DEVICE_CONTEXT* DeviceContextPtr, ULONG Channel, ULONG Value, WDFREQUEST Request ) { NTSTATUS status; ULONG count = 0, reg; LARGE_INTEGER timeOut = { 0 }; PAGED_CODE(); WdfWaitLockAcquire(DeviceContextPtr->WriteLock, NULL); timeOut.QuadPart = WDF_REL_TIMEOUT_IN_MS(1); reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status); // Poll until mailbox is available. It doesn't seem like // the mailbox is full often so polling is sufficient for now // rather than enable mailbox empty interrupt while (reg & MAILBOX_STATUS_FULL) { if (count > MAX_POLL) { RPIQ_LOG_ERROR( "Exit Fail Status 0x%08x", DeviceContextPtr->Mailbox->Status); status = STATUS_IO_TIMEOUT; goto End; } KeDelayExecutionThread(KernelMode, FALSE, &timeOut); reg = READ_REGISTER_NOFENCE_ULONG(&DeviceContextPtr->Mailbox->Status); ++count; } if (Request) { status = WdfRequestForwardToIoQueue( Request, DeviceContextPtr->ChannelQueue[Channel]); if (!NT_SUCCESS(status)) { RPIQ_LOG_ERROR( "WdfRequestForwardToIoQueue failed ( %!STATUS!)", status); goto End; } } WRITE_REGISTER_NOFENCE_ULONG( &DeviceContextPtr->Mailbox->Write, (Value & ~MAILBOX_CHANNEL_MASK) | Channel); status = STATUS_SUCCESS; End: WdfWaitLockRelease(DeviceContextPtr->WriteLock); return status; }
VOID PLxHardwareReset( IN PDEVICE_EXTENSION DevExt ) /*++ Routine Description: Called by D0Exit when the device is being disabled or when the system is shutdown to put the device in a known initial state. Arguments: DevExt Pointer to Device Extension Return Value: --*/ { LARGE_INTEGER delay; union { EEPROM_CSR bits; ULONG ulong; } eeCSR; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "--> PLxIssueFullReset"); // // Drive the 9656 into soft reset. // eeCSR.ulong = READ_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat ); eeCSR.bits.SoftwareReset = TRUE; WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat, eeCSR.ulong ); // // Wait 100 msec. // delay.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); KeDelayExecutionThread( KernelMode, TRUE, &delay ); // // Finally pull the 9656 out of reset. // eeCSR.bits.SoftwareReset = FALSE; WRITE_REGISTER_ULONG( (PULONG) &DevExt->Regs->EEPROM_Ctrl_Stat, eeCSR.ulong ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-- PLxIssueFullReset"); }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback stores activity data in history buffer, // and schedules next wake up time. VOID ActivityDevice::OnHistoryTimerExpire(_In_ WDFTIMER historyTimer) { NTSTATUS status = STATUS_SUCCESS; SENSOR_FunctionEnter(); PActivityDevice pDevice = GetActivityContextFromSensorInstance(WdfTimerGetParentObject(historyTimer)); if (nullptr == pDevice) { status = STATUS_INSUFFICIENT_RESOURCES; TraceError("ACT %!FUNC! GetActivityContextFromSensorInstance failed %!STATUS!", status); } else { ActivitySample data = {}; if (NULL != pDevice->m_SimulatorInstance) { PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); if (nullptr != pSimulator) { status = pSimulator->GetSample(&data); } else { status = STATUS_INVALID_PARAMETER; } } GetSystemTimePreciseAsFileTime(&(data.Timestamp)); if (NT_SUCCESS(status)) { // Add data to the buffer WdfWaitLockAcquire(pDevice->m_HistoryLock, NULL); status = pDevice->AddDataElementToHistoryBuffer(&data); if (!NT_SUCCESS(status)) { TraceError("ACT %!FUNC! AddDataElementToHistoryBuffer Failed %!STATUS!", status); } WdfWaitLockRelease(pDevice->m_HistoryLock); } // Schedule next wake up time if (FALSE != pDevice->m_HistoryStarted) { WdfTimerStart(pDevice->m_HistoryTimer, WDF_REL_TIMEOUT_IN_MS(pDevice->m_HistoryIntervalInMs)); } } SENSOR_FunctionExit(status); }
// Called by Sensor CLX to begin continuously sampling the sensor. NTSTATUS PedometerDevice::OnStart( _In_ SENSOROBJECT SensorInstance // Sensor device object ) { PHardwareSimulator pSimulator = nullptr; PPedometerDevice pDevice = GetPedometerContextFromSensorInstance(SensorInstance); NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); if (nullptr == pDevice) { Status = STATUS_INVALID_PARAMETER; TraceError("PED %!FUNC! Sensor(0x%p) parameter is invalid. Failed %!STATUS!", SensorInstance, Status); goto Exit; } // Get the simulator context pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); } if (NT_SUCCESS(Status)) { // Start the simulator pSimulator->Start(); pDevice->m_FirstSample = TRUE; // Start polling pDevice->m_Started = TRUE; InitPropVariantFromUInt32(SensorState_Active, &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); // Start the sample polling timer. // // Note: The polling timer is configured to allow for the first sample to be reported immediately. // Some hardware may want to delay the first sample report a little to account for hardware start time. WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Pedometer_Default_MinDataInterval_Ms)); } Exit: SENSOR_FunctionExit(Status); return Status; }
// This routine starts the simulator // Returns an NTSTATUS code NTSTATUS HardwareSimulator::Start() { NTSTATUS status = STATUS_SUCCESS; SENSOR_FunctionEnter(); if (SimulatorState_Initialized == m_State) { WdfTimerStart(m_Timer, WDF_REL_TIMEOUT_IN_MS(HardwareSimulator_HardwareInterval)); m_State = SimulatorState_Started; } SENSOR_FunctionExit(status); return status; }
NTSTATUS EchoEvtDeviceSelfManagedIoStart( IN WDFDEVICE Device ) /*++ Routine Description: This event is called by the Framework when the device is started or restarted after a suspend operation. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. Arguments: Device - Handle to a framework device object. Return Value: NTSTATUS - Failures will result in the device stack being torn down. --*/ { PQUEUE_CONTEXT queueContext = QueueGetContext(WdfDeviceGetDefaultQueue(Device)); LARGE_INTEGER DueTime; KdPrint(("--> EchoEvtDeviceSelfManagedIoInit\n")); // // Restart the queue and the periodic timer. We stopped them before going // into low power state. // WdfIoQueueStart(WdfDeviceGetDefaultQueue(Device)); DueTime.QuadPart = WDF_REL_TIMEOUT_IN_MS(100); WdfTimerStart(queueContext->Timer, DueTime.QuadPart); KdPrint(( "<-- EchoEvtDeviceSelfManagedIoInit\n")); return STATUS_SUCCESS; }
// Called by Sensor CLX to begin continously sampling the sensor. NTSTATUS ActivityDevice::OnStart(_In_ SENSOROBJECT sensorInstance) { NTSTATUS status = STATUS_SUCCESS; SENSOR_FunctionEnter(); PActivityDevice pDevice = GetActivityContextFromSensorInstance(sensorInstance); if (nullptr == pDevice) { status = STATUS_INVALID_PARAMETER; TraceError("ACT %!FUNC! Sensor parameter is invalid. Failed %!STATUS!", status); } else { if (FALSE == pDevice->m_PoweredOn) { status = STATUS_DEVICE_NOT_READY; TraceError("ACT %!FUNC! Sensor is not powered on! %!STATUS!", status); } else { // Start simulation if (NULL != pDevice->m_SimulatorInstance) { PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(pDevice->m_SimulatorInstance); if (nullptr != pSimulator) { pSimulator->Start(); } } // Start sensing pDevice->m_FirstSample = TRUE; pDevice->m_Started = TRUE; InitPropVariantFromUInt32(SensorState_Active, &(pDevice->m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); WdfTimerStart(pDevice->m_Timer, WDF_REL_TIMEOUT_IN_MS(Act_Default_MinDataInterval_Ms)); } } SENSOR_FunctionExit(status); return status; }
NTSTATUS BOOTTRACKPAD( _In_ PDEVICE_CONTEXT pDevice ) { NTSTATUS status = 0; static char bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; static char bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; cyapa_boot_regs boot; FuncEntry(TRACE_FLAG_WDFLOADING); SpbReadDataSynchronously(&pDevice->I2CContext, CMD_BOOT_STATUS, &boot, sizeof(boot)); if ((boot.stat & CYAPA_STAT_RUNNING) == 0) { if (boot.error & CYAPA_ERROR_BOOTLOADER) SpbWriteDataSynchronously(&pDevice->I2CContext, CMD_BOOT_STATUS, bl_deactivate, sizeof(bl_deactivate)); else SpbWriteDataSynchronously(&pDevice->I2CContext, CMD_BOOT_STATUS, bl_exit, sizeof(bl_exit)); } WDF_TIMER_CONFIG timerConfig; WDFTIMER hTimer; WDF_OBJECT_ATTRIBUTES attributes; WDF_TIMER_CONFIG_INIT(&timerConfig, CyapaBootTimer); WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = pDevice->FxDevice; status = WdfTimerCreate(&timerConfig, &attributes, &hTimer); WdfTimerStart(hTimer, WDF_REL_TIMEOUT_IN_MS(75)); 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. Arguments: FxDevice - a handle to the framework device object FxPreviousState - previous power state Return Value: Status --*/ { FuncEntry(TRACE_FLAG_WDFLOADING); UNREFERENCED_PARAMETER(FxPreviousState); PDEVICE_CONTEXT pDevice = GetDeviceContext(FxDevice); NTSTATUS status = STATUS_SUCCESS; WdfTimerStart(pDevice->Timer, WDF_REL_TIMEOUT_IN_MS(10)); BOOTTRACKPAD(pDevice); pDevice->RegsSet = false; pDevice->ConnectInterrupt = true; FuncExit(TRACE_FLAG_WDFLOADING); return status; }
VOID TpmEvtEntropyTimer(IN WDFTIMER Timer) { #if _NT_TARGET_VERSION >= 0x601 ULONG Interval; PTPM_CONTEXT TpmContext; PAGED_CODE(); TpmContext = GetTimerContext(Timer)->TpmContext; KdPrintEx((DPFLTR_PNPMEM_ID, DPFLTR_INFO_LEVEL, "TpmEvtEntropyTimer().\n")); if(TpmContext->bUseTimeOut) { TpmContext->PendingEntropy = TRUE; if(NT_SUCCESS(TpmUpdateTpmState(TpmContext,StBusy,IdEntropy))) { TpmProvideEntropy(TpmContext); TpmUpdateTpmState(TpmContext,StAvailable,IdEntropy); } } else { if(NT_SUCCESS(TpmGetEntropyInterval(&Interval))) { TpmContext->TimeOutSecond = 60000 * Interval; TpmContext->bUseTimeOut = TRUE; } } if(TpmContext->TimeOutSecond) { WdfTimerStart(TpmContext->timerHandle, WDF_REL_TIMEOUT_IN_MS(TpmContext->TimeOutSecond)); } #endif }
/*++ Routine Description: This routine sets a property on a pipe. Arguments: pDeviceContext - Device context handle pControlTransfer - The control transfer property struct Return Value: NT status value --*/ NTSTATUS ControlTransfer(IN PDEVICE_CONTEXT pDeviceContext, IN PSUSBDRV_CONTROL_TRANSFER* pControlTransfer, IN OUT PUCHAR pControlBuffer, IN size_t nControlBufferSize, OUT ULONG* pLength) { NTSTATUS status = STATUS_SUCCESS; unsigned int nTimeout = PSUSBDRV_DEFAULT_CONTROL_TIMEOUT; WDF_REQUEST_SEND_OPTIONS sendOptions; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDF_MEMORY_DESCRIPTOR memDesc; PAGED_CODE(); RtlZeroMemory(&controlSetupPacket, sizeof(WDF_USB_CONTROL_SETUP_PACKET)); controlSetupPacket.Packet.bm.Request.Dir = pControlTransfer->cDirection; controlSetupPacket.Packet.bm.Request.Type = pControlTransfer->cRequestType; controlSetupPacket.Packet.bm.Request.Recipient = BmRequestToDevice; controlSetupPacket.Packet.bRequest = pControlTransfer->cRequest; controlSetupPacket.Packet.wValue.Value = pControlTransfer->nValue; controlSetupPacket.Packet.wIndex.Value = pControlTransfer->nIndex; PSDrv_DbgPrint(3, ("ControlTransfer: Dir:%d Type:%d Request:%d Value:%d Index:%d.\n", pControlTransfer->cDirection, pControlTransfer->cRequestType, pControlTransfer->cRequest, pControlTransfer->nValue, pControlTransfer->nIndex)); if (pControlTransfer->nTimeout != 0) { if (pControlTransfer->nTimeout > PSUSBDRV_DEFAULT_CONTROL_TIMEOUT) { PSDrv_DbgPrint(3, ("ControlTransfer: Timeout was truncated from %d to %d!\n", pControlTransfer->nTimeout, PSUSBDRV_DEFAULT_CONTROL_TIMEOUT)); nTimeout = PSUSBDRV_DEFAULT_CONTROL_TIMEOUT; } else { nTimeout = pControlTransfer->nTimeout; } } WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(nTimeout)); PSDrv_DbgPrint(3, ("ControlTransfer: Timeout is set to: %d.\n", nTimeout)); PSDrv_DbgPrint(3, ("ControlTransfer: Performing the control transfer...\n")); if (pControlBuffer != NULL) { PSDrv_DbgPrint(3, ("ControlTransfer: Buffer:%x Length:%d\n", pControlBuffer, nControlBufferSize)); if (nControlBufferSize == 0) { PSDrv_DbgPrint(3, ("ControlTransfer: pControlBuffer is not NULL but nControlBufferSize is 0!\n")); return (STATUS_INVALID_PARAMETER); } WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&memDesc, pControlBuffer, (ULONG)nControlBufferSize); status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDeviceContext->WdfUsbTargetDevice, WDF_NO_HANDLE, &sendOptions, &controlSetupPacket, &memDesc, pLength); } else { status = WdfUsbTargetDeviceSendControlTransferSynchronously(pDeviceContext->WdfUsbTargetDevice, WDF_NO_HANDLE, &sendOptions, &controlSetupPacket, NULL, pLength); } PSDrv_DbgPrint(3, ("ControlTransfer: Finished! Status=%x BytesTransferred=%d\n", status, *pLength)); return status; }
VOID HidFx2EvtUsbInterruptPipeReadComplete( WDFUSBPIPE Pipe, WDFMEMORY Buffer, size_t NumBytesTransferred, WDFCONTEXT Context ) /*++ Routine Description: This the completion routine of the continuous reader. This can called concurrently on multiprocessor system if there are more than one readers configured. So make sure to protect access to global resources. Arguments: Pipe - Handle to WDF USB pipe object Buffer - This buffer is freed when this call returns. If the driver wants to delay processing of the buffer, it can take an additional referrence. NumBytesTransferred - number of bytes of data that are in the read buffer. Context - Provided in the WDF_USB_CONTINUOUS_READER_CONFIG_INIT macro Return Value: NT status value --*/ { PDEVICE_EXTENSION devContext = Context; UCHAR toggledSwitch = 0; PUCHAR switchState = NULL; UCHAR currentSwitchState = 0; UCHAR previousSwitchState = 0; UNREFERENCED_PARAMETER(NumBytesTransferred); UNREFERENCED_PARAMETER(Pipe); TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2EvtUsbInterruptPipeReadComplete Enter\n"); // // Interrupt endpoints sends switch state when first started // or when resuming from suspend. We need to ignore that data since // user did not change the switch state. // if (devContext->IsPowerUpSwitchState) { devContext->IsPowerUpSwitchState = FALSE; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Dropping interrupt message since received during powerup/resume\n"); return; } // // Make sure that there is data in the read packet. Depending on the device // specification, it is possible for it to return a 0 length read in // certain conditions. // if (NumBytesTransferred == 0) { TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, "HidFx2EvtUsbInterruptPipeReadComplete Zero length read " "occured on the Interrupt Pipe's Continuous Reader\n" ); return; } switchState = WdfMemoryGetBuffer(Buffer, NULL); currentSwitchState = *switchState; previousSwitchState = devContext->CurrentSwitchState; // // we want to know which switch got toggled from 0 to 1 // Since the device returns the state of all the swicthes and not just the // one that got toggled, we need to store previous state and xor // it with current state to know whcih one swicth got toggled. // Further, the toggle is considered "on" only when it changes from 0 to 1 // (and not when it changes from 1 to 0). // toggledSwitch = (previousSwitchState ^ currentSwitchState) & currentSwitchState; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "HidFx2EvtUsbInterruptPipeReadComplete SwitchState %x, " "prevSwitch:0x%x, x0R:0x%x\n", currentSwitchState, previousSwitchState, toggledSwitch ); // // Store switch state in device context // devContext->CurrentSwitchState = *switchState; //if (toggledSwitch != 0) { devContext->LatestToggledSwitch = toggledSwitch; //} // // Complete pending Read requests if there is at least one switch toggled // to on position. // if (toggledSwitch != 0) { BOOLEAN inTimerQueue; // // Debounce the switchpack. A simple logic is used for debouncing. // A timer is started for 10 ms everytime there is a switch toggled on. // If within 10 ms same or another switch gets toggled, the timer gets // reset for another 10 ms. The HID read request is completed in timer // function if there is still a switch in toggled-on state. Note that // debouncing happens at the whole switch pack level (not individual // switches) which means if two different switches are toggled-on within // 10 ms only one of them (later one in this case) will get accepted and // sent to hidclass driver // inTimerQueue = WdfTimerStart( devContext->DebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWICTHPACK_DEBOUNCE_TIME_IN_MS) ); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Debounce Timer started with timeout of %d ms" " (TimerReturnValue:%d)\n", SWICTHPACK_DEBOUNCE_TIME_IN_MS, inTimerQueue); } TraceEvents(TRACE_LEVEL_VERBOSE, DBG_INIT, "HidFx2EvtUsbInterruptPipeReadComplete Exit\n"); }
NTSTATUS Toastmon_OpenDevice( WDFDEVICE Device, PUNICODE_STRING SymbolicLink, WDFIOTARGET *Target ) /*++ Routine Description: Open the I/O target and preallocate any resources required to communicate with the target device. Arguments: Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; PTARGET_DEVICE_INFO targetDeviceInfo = NULL; WDF_IO_TARGET_OPEN_PARAMS openParams; WDFIOTARGET ioTarget; WDF_OBJECT_ATTRIBUTES attributes; PDEVICE_EXTENSION deviceExtension = GetDeviceExtension(Device); WDF_TIMER_CONFIG wdfTimerConfig; WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TARGET_DEVICE_INFO); status = WdfIoTargetCreate(deviceExtension->WdfDevice, &attributes, &ioTarget); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetCreate failed 0x%x\n", status)); return status; } targetDeviceInfo = GetTargetDeviceInfo(ioTarget); targetDeviceInfo->DeviceExtension = deviceExtension; // // Warning: It's not recommended to open the targetdevice // from a pnp notification callback routine, because if // the target device initiates any kind of PnP action as // a result of this open, the PnP manager could deadlock. // You should queue a workitem to do that. // For example, SWENUM devices in conjunction with KS // initiate an enumeration of a device when you do the // open on the device interface. // We can open the target device here because we know the // toaster function driver doesn't trigger any pnp action. // WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME( &openParams, SymbolicLink, STANDARD_RIGHTS_ALL); openParams.ShareAccess = FILE_SHARE_WRITE | FILE_SHARE_READ; // // Framework provides default action for all of these if you don't register // these callbacks -it will close the handle to the target when the device is // being query-removed and reopen it if the query-remove fails. // In this sample, we use a periodic timers to post requests to the target. // So we need to register these callbacks so that we can start and stop // the timer when the state of the target device changes. Since we are // registering these callbacks, we are now responsbile for closing and // reopening the target. // openParams.EvtIoTargetQueryRemove = ToastMon_EvtIoTargetQueryRemove; openParams.EvtIoTargetRemoveCanceled = ToastMon_EvtIoTargetRemoveCanceled; openParams.EvtIoTargetRemoveComplete = ToastMon_EvtIoTargetRemoveComplete; status = WdfIoTargetOpen(ioTarget, &openParams); if (!NT_SUCCESS(status)) { KdPrint(("WdfIoTargetOpen failed with status 0x%x\n", status)); WdfObjectDelete(ioTarget); return status; } KdPrint(("Target Device 0x%x, PDO 0x%x, Fileobject 0x%x, Filehandle 0x%x\n", WdfIoTargetWdmGetTargetDeviceObject(ioTarget), WdfIoTargetWdmGetTargetPhysicalDevice(ioTarget), WdfIoTargetWdmGetTargetFileObject(ioTarget), WdfIoTargetWdmGetTargetFileHandle(ioTarget))); // // Create two requests - one for read and one for write. // WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = ioTarget; status = WdfRequestCreate(&attributes, ioTarget, &targetDeviceInfo->ReadRequest); if (!NT_SUCCESS(status)) { WdfObjectDelete(ioTarget); return status; } WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = ioTarget; status = WdfRequestCreate(&attributes, ioTarget, &targetDeviceInfo->WriteRequest); if (!NT_SUCCESS(status)) { WdfObjectDelete(ioTarget); return status; } // // Create a passive timer to post requests to the I/O target. // WDF_TIMER_CONFIG_INIT(&wdfTimerConfig, Toastmon_EvtTimerPostRequests); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, TIMER_CONTEXT); // // Make IoTarget as parent of the timer to prevent the ioTarget // from deleted until the dpc has runto completion. // attributes.ParentObject = ioTarget; // // By specifying WdfExecutionLevelPassive the framework will invoke // the timer callback Toastmon_EvtTimerPostRequests at PASSIVE_LEVEL. // attributes.ExecutionLevel = WdfExecutionLevelPassive; // // Setting the AutomaticSerialization to FALSE prevents // WdfTimerCreate to fail if the parent device object's // execution level is set to WdfExecutionLevelPassive. // wdfTimerConfig.AutomaticSerialization = FALSE; status = WdfTimerCreate(&wdfTimerConfig, &attributes, &targetDeviceInfo->TimerForPostingRequests ); if(!NT_SUCCESS(status)) { KdPrint(("WdfTimerCreate failed 0x%x\n", status)); WdfObjectDelete(ioTarget); return status; } GetTimerContext(targetDeviceInfo->TimerForPostingRequests)->IoTarget = ioTarget; // // Start the passive timer. The first timer will be queued after 1ms interval and // after that it will be requeued in the timer callback function. // The value of 1 ms (lowest timer resoltion allowed on NT) is chosen here so // that timer would fire right away. // WdfTimerStart(targetDeviceInfo->TimerForPostingRequests, WDF_REL_TIMEOUT_IN_MS(1)); *Target = ioTarget; return status; }
/*++ Routine Description: This callback is invoked when the framework received WdfRequestTypeRead or WdfRequestTypeWrite request. This read/write is performed in stages of MAX_TRANSFER_SIZE. Once a stage of transfer is complete, then the request is circulated again, until the requested length of transfer is performed. Arguments: Queue - Handle to the framework queue object that is associated with the I/O request. Request - Handle to a framework request object. This one represents the WdfRequestTypeRead/WdfRequestTypeWrite IRP received by the framework. Length - Length of the input/output buffer. Return Value: VOID --*/ VOID ReadWriteBulkEndPoints(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN ULONG Length, IN WDF_REQUEST_TYPE RequestType) { PMDL newMdl = NULL; PMDL requestMdl = NULL; PURB urb = NULL; WDFMEMORY urbMemory; ULONG totalLength = Length; ULONG stageLength = 0; ULONG urbFlags = 0; NTSTATUS status; ULONG_PTR virtualAddress = 0; PREQUEST_CONTEXT rwContext = NULL; PFILE_CONTEXT fileContext = NULL; WDFUSBPIPE pipe; WDF_USB_PIPE_INFORMATION pipeInfo; WDF_OBJECT_ATTRIBUTES objectAttribs; USBD_PIPE_HANDLE usbdPipeHandle; PDEVICE_CONTEXT deviceContext; WDF_REQUEST_SEND_OPTIONS sendOptions; PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - begins\n")); // First validate input parameters. deviceContext = GetDeviceContext(WdfIoQueueGetDevice(Queue)); if (totalLength > deviceContext->MaximumTransferSize) { PSDrv_DbgPrint(1, ("Transfer length (%d) is bigger then MaximumTransferSize (%d)!\n", totalLength, deviceContext->MaximumTransferSize)); status = STATUS_INVALID_PARAMETER; goto Exit; } if ((RequestType != WdfRequestTypeRead) && (RequestType != WdfRequestTypeWrite)) { PSDrv_DbgPrint(1, ("RequestType has to be either Read or Write! (RequestType = %d)\n", RequestType)); status = STATUS_INVALID_PARAMETER; goto Exit; } // Get the pipe associate with this request. fileContext = GetFileContext(WdfRequestGetFileObject(Request)); pipe = fileContext->Pipe; WDF_USB_PIPE_INFORMATION_INIT(&pipeInfo); WdfUsbTargetPipeGetInformation(pipe, &pipeInfo); if((WdfUsbPipeTypeBulk != pipeInfo.PipeType) && (WdfUsbPipeTypeInterrupt != pipeInfo.PipeType)) { PSDrv_DbgPrint(1, ("Usbd pipe type is not bulk or interrupt! (PipeType = %d)\n", pipeInfo.PipeType)); status = STATUS_INVALID_DEVICE_REQUEST; goto Exit; } rwContext = GetRequestContext(Request); if(RequestType == WdfRequestTypeRead) { status = WdfRequestRetrieveOutputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveOutputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_IN; rwContext->Read = TRUE; PSDrv_DbgPrint(3, ("This is a read operation...\n")); } else { status = WdfRequestRetrieveInputWdmMdl(Request, &requestMdl); if(!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfRequestRetrieveInputWdmMdl failed! (Status = %x)\n", status)); goto Exit; } urbFlags |= USBD_TRANSFER_DIRECTION_OUT; rwContext->Read = FALSE; PSDrv_DbgPrint(3, ("This is a write operation...\n")); } urbFlags |= USBD_SHORT_TRANSFER_OK; virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(requestMdl); // The transfer request is for totalLength. We can perform a max of MAX_TRANSFER_SIZE in each stage. if (totalLength > MAX_TRANSFER_SIZE) { stageLength = MAX_TRANSFER_SIZE; } else { stageLength = totalLength; } newMdl = IoAllocateMdl((PVOID)virtualAddress, totalLength, FALSE, FALSE, NULL); if (newMdl == NULL) { PSDrv_DbgPrint(1, ("IoAllocateMdl failed! (newMdl is NULL)\n")); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } // Map the portion of user-buffer described by an mdl to another mdl IoBuildPartialMdl(requestMdl, newMdl, (PVOID)virtualAddress, stageLength); WDF_OBJECT_ATTRIBUTES_INIT(&objectAttribs); objectAttribs.ParentObject = Request; status = WdfMemoryCreate(&objectAttribs, NonPagedPool, POOL_TAG, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urbMemory, (PVOID*)&urb); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfMemoryCreate for urbMemory failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle(pipe); UsbBuildInterruptOrBulkTransferRequest(urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbdPipeHandle, NULL, newMdl, stageLength, urbFlags, NULL); status = WdfUsbTargetPipeFormatRequestForUrb(pipe, Request, urbMemory, NULL); if (!NT_SUCCESS(status)) { PSDrv_DbgPrint(1, ("WdfUsbTargetPipeFormatRequestForUrb failed! (Status = %x)\n", status)); status = STATUS_INSUFFICIENT_RESOURCES; goto Exit; } WdfRequestSetCompletionRoutine(Request, ReadWriteCompletion, NULL); // Set REQUEST_CONTEXT parameters. rwContext->UrbMemory = urbMemory; rwContext->Mdl = newMdl; rwContext->Length = totalLength - stageLength; rwContext->Numxfer = 0; rwContext->VirtualAddress = virtualAddress + stageLength; // Set the timeout if (fileContext->nTimeOut != 0) { WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(fileContext->nTimeOut)); PSDrv_DbgPrint(3, ("Pipe timeout is set to: %d\n", fileContext->nTimeOut)); if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), &sendOptions)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } else { if (!WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pipe), WDF_NO_SEND_OPTIONS)) { status = WdfRequestGetStatus(Request); ASSERT(!NT_SUCCESS(status)); } } Exit: if (!NT_SUCCESS(status)) { WdfRequestCompleteWithInformation(Request, status, 0); if (newMdl != NULL) { IoFreeMdl(newMdl); } } PSDrv_DbgPrint(3, ("ReadWriteBulkEndPoints - ends\n")); return; }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback reads current value, compare value to threshold, // pushes it up to CLX framework, and schedule next wake up time. VOID PedometerDevice::OnTimerExpire( _In_ WDFTIMER Timer // WDF timer object ) { PPedometerDevice pDevice = nullptr; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); pDevice = GetPedometerContextFromSensorInstance(WdfTimerGetParentObject(Timer)); if (nullptr == pDevice) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetPedometerContextFromSensorInstance failed %!STATUS!", Status); goto Exit; } // Get data and push to clx WdfWaitLockAcquire(pDevice->m_Lock, NULL); Status = pDevice->GetData(); if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) { TraceError("PED %!FUNC! GetData Failed %!STATUS!", Status); } WdfWaitLockRelease(pDevice->m_Lock); // Schedule next wake up time if (FALSE != pDevice->m_PoweredOn && FALSE != pDevice->m_Started) { LONGLONG WaitTimeHundredNanoseconds = 0; // in unit of 100ns if (0 == pDevice->m_StartTime) { // in case we fail to get sensor start time, use static wait time WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { ULONG CurrentTimeMs = 0; // dynamically calculate wait time to avoid jitter Status = GetPerformanceTime (&CurrentTimeMs); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetPerformanceTime %!STATUS!", Status); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { pDevice->m_SampleCount++; if (CurrentTimeMs > (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1)))) { // If we skipped two or more beats, reschedule the timer with a zero due time to catch up on missing samples WaitTimeHundredNanoseconds = 0; } else { WaitTimeHundredNanoseconds = (pDevice->m_StartTime + (pDevice->m_Interval * (pDevice->m_SampleCount + 1))) - CurrentTimeMs; } WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds); } } WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds); } Exit: SENSOR_FunctionExit(Status); }
VOID EvtIoDeviceControl( IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode ) { WDFDEVICE device; PDEVICE_CONTEXT pDevContext; size_t bytesTransferred = 0; NTSTATUS status; WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket; WDF_MEMORY_DESCRIPTOR memDesc; WDFMEMORY memory; WDF_REQUEST_SEND_OPTIONS sendOptions; UNREFERENCED_PARAMETER(InputBufferLength); UNREFERENCED_PARAMETER(OutputBufferLength); device = WdfIoQueueGetDevice(Queue); pDevContext = GetDeviceContext(device); switch(IoControlCode) { case IOCTL_OSRUSBFX2_SET_BAR_GRAPH_DISPLAY: if(InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_OVERFLOW; bytesTransferred = sizeof(UCHAR); break; } status = WdfRequestRetrieveInputMemory(Request, &memory); if (!NT_SUCCESS(status)) { KdPrint(("WdfRequestRetrieveMemory failed %!STATUS!", status)); break; } WDF_USB_CONTROL_SETUP_PACKET_INIT_VENDOR(&controlSetupPacket, BmRequestHostToDevice, BmRequestToDevice, USBFX2LK_SET_BARGRAPH_DISPLAY, // Request 0, // Value 0); // Index WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&memDesc, memory, NULL); // // Send the I/O with a timeout to avoid hanging the calling // thread indefinitely. // WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(100)); status = WdfUsbTargetDeviceSendControlTransferSynchronously( pDevContext->UsbDevice, NULL, // Optional WDFREQUEST &sendOptions, // PWDF_REQUEST_SEND_OPTIONS &controlSetupPacket, &memDesc, (PULONG)&bytesTransferred); if (!NT_SUCCESS(status)) { KdPrint(("SendControlTransfer failed %!STATUS!", status)); break; } break; default: status = STATUS_INVALID_DEVICE_REQUEST; break; } WdfRequestCompleteWithInformation(Request, status, bytesTransferred); return; }
NTSTATUS Acpi_EvaluateUcsiDsm ( _In_ PACPI_CONTEXT AcpiCtx, _In_ ULONG FunctionIndex, _Outptr_opt_ PACPI_EVAL_OUTPUT_BUFFER* Output ) /*++ N.B. Caller is expected to free the Output buffer. --*/ { NTSTATUS status; WDFDEVICE device; WDFMEMORY inputMemory; WDF_MEMORY_DESCRIPTOR inputMemDesc; PACPI_EVAL_INPUT_BUFFER_COMPLEX inputBuffer; size_t inputBufferSize; size_t inputArgumentBufferSize; PACPI_METHOD_ARGUMENT argument; WDF_MEMORY_DESCRIPTOR outputMemDesc; PACPI_EVAL_OUTPUT_BUFFER outputBuffer; size_t outputBufferSize; size_t outputArgumentBufferSize; WDF_OBJECT_ATTRIBUTES attributes; WDF_REQUEST_SEND_OPTIONS sendOptions; PAGED_CODE(); TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); device = Context_GetWdfDevice(AcpiCtx); inputMemory = WDF_NO_HANDLE; outputBuffer = nullptr; inputArgumentBufferSize = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(GUID)) + ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + ACPI_METHOD_ARGUMENT_LENGTH(0); inputBufferSize = FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) + inputArgumentBufferSize; WDF_OBJECT_ATTRIBUTES_INIT(&attributes); attributes.ParentObject = device; status = WdfMemoryCreate(&attributes, NonPagedPoolNx, 0, inputBufferSize, &inputMemory, (PVOID*) &inputBuffer); if (!NT_SUCCESS(status)) { TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate failed for %Iu bytes - %!STATUS!", device, inputBufferSize, status); goto Exit; } RtlZeroMemory(inputBuffer, inputBufferSize); inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE; inputBuffer->Size = (ULONG) inputArgumentBufferSize; inputBuffer->ArgumentCount = 4; inputBuffer->MethodNameAsUlong = (ULONG) 'MSD_'; argument = &(inputBuffer->Argument[0]); ACPI_METHOD_SET_ARGUMENT_BUFFER(argument, &GUID_UCSI_DSM, sizeof(GUID_UCSI_DSM)); argument = ACPI_METHOD_NEXT_ARGUMENT(argument); ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, UCSI_DSM_REVISION); argument = ACPI_METHOD_NEXT_ARGUMENT(argument); ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, FunctionIndex); argument = ACPI_METHOD_NEXT_ARGUMENT(argument); argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE_EX; argument->DataLength = 0; outputArgumentBufferSize = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)); outputBufferSize = FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + outputArgumentBufferSize; outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER) ExAllocatePoolWithTag(NonPagedPoolNx, outputBufferSize, TAG_UCSI); if (outputBuffer == nullptr) { status = STATUS_INSUFFICIENT_RESOURCES; TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ExAllocatePoolWithTag failed for %Iu bytes", device, outputBufferSize); goto Exit; } RtlZeroMemory(outputBuffer, outputBufferSize); WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemDesc, inputMemory, NULL); WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputMemDesc, outputBuffer, (ULONG) outputBufferSize); WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, WDF_REL_TIMEOUT_IN_MS(UCSI_DSM_EXECUTION_TIMEOUT_IN_MS)); status = WdfIoTargetSendInternalIoctlSynchronously( WdfDeviceGetIoTarget(device), NULL, IOCTL_ACPI_EVAL_METHOD, &inputMemDesc, &outputMemDesc, &sendOptions, NULL); if (!NT_SUCCESS(status)) { TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_EVAL_METHOD for _DSM failed - %!STATUS!", device, status); goto Exit; } if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) { TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI_EVAL_OUTPUT_BUFFER signature is incorrect", device); status = STATUS_ACPI_INVALID_DATA; goto Exit; } Exit: if (inputMemory != WDF_NO_HANDLE) { WdfObjectDelete(inputMemory); } if (!NT_SUCCESS(status) || (Output == nullptr)) { if (outputBuffer) { ExFreePoolWithTag(outputBuffer, TAG_UCSI); } } else { *Output = outputBuffer; } TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); return status; }
// This callback is called when interval wait time has expired and driver is ready // to collect new sample. The callback reads current value, // pushes it up to CLX framework, and schedule next wake up time. VOID CustomSensorDevice::OnTimerExpire( _In_ WDFTIMER Timer // WDF timer object ) { PCustomSensorDevice pDevice = nullptr; NTSTATUS Status = STATUS_SUCCESS; SENSOR_FunctionEnter(); pDevice = GetCustomSensorContextFromSensorInstance(WdfTimerGetParentObject(Timer)); if (nullptr == pDevice) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("CSTM %!FUNC! GetCustomSensorContextFromSensorInstance failed %!STATUS!", Status); } if (NT_SUCCESS(Status)) { // Get data and push to clx WdfWaitLockAcquire(pDevice->m_Lock, NULL); Status = pDevice->GetData(); if (!NT_SUCCESS(Status) && Status != STATUS_DATA_NOT_ACCEPTED) { TraceError("CSTM %!FUNC! GetCstmData Failed %!STATUS!", Status); } WdfWaitLockRelease(pDevice->m_Lock); // Schedule next wake up time if (FALSE != pDevice->m_PoweredOn && FALSE != pDevice->m_Started) { LONGLONG WaitTimeHundredNanoseconds = 0; // in unit of 100ns if (0 == pDevice->m_StartTime) { // in case we fail to get sensor start time, use static wait time WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { ULONG CurrentTimeMs = 0; // dynamically calculate wait time to avoid jitter Status = GetPerformanceTime(&CurrentTimeMs); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetPerformanceTime %!STATUS!", Status); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(pDevice->m_Interval); } else { WaitTimeHundredNanoseconds = pDevice->m_Interval - ((CurrentTimeMs - pDevice->m_StartTime) % pDevice->m_Interval); WaitTimeHundredNanoseconds = WDF_REL_TIMEOUT_IN_MS(WaitTimeHundredNanoseconds); } } WdfTimerStart(pDevice->m_Timer, WaitTimeHundredNanoseconds); } } SENSOR_FunctionExit(Status); }
// This the completion routine of the continuous reader. This can called concurrently on multiprocessor system if there are // more than one readers configured. So make sure to protect access to global resources. // void HidFx2EvtUsbInterruptPipeReadComplete( WDFUSBPIPE hPipe, WDFMEMORY hBuffer, size_t cNumBytesTransferred, WDFCONTEXT pContext ) { PDEVICE_EXTENSION pDevContext = pContext; BOOLEAN fInTimerQueue; unsigned char *pbSwitchState = NULL; unsigned char bCurrentSwitchState = 0; unsigned char bPrevSwitchState = 0; unsigned char bToggledSwitch = 0; UNREFERENCED_PARAMETER(cNumBytesTransferred); UNREFERENCED_PARAMETER(hPipe); TraceVerbose(DBG_INIT, "(%!FUNC!) Enter\n"); // Interrupt endpoints sends switch state when first started or when resuming from suspend. // We need to ignore that data since user did not change the switch state. if (pDevContext->fIsPowerUpSwitchState) { pDevContext->fIsPowerUpSwitchState = FALSE; TraceInfo(DBG_INIT, "(%!FUNC!) Dropping interrupt message since received during powerup/resume\n"); return; } // Make sure that there is data in the read packet. // Depending on the device specification, it is possible for it to return a 0 length read in certain conditions. if (cNumBytesTransferred == 0) { TraceWarning(DBG_INIT, "(%!FUNC!) Zero length read occured on the Interrupt Pipe's Continuous Reader\n"); return; } pbSwitchState = WdfMemoryGetBuffer(hBuffer, NULL); bCurrentSwitchState = ~(*pbSwitchState); // switchs are inverted on hardware boards bCurrentSwitchState &= RADIO_SWITCH_BUTTONS_BIT_MASK; //Mask off everything except the actual radio switch bit bPrevSwitchState = pDevContext->bCurrentSwitchState; if (bPrevSwitchState ^ bCurrentSwitchState) // make sure we toggled the radio switch { switch(pDevContext->driverMode) { // If it's a slider switch we want 0->1 and 1->0 transitions. case DM_SLIDER_SWITCH: case DM_SLIDER_SWITCH_AND_LED: bToggledSwitch = bCurrentSwitchState; // A timer is started for 10 ms everytime there is a switch toggled fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); break; //If it's a button so we only report 0->1 transitions case DM_BUTTON: case DM_BUTTON_AND_LED: bToggledSwitch = (bPrevSwitchState ^ bCurrentSwitchState) & bCurrentSwitchState; if (bToggledSwitch != 0) { // A timer is started for 10 ms everytime there is a switch toggled on fInTimerQueue = WdfTimerStart(pDevContext->hDebounceTimer, WDF_REL_TIMEOUT_IN_MS(SWITCHPACK_DEBOUNCE_TIME)); TraceInfo(DBG_INIT, "(%!FUNC!) Debounce Timer started. Existing -%!bool!\n", fInTimerQueue); } break; // Ignore button presses if LED only case DM_LED_ONLY: default: break; } // Store switch state in device context pDevContext->bCurrentSwitchState = bCurrentSwitchState; pDevContext->bLatestToggledSwitch = bToggledSwitch; } else { TraceInfo(DBG_INIT, "(%!FUNC!) Not a radio switch toggle\n"); } TraceInfo(DBG_INIT, "(%!FUNC!) Switch 0x%x, prevSwitch:0x%x, X0R:0x%x\n", bCurrentSwitchState, bPrevSwitchState, bToggledSwitch); TraceVerbose(DBG_INIT, "(%!FUNC!) Exit\n"); }
VOID SimSensorAddReadRequest ( _In_ WDFDEVICE Device, _In_ WDFREQUEST ReadRequest ) /*++ Routine Description: Handles IOCTL_THERMAL_READ_TEMPERATURE. If the request can be satisfied, it is completed immediately. Else, adds request to pending request queue. Arguments: Device - Supplies a handle to the device that received the request. ReadRequest - Supplies a handle to the request. --*/ { ULONG BytesReturned; PREAD_REQUEST_CONTEXT Context; WDF_OBJECT_ATTRIBUTES ContextAttributes; PFDO_DATA DevExt; LARGE_INTEGER ExpirationTime; size_t Length; BOOLEAN LockHeld; PULONG RequestTemperature; NTSTATUS Status; ULONG Temperature; WDFTIMER Timer; WDF_OBJECT_ATTRIBUTES TimerAttributes; WDF_TIMER_CONFIG TimerConfig; PTHERMAL_WAIT_READ ThermalWaitRead; DebugEnter(); PAGED_CODE(); DevExt = GetDeviceExtension(Device); BytesReturned = 0; LockHeld = FALSE; Status = WdfRequestRetrieveInputBuffer(ReadRequest, sizeof(THERMAL_WAIT_READ), &ThermalWaitRead, &Length); if (!NT_SUCCESS(Status) || Length != sizeof(THERMAL_WAIT_READ)) { // // This request is malformed, bail. // WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } if (ThermalWaitRead->Timeout != -1 /* INFINITE */ ) { // // Estimate the system time this request will expire at. // KeQuerySystemTime(&ExpirationTime); ExpirationTime.QuadPart += ThermalWaitRead->Timeout * 10000; } else { // // Value which indicates the request never expires. // ExpirationTime.QuadPart = -1LL /* INFINITE */; } // // Handle the immediate timeout case in the fast path. // Temperature = SimSensorReadVirtualTemperature(Device); if (SimSensorAreConstraintsSatisfied(Temperature, ThermalWaitRead->LowTemperature, ThermalWaitRead->HighTemperature, ExpirationTime)) { Status = WdfRequestRetrieveOutputBuffer(ReadRequest, sizeof(ULONG), &RequestTemperature, &Length); if(NT_SUCCESS(Status) && Length == sizeof(ULONG)) { *RequestTemperature = Temperature; BytesReturned = sizeof(ULONG); } else { Status = STATUS_INVALID_PARAMETER; DebugPrint(SIMSENSOR_ERROR, "WdfRequestRetrieveOutputBuffer() Failed. 0x%x", Status); } WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); } else { WdfWaitLockAcquire(DevExt->QueueLock, NULL); LockHeld = TRUE; // // Create a context to store request-specific information. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&ContextAttributes, READ_REQUEST_CONTEXT); Status = WdfObjectAllocateContext(ReadRequest, &ContextAttributes, &Context); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfObjectAllocateContext() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } Context->ExpirationTime.QuadPart = ExpirationTime.QuadPart; Context->LowTemperature = ThermalWaitRead->LowTemperature; Context->HighTemperature = ThermalWaitRead->HighTemperature; if(Context->ExpirationTime.QuadPart != -1LL /* INFINITE */ ) { // // This request eventually expires, create a timer to complete it. // WDF_TIMER_CONFIG_INIT(&TimerConfig, SimSensorExpiredRequestTimer); WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; TimerAttributes.SynchronizationScope = WdfSynchronizationScopeNone; TimerAttributes.ParentObject = Device; Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &Timer); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfTimerCreate() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } WdfTimerStart(Timer, WDF_REL_TIMEOUT_IN_MS(ThermalWaitRead->Timeout)); } Status = WdfRequestForwardToIoQueue(ReadRequest, DevExt->PendingRequestQueue); if(!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfRequestForwardToIoQueue() Failed. 0x%x", Status); WdfRequestCompleteWithInformation(ReadRequest, Status, BytesReturned); goto AddReadRequestEnd; } // // Force a rescan of the queue to update the interrupt thresholds. // SimSensorScanPendingQueue(Device); } AddReadRequestEnd: if(LockHeld == TRUE) { WdfWaitLockRelease(DevExt->QueueLock); } DebugExitStatus(Status); }
NDIS_STATUS StaAssociate( __in PSTATION pStation, __in PSTA_BSS_ENTRY pAPEntry, __in ULONG AssociateTimeout ) { NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS; PUCHAR pAssocPacket = NULL; USHORT AssocPacketLength; ULONG StatusCode = 0; MpEntry; do { // // Create the associate packet // ndisStatus = StaCreateAssociateRequestPacket( pStation, pAPEntry, &pAssocPacket, &AssocPacketLength ); if (ndisStatus != NDIS_STATUS_SUCCESS) { // // Complete the association process // StatusCode = ndisStatus; NdisAcquireSpinLock(&(pStation->ConnectContext.Lock)); if (pStation->ConnectContext.AssociateState == ASSOC_STATE_RECEIVED_AUTHENTICATE) { // // Reset ourselves to ready to original state // pStation->ConnectContext.AssociateState = ASSOC_STATE_STARTED_ASSOCIATION; } NdisReleaseSpinLock(&(pStation->ConnectContext.Lock)); break; } NdisAcquireSpinLock(&(pStation->ConnectContext.Lock)); if ((pStation->ConnectContext.ConnectState >= CONN_STATE_READY_TO_CONNECT) && (pStation->ConnectContext.AssociateState == ASSOC_STATE_RECEIVED_AUTHENTICATE)) { // // Packet will be sent means we will be waiting for packet response // pStation->ConnectContext.AssociateState = ASSOC_STATE_WAITING_FOR_ASSOCIATE; // // Save association request packet inside the AP entry. This will be freed // on association completion indication // NdisDprAcquireSpinLock(&(pAPEntry->Lock)); pAPEntry->pAssocRequest = pAssocPacket; pAPEntry->AssocRequestLength = AssocPacketLength; NdisDprReleaseSpinLock(&(pAPEntry->Lock)); NdisReleaseSpinLock(&(pStation->ConnectContext.Lock)); } else { // // Reset, disconnect, deauthenticated by AP after authentication succeeded // NdisReleaseSpinLock(&(pStation->ConnectContext.Lock)); MpTrace(COMP_ASSOC, DBG_LOUD, ("Reset/Disconnect/Deauth while starting association\n")); // // Assoc packet pointer isnt saved, free it // StaFreeAssociateRequestPacket( pStation, pAPEntry, pAssocPacket, AssocPacketLength ); // // Abort association // StatusCode = (ULONG)STATUS_CANCELLED; break; } // // Send the association request packet // ndisStatus = Hw11SendMgmtPacket( pStation->pNic, pAPEntry, pAssocPacket, AssocPacketLength ); if (ndisStatus != NDIS_STATUS_SUCCESS) { MpTrace(COMP_ASSOC, DBG_SERIOUS, ("Unable to send Association Request packet\n")); StatusCode = ndisStatus; NdisAcquireSpinLock(&(pStation->ConnectContext.Lock)); if (pStation->ConnectContext.AssociateState == ASSOC_STATE_WAITING_FOR_AUTHENTICATE) { // // Reset ourselves to ready to original state // pStation->ConnectContext.AssociateState = ASSOC_STATE_STARTED_ASSOCIATION; } NdisReleaseSpinLock(&(pStation->ConnectContext.Lock)); break; } else { // Add an extra refcount for the association timer STA_INCREMENT_REF(pStation->ConnectContext.AsyncFuncCount); // // Set the timeout timer for associate failure case. // //NdisMSetTimer(&(pStation->ConnectContext.Timer_AssociateTimeout), AssociateTimeout); WdfTimerStart(pStation->ConnectContext.Timer_AssociateTimeout, WDF_REL_TIMEOUT_IN_MS(AssociateTimeout)); } // // We dont let the hardware pend the request since we will be // freeing the packet // MPVERIFY(ndisStatus != NDIS_STATUS_PENDING); }while (FALSE); // // Fail the association if we failed inline, etc // if (StatusCode != 0) { StaAssociateComplete(pStation, DOT11_ASSOC_STATUS_SYSTEM_ERROR); } return ndisStatus; }
NTSTATUS AndroidUsbPipeFileObject::CommonBulkReadWrite( WDFREQUEST request, PMDL transfer_mdl, ULONG length, bool is_read, ULONG time_out, bool is_ioctl) { ASSERT_IRQL_LOW_OR_DISPATCH(); ASSERT(IsPipeAttached()); if (!IsPipeAttached()) { WdfRequestComplete(request, STATUS_INVALID_DEVICE_STATE); return STATUS_INVALID_DEVICE_STATE; } // Quick access check. Might be redundant though... ASSERT((is_read && is_input_pipe()) || (!is_read && is_output_pipe())); if ((is_read && is_output_pipe()) || (!is_read && is_input_pipe())) { WdfRequestComplete(request, STATUS_ACCESS_DENIED); return STATUS_ACCESS_DENIED; } // Set URB flags ULONG urb_flags = USBD_SHORT_TRANSFER_OK | (is_read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT); // Calculate transfer length for this stage. ULONG stage_len = (length > GetTransferGranularity()) ? GetTransferGranularity() : length; // Get virtual address that we're gonna use in the transfer. // We rely here on the fact that we're in the context of the calling thread. void* virtual_address = MmGetMdlVirtualAddress(transfer_mdl); // Allocate our private MDL for this address which we will use for the transfer PMDL new_mdl = IoAllocateMdl(virtual_address, length, FALSE, FALSE, NULL); ASSERT(NULL != new_mdl); if (NULL == new_mdl) { WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; } // Map the portion of user buffer that we're going to transfer at this stage // to our mdl. IoBuildPartialMdl(transfer_mdl, new_mdl, virtual_address, stage_len); // Allocate memory for URB and associate it with this request WDF_OBJECT_ATTRIBUTES mem_attrib; WDF_OBJECT_ATTRIBUTES_INIT(&mem_attrib); mem_attrib.ParentObject = request; WDFMEMORY urb_mem = NULL; PURB urb = NULL; NTSTATUS status = WdfMemoryCreate(&mem_attrib, NonPagedPool, GANDR_POOL_TAG_BULKRW_URB, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), &urb_mem, reinterpret_cast<PVOID*>(&urb)); ASSERT(NT_SUCCESS(status) && (NULL != urb)); if (!NT_SUCCESS(status)) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INSUFFICIENT_RESOURCES); return STATUS_INSUFFICIENT_RESOURCES; } // Get USB pipe handle for our pipe and initialize transfer request for it USBD_PIPE_HANDLE usbd_pipe_hndl = usbd_pipe(); ASSERT(NULL != usbd_pipe_hndl); if (NULL == usbd_pipe_hndl) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INTERNAL_ERROR); return STATUS_INTERNAL_ERROR; } // Initialize URB with request information UsbBuildInterruptOrBulkTransferRequest( urb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), usbd_pipe_hndl, NULL, new_mdl, stage_len, urb_flags, NULL); // Build transfer request status = WdfUsbTargetPipeFormatRequestForUrb(wdf_pipe(), request, urb_mem, NULL); ASSERT(NT_SUCCESS(status)); if (!NT_SUCCESS(status)) { IoFreeMdl(new_mdl); WdfRequestComplete(request, status); return status; } // Initialize our request context. AndroidUsbWdfRequestContext* context = GetAndroidUsbWdfRequestContext(request); ASSERT(NULL != context); if (NULL == context) { IoFreeMdl(new_mdl); WdfRequestComplete(request, STATUS_INTERNAL_ERROR); return STATUS_INTERNAL_ERROR; } context->object_type = AndroidUsbWdfObjectTypeRequest; context->urb_mem = urb_mem; context->transfer_mdl = transfer_mdl; context->mdl = new_mdl; context->length = length; context->transfer_size = stage_len; context->num_xfer = 0; context->virtual_address = virtual_address; context->is_read = is_read; context->initial_time_out = time_out; context->is_ioctl = is_ioctl; // Set our completion routine WdfRequestSetCompletionRoutine(request, CommonReadWriteCompletionEntry, this); // Init send options (our timeout goes here) WDF_REQUEST_SEND_OPTIONS send_options; if (0 != time_out) { WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_TIMEOUT); WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&send_options, WDF_REL_TIMEOUT_IN_MS(time_out)); } // Timestamp first WdfRequestSend KeQuerySystemTime(&context->sent_at); // Send request asynchronously. if (WdfRequestSend(request, wdf_pipe_io_target(), (0 == time_out) ? WDF_NO_SEND_OPTIONS : &send_options)) { return STATUS_SUCCESS; } // Something went wrong here status = WdfRequestGetStatus(request); ASSERT(!NT_SUCCESS(status)); GoogleDbgPrint("\n!!!!! CommonBulkReadWrite: WdfRequestGetStatus (is_read = %u) failed: %08X", is_read, status); WdfRequestCompleteWithInformation(request, status, 0); return status; }