_Use_decl_annotations_ NTSTATUS SimBattQueryStatus ( PVOID Context, ULONG BatteryTag, PBATTERY_STATUS BatteryStatus ) /*++ Routine Description: Called by the class driver to retrieve the batteries current status The battery class driver will serialize all requests it issues to the miniport for a given battery. Arguments: Context - Supplies the miniport context value for battery BatteryTag - Supplies the tag of current battery BatteryStatus - Supplies a pointer to the structure to return the current battery status in Return Value: Success if there is a battery currently installed, else no such device. --*/ { PSIMBATT_FDO_DATA DevExt; NTSTATUS Status; DebugEnter(); PAGED_CODE(); DevExt = (PSIMBATT_FDO_DATA)Context; WdfWaitLockAcquire(DevExt->StateLock, NULL); if (BatteryTag != DevExt->BatteryTag) { Status = STATUS_NO_SUCH_DEVICE; goto QueryStatusEnd; } RtlCopyMemory(BatteryStatus, &DevExt->State.BatteryStatus, sizeof(BATTERY_STATUS)); Status = STATUS_SUCCESS; QueryStatusEnd: WdfWaitLockRelease(DevExt->StateLock); DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ NTSTATUS SimBattSetStatusNotify ( PVOID Context, ULONG BatteryTag, PBATTERY_NOTIFY BatteryNotify ) /*++ Routine Description: Called by the class driver to set the capacity and power state levels at which the class driver requires notification. The battery class driver will serialize all requests it issues to the miniport for a given battery. Arguments: Context - Supplies the miniport context value for battery BatteryTag - Supplies the tag of current battery BatteryNotify - Supplies a pointer to a structure containing the notification critera. Return Value: Success if there is a battery currently installed, else no such device. --*/ { PSIMBATT_FDO_DATA DevExt; NTSTATUS Status; UNREFERENCED_PARAMETER(BatteryNotify); DebugEnter(); PAGED_CODE(); DevExt = (PSIMBATT_FDO_DATA)Context; WdfWaitLockAcquire(DevExt->StateLock, NULL); if (BatteryTag != DevExt->BatteryTag) { Status = STATUS_NO_SUCH_DEVICE; goto SetStatusNotifyEnd; } Status = STATUS_NOT_SUPPORTED; SetStatusNotifyEnd: WdfWaitLockRelease(DevExt->StateLock); DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ NTSTATUS SimBattQueryTag ( PVOID Context, PULONG BatteryTag ) /*++ Routine Description: This routine is called to get the value of the current battery tag. Arguments: Context - Supplies the miniport context value for battery BatteryTag - Supplies a pointer to a ULONG to receive the battery tag. Return Value: NTSTATUS --*/ { PSIMBATT_FDO_DATA DevExt; NTSTATUS Status; DebugEnter(); PAGED_CODE(); DevExt = (PSIMBATT_FDO_DATA)Context; WdfWaitLockAcquire(DevExt->StateLock, NULL); *BatteryTag = DevExt->BatteryTag; WdfWaitLockRelease(DevExt->StateLock); if (*BatteryTag == BATTERY_TAG_INVALID) { Status = STATUS_NO_SUCH_DEVICE; } else { Status = STATUS_SUCCESS; } DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ NTSTATUS SimBattDisableStatusNotify ( PVOID Context ) /*++ Routine Description: Called by the class driver to disable notification. The battery class driver will serialize all requests it issues to the miniport for a given battery. Arguments: Context - Supplies the miniport context value for battery Return Value: Success if there is a battery currently installed, else no such device. --*/ { NTSTATUS Status; UNREFERENCED_PARAMETER(Context); DebugEnter(); PAGED_CODE(); Status = STATUS_NOT_SUPPORTED; DebugExitStatus(Status); return Status; }
NTSTATUS DriverEntry ( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ) /*++ Routine Description: DriverEntry initializes the driver and is the first routine called by the system after the driver is loaded. DriverEntry configures and creates a WDF driver object. Parameters Description: DriverObject - Supplies a pointer to the driver object. RegistryPath - Supplies a pointer to a unicode string representing the path to the driver-specific key in the registry. Return Value: NTSTATUS. --*/ { WDF_OBJECT_ATTRIBUTES DriverAttributes; WDF_DRIVER_CONFIG DriverConfig; NTSTATUS Status; DebugEnter(); WDF_DRIVER_CONFIG_INIT(&DriverConfig, SimTcDriverDeviceAdd); // // Initialize attributes and a context area for the driver object. // WDF_OBJECT_ATTRIBUTES_INIT(&DriverAttributes); DriverAttributes.SynchronizationScope = WdfSynchronizationScopeNone; // // Create the driver object // Status = WdfDriverCreate(DriverObject, RegistryPath, &DriverAttributes, &DriverConfig, WDF_NO_HANDLE); if (!NT_SUCCESS(Status)) { DebugPrint(SIMTC_ERROR, "WdfDriverCreate() Failed. Status 0x%x\n", Status); goto DriverEntryEnd; } DriverEntryEnd: DebugExitStatus(Status); return Status; }
NTSTATUS SimTcDriverDeviceAdd ( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDriverDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. A WDF device object is created and initialized to represent a new instance of the battery device. Arguments: Driver - Supplies a handle to the WDF Driver object. DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { PFDO_DATA DevExt; WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE DeviceHandle; WDF_QUERY_INTERFACE_CONFIG QueryInterfaceConfig; NTSTATUS Status; THERMAL_DEVICE_INTERFACE ThermalDeviceInterface; UNREFERENCED_PARAMETER(Driver); DebugEnter(); PAGED_CODE(); // // Initialize attributes and a context area for the device object. // WDF_OBJECT_ATTRIBUTES_INIT(&DeviceAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&DeviceAttributes, FDO_DATA); // // Create a framework device object. This call will in turn create // a WDM device object, attach to the lower stack, and set the // appropriate flags and attributes. // Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &DeviceHandle); if (!NT_SUCCESS(Status)) { DebugPrint(SIMTC_ERROR, "WdfDeviceCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Create a driver interface for this device to advertise the thermal // cooling interface. // RtlZeroMemory(&ThermalDeviceInterface, sizeof(ThermalDeviceInterface)); ThermalDeviceInterface.Size = sizeof(ThermalDeviceInterface); ThermalDeviceInterface.Version = 1; ThermalDeviceInterface.Context = DeviceHandle; ThermalDeviceInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp; ThermalDeviceInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp; ThermalDeviceInterface.Flags = ThermalDeviceFlagPassiveCooling | ThermalDeviceFlagActiveCooling; ThermalDeviceInterface.ActiveCooling = SimTcEngageActiveCooling; ThermalDeviceInterface.PassiveCooling = SimTcEngagePassiveCooling; WDF_QUERY_INTERFACE_CONFIG_INIT(&QueryInterfaceConfig, (PINTERFACE) &ThermalDeviceInterface, &GUID_THERMAL_COOLING_INTERFACE, NULL); Status = WdfDeviceAddQueryInterface(DeviceHandle, &QueryInterfaceConfig); if (!NT_SUCCESS(Status)) { DebugPrint(SIMTC_ERROR, "WdfDeviceAddQueryInterface() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Finish initializing the device context area. // DevExt = GetDeviceExtension(DeviceHandle); DevExt->ThermalLevel = 100UL; DevExt->ActiveCoolingEngaged = FALSE; DriverDeviceAddEnd: DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ NTSTATUS SimBattSetInformation ( PVOID Context, ULONG BatteryTag, BATTERY_SET_INFORMATION_LEVEL Level, PVOID Buffer ) /* Routine Description: Called by the class driver to set the battery's charge/discharge state, critical bias, or charge current. Arguments: Context - Supplies the miniport context value for battery BatteryTag - Supplies the tag of current battery Level - Supplies action requested Buffer - Supplies a critical bias value if level is BatteryCriticalBias. Return Value: NTSTATUS --*/ { PBATTERY_CHARGING_SOURCE ChargingSource; PSIMBATT_FDO_DATA DevExt; NTSTATUS Status; DebugEnter(); PAGED_CODE(); DevExt = (PSIMBATT_FDO_DATA)Context; WdfWaitLockAcquire(DevExt->StateLock, NULL); if (BatteryTag != DevExt->BatteryTag) { Status = STATUS_NO_SUCH_DEVICE; goto SetInformationEnd; } if (Buffer == NULL) { Status = STATUS_INVALID_PARAMETER_4; } else if (Level == BatteryChargingSource) { ChargingSource = (PBATTERY_CHARGING_SOURCE)Buffer; DevExt->State.MaxCurrentDraw = ChargingSource->MaxCurrent; DebugPrint(SIMBATT_INFO, "SimBatt : Set MaxCurrentDraw = %u mA\n", DevExt->State.MaxCurrentDraw); Status = STATUS_SUCCESS; } else { Status = STATUS_NOT_SUPPORTED; } SetInformationEnd: WdfWaitLockRelease(DevExt->StateLock); DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ NTSTATUS SimBattQueryInformation ( PVOID Context, ULONG BatteryTag, BATTERY_QUERY_INFORMATION_LEVEL Level, LONG AtRate, PVOID Buffer, ULONG BufferLength, PULONG ReturnedLength ) /*++ Routine Description: Called by the class driver to retrieve battery information The battery class driver will serialize all requests it issues to the miniport for a given battery. Return invalid parameter when a request for a specific level of information can't be handled. This is defined in the battery class spec. Arguments: Context - Supplies the miniport context value for battery BatteryTag - Supplies the tag of current battery Level - Supplies the type of information required AtRate - Supplies the rate of drain for the BatteryEstimatedTime level Buffer - Supplies a pointer to a buffer to place the information BufferLength - Supplies the length in bytes of the buffer ReturnedLength - Supplies the length in bytes of the returned data Return Value: Success if there is a battery currently installed, else no such device. --*/ { PSIMBATT_FDO_DATA DevExt; ULONG ResultValue; PVOID ReturnBuffer; size_t ReturnBufferLength; NTSTATUS Status; UNREFERENCED_PARAMETER(AtRate); DebugEnter(); PAGED_CODE(); DevExt = (PSIMBATT_FDO_DATA)Context; WdfWaitLockAcquire(DevExt->StateLock, NULL); if (BatteryTag != DevExt->BatteryTag) { Status = STATUS_NO_SUCH_DEVICE; goto QueryInformationEnd; } // // Determine the value of the information being queried for and return it. // In a real battery, this would require hardware/firmware accesses. The // simulated battery fakes this by storing the data to be returned in // memory. // ReturnBuffer = NULL; ReturnBufferLength = 0; DebugPrint(SIMBATT_INFO, "Query for information level 0x%x\n", Level); Status = STATUS_INVALID_DEVICE_REQUEST; switch (Level) { case BatteryInformation: ReturnBuffer = &DevExt->State.BatteryInfo; ReturnBufferLength = sizeof(BATTERY_INFORMATION); Status = STATUS_SUCCESS; break; case BatteryEstimatedTime: if (DevExt->State.EstimatedTime == SIMBATT_RATE_CALCULATE) { if (AtRate == 0) { AtRate = DevExt->State.BatteryStatus.Rate; } if (AtRate < 0) { ResultValue = (3600 * DevExt->State.BatteryStatus.Capacity) / (-AtRate); } else { ResultValue = BATTERY_UNKNOWN_TIME; } } else { ResultValue = DevExt->State.EstimatedTime; } ReturnBuffer = &ResultValue; ReturnBufferLength = sizeof(ResultValue); Status = STATUS_SUCCESS; break; case BatteryUniqueID: ReturnBuffer = DevExt->State.UniqueId; Status = RtlStringCbLengthW(DevExt->State.UniqueId, sizeof(DevExt->State.UniqueId), &ReturnBufferLength); ReturnBufferLength += sizeof(WCHAR); break; case BatteryManufactureName: ReturnBuffer = DevExt->State.ManufacturerName; Status = RtlStringCbLengthW(DevExt->State.ManufacturerName, sizeof(DevExt->State.ManufacturerName), &ReturnBufferLength); ReturnBufferLength += sizeof(WCHAR); break; case BatteryDeviceName: ReturnBuffer = DevExt->State.DeviceName; Status = RtlStringCbLengthW(DevExt->State.DeviceName, sizeof(DevExt->State.DeviceName), &ReturnBufferLength); ReturnBufferLength += sizeof(WCHAR); break; case BatterySerialNumber: ReturnBuffer = DevExt->State.SerialNumber; Status = RtlStringCbLengthW(DevExt->State.SerialNumber, sizeof(DevExt->State.SerialNumber), &ReturnBufferLength); ReturnBufferLength += sizeof(WCHAR); break; case BatteryManufactureDate: if (DevExt->State.ManufactureDate.Day != 0) { ReturnBuffer = &DevExt->State.ManufactureDate; ReturnBufferLength = sizeof(BATTERY_MANUFACTURE_DATE); Status = STATUS_SUCCESS; } break; case BatteryGranularityInformation: if (DevExt->State.GranularityCount > 0) { ReturnBuffer = DevExt->State.GranularityScale; ReturnBufferLength = DevExt->State.GranularityCount * sizeof(BATTERY_REPORTING_SCALE); Status = STATUS_SUCCESS; } break; case BatteryTemperature: ReturnBuffer = &DevExt->State.Temperature; ReturnBufferLength = sizeof(ULONG); Status = STATUS_SUCCESS; break; default: Status = STATUS_INVALID_PARAMETER; break; } NT_ASSERT(((ReturnBufferLength == 0) && (ReturnBuffer == NULL)) || ((ReturnBufferLength > 0) && (ReturnBuffer != NULL))); if (NT_SUCCESS(Status)) { *ReturnedLength = (ULONG)ReturnBufferLength; if (ReturnBuffer != NULL) { if ((Buffer == NULL) || (BufferLength < ReturnBufferLength)) { Status = STATUS_BUFFER_TOO_SMALL; } else { memcpy(Buffer, ReturnBuffer, ReturnBufferLength); } } } else { *ReturnedLength = 0; } QueryInformationEnd: WdfWaitLockRelease(DevExt->StateLock); DebugExitStatus(Status); return Status; }
_Use_decl_annotations_ VOID SimBattPrepareHardware ( WDFDEVICE Device ) /*++ Routine Description: This routine is called to initialize battery data to sane values. A real battery would query hardware to determine if a battery is present, query its static capabilities, etc. Arguments: Device - Supplies the device to initialize. Return Value: NTSTATUS --*/ { PSIMBATT_FDO_DATA DevExt; WDF_OBJECT_ATTRIBUTES MemoryAttributes; WDFMEMORY MemoryObject; PSIMBATT_STATE RegState; NTSTATUS Status; DebugEnter(); PAGED_CODE(); DevExt = GetDeviceExtension(Device); // // Get this battery's state stored in the registry, otherwise use defaults. // RegState = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = Device; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SIMBATT_TAG, sizeof(SIMBATT_STATE), &MemoryObject, &((PVOID)(RegState))); if (!NT_SUCCESS(Status)) { goto SimBattPrepareHardwareEnd; } Status = GetSimBattStateFromRegistry(Device, RegState); if (!NT_SUCCESS(Status)) { RtlZeroMemory(RegState, sizeof(SIMBATT_STATE)); WdfWaitLockAcquire(DevExt->StateLock, NULL); SimBattUpdateTag(DevExt); DevExt->State.Version = RegState->Version; DevExt->State.BatteryStatus.PowerState = RegState->BatteryStatus.PowerState; DevExt->State.BatteryStatus.Capacity = RegState->BatteryStatus.Capacity; DevExt->State.BatteryStatus.Voltage = RegState->BatteryStatus.Voltage; DevExt->State.BatteryStatus.Rate = RegState->BatteryStatus.Rate; DevExt->State.BatteryInfo.Capabilities = RegState->BatteryInfo.Capabilities; DevExt->State.BatteryInfo.Technology = RegState->BatteryInfo.Technology; DevExt->State.BatteryInfo.Chemistry[0] = RegState->BatteryInfo.Chemistry[0]; DevExt->State.BatteryInfo.Chemistry[1] = RegState->BatteryInfo.Chemistry[1]; DevExt->State.BatteryInfo.Chemistry[2] = RegState->BatteryInfo.Chemistry[2]; DevExt->State.BatteryInfo.Chemistry[3] = RegState->BatteryInfo.Chemistry[3]; DevExt->State.BatteryInfo.DesignedCapacity = RegState->BatteryInfo.DesignedCapacity; DevExt->State.BatteryInfo.FullChargedCapacity = RegState->BatteryInfo.FullChargedCapacity; DevExt->State.BatteryInfo.DefaultAlert1 = RegState->BatteryInfo.DefaultAlert1; DevExt->State.BatteryInfo.DefaultAlert2 = RegState->BatteryInfo.DefaultAlert2; DevExt->State.BatteryInfo.CriticalBias = RegState->BatteryInfo.CriticalBias; DevExt->State.BatteryInfo.CycleCount = RegState->BatteryInfo.CycleCount; DevExt->State.MaxCurrentDraw = RegState->MaxCurrentDraw; SimBattSetBatteryString(RegState->DeviceName, DevExt->State.DeviceName); SimBattSetBatteryString(RegState->ManufacturerName, DevExt->State.ManufacturerName); SimBattSetBatteryString(RegState->SerialNumber, DevExt->State.SerialNumber); SimBattSetBatteryString(RegState->UniqueId, DevExt->State.UniqueId); WdfWaitLockRelease(DevExt->StateLock); } else { WdfWaitLockAcquire(DevExt->StateLock, NULL); SimBattUpdateTag(DevExt); DevExt->State.Version = SIMBATT_STATE_VERSION; DevExt->State.BatteryStatus.PowerState = BATTERY_POWER_ON_LINE; DevExt->State.BatteryStatus.Capacity = 100; DevExt->State.BatteryStatus.Voltage = BATTERY_UNKNOWN_VOLTAGE; DevExt->State.BatteryStatus.Rate = 0; DevExt->State.BatteryInfo.Capabilities = BATTERY_SYSTEM_BATTERY | BATTERY_CAPACITY_RELATIVE; DevExt->State.BatteryInfo.Technology = 1; DevExt->State.BatteryInfo.Chemistry[0] = 'F'; DevExt->State.BatteryInfo.Chemistry[1] = 'a'; DevExt->State.BatteryInfo.Chemistry[2] = 'k'; DevExt->State.BatteryInfo.Chemistry[3] = 'e'; DevExt->State.BatteryInfo.DesignedCapacity = 100; DevExt->State.BatteryInfo.FullChargedCapacity = 100; DevExt->State.BatteryInfo.DefaultAlert1 = 0; DevExt->State.BatteryInfo.DefaultAlert2 = 0; DevExt->State.BatteryInfo.CriticalBias = 0; DevExt->State.BatteryInfo.CycleCount = 100; DevExt->State.MaxCurrentDraw = UNKNOWN_CURRENT; SimBattSetBatteryString(DEFAULT_NAME, DevExt->State.DeviceName); SimBattSetBatteryString(DEFAULT_MANUFACTURER, DevExt->State.ManufacturerName); SimBattSetBatteryString(DEFAULT_SERIALNO, DevExt->State.SerialNumber); SimBattSetBatteryString(DEFAULT_UNIQUEID, DevExt->State.UniqueId); WdfWaitLockRelease(DevExt->StateLock); // // Save new defaults to registry. // Normally this only happens the first time the device starts after // install because the key should exist after that point. // SaveSimBattStateToRegistry(Device, &DevExt->State); } if (RegState != NULL) { WdfObjectDelete(MemoryObject); } SimBattPrepareHardwareEnd: DebugExitStatus(Status); return; }
NTSTATUS SimSensorScanPendingQueue ( _In_ WDFDEVICE Device ) /*++ Routine Description: This routine scans the device's pending queue for retirable requests. N.B. This routine requires the QueueLock be held. Arguments: Device - Supplies a handle to the device. --*/ { WDFREQUEST CurrentRequest; PFDO_DATA DevExt; WDFREQUEST LastRequest; ULONG LowerBound; NTSTATUS Status; ULONG Temperature; ULONG UpperBound; DebugEnter(); PAGED_CODE(); DevExt = GetDeviceExtension(Device); Status = STATUS_SUCCESS; LastRequest = NULL; CurrentRequest = NULL; Temperature = SimSensorReadVirtualTemperature(Device); // // Prime the walk by finding the first request present. If there are no // requests, bail out immediately. // LowerBound = 0; UpperBound = (ULONG)-1; Status = WdfIoQueueFindRequest(DevExt->PendingRequestQueue, NULL, NULL, NULL, &CurrentRequest); // // Due to a technical limitation in SDV analysis engine, the following // analysis assume has to be inserted to supress a false defect for // the wdfioqueueretrievefoundrequest rule. // _Analysis_assume_(Status == STATUS_NOT_FOUND); while (NT_SUCCESS(Status)) { // // Walk past the current request. By walking past the current request // before checking it, the walk doesn't have to restart every time a // request is satisfied and removed form the queue. // LastRequest = CurrentRequest; Status = WdfIoQueueFindRequest(DevExt->PendingRequestQueue, LastRequest, NULL, NULL, &CurrentRequest); // // Process the last request. // SimSensorCheckQueuedRequest(Device, Temperature, &LowerBound, &UpperBound, LastRequest); WdfObjectDereference(LastRequest); if(Status == STATUS_NOT_FOUND) { // // LastRequest unexpectedly disappeared from the queue. Start over. // LowerBound = 0; UpperBound = (ULONG)-1; Status = WdfIoQueueFindRequest(DevExt->PendingRequestQueue, NULL, NULL, NULL, &CurrentRequest); } } // // Update the thresholds based on the latest contents of the queue. // SimSensorSetVirtualInterruptThresholds(Device, LowerBound, UpperBound); DebugExitStatus(Status); return Status; }
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); }
NTSTATUS SimSensorDriverDeviceAdd ( WDFDRIVER Driver, PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDriverDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. A WDF device object is created and initialized to represent a new instance of the battery device. Arguments: Driver - Supplies a handle to the WDF Driver object. DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { WDF_OBJECT_ATTRIBUTES DeviceAttributes; WDFDEVICE DeviceHandle; PFDO_DATA DevExt; BOOLEAN LockHeld; WDF_IO_QUEUE_CONFIG PendingRequestQueueConfig; WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerCallbacks; WDFQUEUE Queue; WDF_IO_QUEUE_CONFIG QueueConfig; NTSTATUS Status; WDF_OBJECT_ATTRIBUTES WorkitemAttributes; WDF_WORKITEM_CONFIG WorkitemConfig; UNREFERENCED_PARAMETER(Driver); DebugEnter(); PAGED_CODE(); LockHeld = FALSE; // // Initialize attributes and a context area for the device object. // WDF_OBJECT_ATTRIBUTES_INIT(&DeviceAttributes); WDF_OBJECT_ATTRIBUTES_SET_CONTEXT_TYPE(&DeviceAttributes, FDO_DATA); // // Initailize power callbacks // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&PnpPowerCallbacks); PnpPowerCallbacks.EvtDeviceD0Entry = SimSensorDeviceD0Entry; PnpPowerCallbacks.EvtDeviceD0Exit = SimSensorDeviceD0Exit; PnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = SimSensorSelfManagedIoSuspend; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &PnpPowerCallbacks); // // Create a framework device object. This call will in turn create // a WDM device object, attach to the lower stack, and set the // appropriate flags and attributes. // Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &DeviceHandle); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfDeviceCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } DevExt = GetDeviceExtension(DeviceHandle); // // Configure a default queue for IO requests. This queue processes requests // to read the sensor state. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig, WdfIoQueueDispatchParallel); QueueConfig.EvtIoDeviceControl = SimSensorIoDeviceControl; // // The system uses IoInternalDeviceControl requests to communicate with the // ACPI driver on the device stack. For proper operation of thermal zones, // these requests must be forwarded unless the driver knows how to handle // them. // QueueConfig.EvtIoInternalDeviceControl = SimSensorIoInternalDeviceControl; Status = WdfIoQueueCreate(DeviceHandle, &QueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &Queue); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfIoQueueCreate() (Default) Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Configure a manual dispatch queue for pending requests. This queue // stores requests to read the sensor state which can't be retired // immediately. // WDF_IO_QUEUE_CONFIG_INIT(&PendingRequestQueueConfig, WdfIoQueueDispatchManual); Status = WdfIoQueueCreate(DeviceHandle, &PendingRequestQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &DevExt->PendingRequestQueue); PendingRequestQueueConfig.EvtIoStop = SimSensorQueueIoStop; if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfIoQueueCreate() (Pending) Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Configure a workitem to process the simulated interrupt. // WDF_OBJECT_ATTRIBUTES_INIT(&WorkitemAttributes); WorkitemAttributes.ParentObject = DeviceHandle; WDF_WORKITEM_CONFIG_INIT(&WorkitemConfig, SimSensorTemperatureInterruptWorker); Status = WdfWorkItemCreate(&WorkitemConfig, &WorkitemAttributes, &DevExt->InterruptWorker); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWorkItemCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Create the request queue waitlock. // Status = WdfWaitLockCreate(NULL, &DevExt->QueueLock); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWaitLockCreate() Failed. Status 0x%x\n", Status); goto DriverDeviceAddEnd; } // // Initilize the simulated sensor hardware. // DevExt->Sensor.LowerBound = 0; DevExt->Sensor.UpperBound = (ULONG)-1; DevExt->Sensor.Temperature = VIRTUAL_SENSOR_RESET_TEMPERATURE; Status = WdfWaitLockCreate(NULL, &DevExt->Sensor.Lock); if (!NT_SUCCESS(Status)) { DebugPrint(SIMSENSOR_ERROR, "WdfWaitLockCreate() Failed. 0x%x\n", Status); goto DriverDeviceAddEnd; } DriverDeviceAddEnd: DebugExitStatus(Status); return Status; }