_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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #10
0
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;
}
Example #11
0
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);
}
Example #12
0
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;
}