NTSTATUS NTAPI CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, OUT PULONG Tag) { PDEVICE_OBJECT PdoDevice; ULONG StaData; ULONG NewTag; NTSTATUS Status; PAGED_CODE(); if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n", *Tag, DeviceExtension, DeviceExtension->DeviceId); /* Get PDO and clear notification flag */ PdoDevice = DeviceExtension->PdoDeviceObject; DeviceExtension->NotifySent = 0; /* Get _STA from PDO (we need the machine status, not the battery status) */ Status = CmBattGetStaData(PdoDevice, &StaData); if (NT_SUCCESS(Status)) { /* Is a battery present? */ if (StaData & ACPI_STA_BATTERY_PRESENT) { /* Do we not have a tag yet? */ if (!DeviceExtension->Tag) { /* Set the new tag value, reset tags if we reached the maximum */ NewTag = DeviceExtension->TagData; if (DeviceExtension->TagData++ == 0xFFFFFFFF) NewTag = 1; DeviceExtension->Tag = NewTag; if (CmBattDebug & CMBATT_GENERIC_INFO) DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension->Tag); /* Reset trip point data */ DeviceExtension->TripPointOld = 0; DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; /* Clear AR lock and set new interrupt time */ InterlockedExchange(&DeviceExtension->ArLockValue, 0); DeviceExtension->InterruptTime = KeQueryInterruptTime(); } } else { /* No battery, so no tag */ DeviceExtension->Tag = 0; Status = STATUS_NO_SUCH_DEVICE; } } /* Return the tag and status result */ *Tag = DeviceExtension->Tag; if (CmBattDebug & CMBATT_ACPI_WARNING) DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag, Status); return Status; }
//============================================================================= STDMETHODIMP CMiniportWaveCyclicStream::GetPosition( OUT PULONG Position ) /*++ Routine Description: The GetPosition function gets the current position of the DMA read or write pointer for the stream. Callers of GetPosition should run at IRQL <= DISPATCH_LEVEL. Arguments: Position - Position of the DMA pointer Return Value: NT status code. --*/ { if (m_fDmaActive) { // Get the current time ULONGLONG CurrentTime = KeQueryInterruptTime(); // Calculate the time elapsed since the last call to GetPosition() or since the // DMA engine started. Note that the division by 10000 to convert to milliseconds // may cause us to lose some of the time, so we will carry the remainder forward // to the next GetPosition() call. ULONG TimeElapsedInMS = ((ULONG) (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward)) / 10000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ullElapsedTimeCarryForward = (CurrentTime - m_ullDmaTimeStamp + m_ullElapsedTimeCarryForward) % 10000; // Calculate how many bytes in the DMA buffer would have been processed in the elapsed // time. Note that the division by 1000 to convert to milliseconds may cause us to // lose some bytes, so we will carry the remainder forward to the next GetPosition() call. ULONG ByteDisplacement = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) / 1000; // Carry forward the remainder of this division so we don't fall behind with our position. m_ulByteDisplacementCarryForward = ((m_ulDmaMovementRate * TimeElapsedInMS) + m_ulByteDisplacementCarryForward) % 1000; // Increment the DMA position by the number of bytes displaced since the last // call to GetPosition() and ensure we properly wrap at buffer length. m_ulDmaPosition = (m_ulDmaPosition + ByteDisplacement) % m_ulDmaBufferSize; // Return the new DMA position *Position = m_ulDmaPosition; // Update the DMA time stamp for the next call to GetPosition() m_ullDmaTimeStamp = CurrentTime; } else { // DMA is inactive so just return the current DMA position. *Position = m_ulDmaPosition; } return STATUS_SUCCESS; } // GetPosition
BOOLEAN FASTCALL KiInsertTimerTable(IN PKTIMER Timer, IN ULONG Hand) { LARGE_INTEGER InterruptTime; LONGLONG DueTime = Timer->DueTime.QuadPart; BOOLEAN Expired = FALSE; PLIST_ENTRY ListHead, NextEntry; PKTIMER CurrentTimer; DPRINT("KiInsertTimerTable(): Timer %p, Hand: %lu\n", Timer, Hand); /* Check if the period is zero */ if (!Timer->Period) Timer->Header.SignalState = FALSE; /* Sanity check */ ASSERT(Hand == KiComputeTimerTableIndex(DueTime)); /* Loop the timer list backwards */ ListHead = &KiTimerTableListHead[Hand].Entry; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the timer */ CurrentTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); /* Now check if we can fit it before */ if ((ULONGLONG)DueTime >= CurrentTimer->DueTime.QuadPart) break; /* Keep looping */ NextEntry = NextEntry->Blink; } /* Looped all the list, insert it here and get the interrupt time again */ InsertHeadList(NextEntry, &Timer->TimerListEntry); /* Check if we didn't find it in the list */ if (NextEntry == ListHead) { /* Set the time */ KiTimerTableListHead[Hand].Time.QuadPart = DueTime; /* Make sure it hasn't expired already */ InterruptTime.QuadPart = KeQueryInterruptTime(); if (DueTime <= InterruptTime.QuadPart) Expired = TRUE; } /* Return expired state */ return Expired; }
/*----------------------------------------------------------------------------*/ int zrtp_add_system_state(zrtp_global_t* zrtp, MD_CTX *ctx) { LARGE_INTEGER li1; LARGE_INTEGER li2; ULONG ul1; ULONG ul2; ULONGLONG ull; PKTHREAD thread; static int tsc_ok = 1; /* * WARNING! * Of course it's not a real size of entropy added to the context. It's very * difficult to compute the size of real random data and estimate its quality. * This value means: size of maximum possible random data which this function can provide. */ static int entropy_length = sizeof(LARGE_INTEGER)*2 + sizeof(PKTHREAD) + sizeof(ULONG)*2 + sizeof(LARGE_INTEGER)*2 + sizeof(ULONG)*2; li2 = KeQueryPerformanceCounter(&li1); MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); MD_Update(ctx, &li2, sizeof(LARGE_INTEGER)); ull = KeQueryInterruptTime(); MD_Update(ctx, &ull, sizeof(ULONGLONG)); thread = KeGetCurrentThread(); MD_Update(ctx, &thread, sizeof(PKTHREAD)); ul2 = KeQueryRuntimeThread(thread, &ul1); MD_Update(ctx, &ul1, sizeof(ULONG)); MD_Update(ctx, &ul2, sizeof(ULONG)); KeQuerySystemTime(&li1); MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); KeQueryTickCount(&li1); MD_Update(ctx, &li1, sizeof(LARGE_INTEGER)); if (tsc_ok) { __try { ull = _RDTSC(); MD_Update(ctx, &ull, sizeof(ULONGLONG)); } __except(EXCEPTION_EXECUTE_HANDLER) { tsc_ok = 0; } } return entropy_length; }
/** * Get current NT interrupt time. * @return NT interrupt time */ static uint64_t rtTimerNtQueryInterruptTime(void) { # ifdef RT_ARCH_AMD64 return KeQueryInterruptTime(); /* macro */ # else if (g_pfnrtKeQueryInterruptTime) return g_pfnrtKeQueryInterruptTime(); /* NT4 */ ULARGE_INTEGER InterruptTime; do { InterruptTime.HighPart = ((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.High1Time; InterruptTime.LowPart = ((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.LowPart; } while (((KUSER_SHARED_DATA volatile *)SharedUserData)->InterruptTime.High2Time != InterruptTime.HighPart); return InterruptTime.QuadPart; # endif }
void rnd_reseed_now() { seed_data seed; KeQuerySystemTime(&seed.seed20); seed.seed1 = PsGetCurrentProcess(); seed.seed2 = PsGetCurrentProcessId(); seed.seed3 = KeGetCurrentThread(); seed.seed4 = PsGetCurrentThreadId(); seed.seed5 = KeGetCurrentProcessorNumber(); seed.seed6 = KeQueryInterruptTime(); seed.seed10 = KeQueryPerformanceCounter(NULL); seed.seed11 = __rdtsc(); seed.seed12 = ExGetPreviousMode(); seed.seed14 = IoGetTopLevelIrp(); seed.seed15 = MmQuerySystemSize(); seed.seed24 = KeGetCurrentIrql(); if (KeGetCurrentIrql() == PASSIVE_LEVEL) { seed.seed7 = KeQueryPriorityThread(seed.seed3); seed.seed17 = ExUuidCreate(&seed.seed18); seed.seed19 = RtlRandom(&seed.seed8); } if (KeGetCurrentIrql() <= APC_LEVEL) { seed.seed13 = IoGetInitialStack(); seed.seed16 = PsGetProcessExitTime(); IoGetStackLimits(&seed.seed22, &seed.seed23); } KeQueryTickCount(&seed.seed21); rnd_add_buff(&seed, sizeof(seed)); /* Prevent leaks */ zeroauto(&seed, sizeof(seed)); }
VOID NTAPI KiTimerExpiration(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2) { ULARGE_INTEGER SystemTime, InterruptTime; LARGE_INTEGER Interval; LONG Limit, Index, i; ULONG Timers, ActiveTimers, DpcCalls; PLIST_ENTRY ListHead, NextEntry; KIRQL OldIrql; PKTIMER Timer; PKDPC TimerDpc; ULONG Period; DPC_QUEUE_ENTRY DpcEntry[MAX_TIMER_DPCS]; PKSPIN_LOCK_QUEUE LockQueue; #ifdef CONFIG_SMP PKPRCB Prcb = KeGetCurrentPrcb(); #endif /* Disable interrupts */ _disable(); /* Query system and interrupt time */ KeQuerySystemTime((PLARGE_INTEGER)&SystemTime); InterruptTime.QuadPart = KeQueryInterruptTime(); Limit = KeTickCount.LowPart; /* Bring interrupts back */ _enable(); /* Get the index of the timer and normalize it */ Index = PtrToLong(SystemArgument1); if ((Limit - Index) >= TIMER_TABLE_SIZE) { /* Normalize it */ Limit = Index + TIMER_TABLE_SIZE - 1; } /* Setup index and actual limit */ Index--; Limit &= (TIMER_TABLE_SIZE - 1); /* Setup accounting data */ DpcCalls = 0; Timers = 24; ActiveTimers = 4; /* Lock the Database and Raise IRQL */ OldIrql = KiAcquireDispatcherLock(); /* Start expiration loop */ do { /* Get the current index */ Index = (Index + 1) & (TIMER_TABLE_SIZE - 1); /* Get list pointers and loop the list */ ListHead = &KiTimerTableListHead[Index].Entry; while (ListHead != ListHead->Flink) { /* Lock the timer and go to the next entry */ LockQueue = KiAcquireTimerLock(Index); NextEntry = ListHead->Flink; /* Get the current timer and check its due time */ Timers--; Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); if ((NextEntry != ListHead) && (Timer->DueTime.QuadPart <= InterruptTime.QuadPart)) { /* It's expired, remove it */ ActiveTimers--; KiRemoveEntryTimer(Timer); /* Make it non-inserted, unlock it, and signal it */ Timer->Header.Inserted = FALSE; KiReleaseTimerLock(LockQueue); Timer->Header.SignalState = 1; /* Get the DPC and period */ TimerDpc = Timer->Dpc; Period = Timer->Period; /* Check if there's any waiters */ if (!IsListEmpty(&Timer->Header.WaitListHead)) { /* Check the type of event */ if (Timer->Header.Type == TimerNotificationObject) { /* Unwait the thread */ KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT); } else { /* Otherwise unwait the thread and signal the timer */ KxUnwaitThreadForEvent((PKEVENT)Timer, IO_NO_INCREMENT); } } /* Check if we have a period */ if (Period) { /* Calculate the interval and insert the timer */ Interval.QuadPart = Int32x32To64(Period, -10000); while (!KiInsertTreeTimer(Timer, Interval)); } /* Check if we have a DPC */ if (TimerDpc) { #ifdef CONFIG_SMP /* * If the DPC is targeted to another processor, * then insert it into that processor's DPC queue * instead of delivering it now. * If the DPC is a threaded DPC, and the current CPU * has threaded DPCs enabled (KiExecuteDpc is actively parsing DPCs), * then also insert it into the DPC queue for threaded delivery, * instead of doing it here. */ if (((TimerDpc->Number >= MAXIMUM_PROCESSORS) && ((TimerDpc->Number - MAXIMUM_PROCESSORS) != Prcb->Number)) || ((TimerDpc->Type == ThreadedDpcObject) && (Prcb->ThreadDpcEnable))) { /* Queue it */ KeInsertQueueDpc(TimerDpc, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } else #endif { /* Setup the DPC Entry */ DpcEntry[DpcCalls].Dpc = TimerDpc; DpcEntry[DpcCalls].Routine = TimerDpc->DeferredRoutine; DpcEntry[DpcCalls].Context = TimerDpc->DeferredContext; DpcCalls++; ASSERT(DpcCalls < MAX_TIMER_DPCS); } } /* Check if we're done processing */ if (!(ActiveTimers) || !(Timers)) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Reset accounting */ Timers = 24; ActiveTimers = 4; /* Lock the dispatcher database */ KiAcquireDispatcherLock(); } } else { /* Check if the timer list is empty */ if (NextEntry != ListHead) { /* Sanity check */ ASSERT(KiTimerTableListHead[Index].Time.QuadPart <= Timer->DueTime.QuadPart); /* Update the time */ _disable(); KiTimerTableListHead[Index].Time.QuadPart = Timer->DueTime.QuadPart; _enable(); } /* Release the lock */ KiReleaseTimerLock(LockQueue); /* Check if we've scanned all the timers we could */ if (!Timers) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Reset accounting */ Timers = 24; ActiveTimers = 4; /* Lock the dispatcher database */ KiAcquireDispatcherLock(); } /* Done looping */ break; } } } while (Index != Limit); /* Verify the timer table, on debug builds */ if (KeNumberProcessors == 1) KiCheckTimerTable(InterruptTime); /* Check if we still have DPC entries */ if (DpcCalls) { /* Release the dispatcher while doing DPCs */ KiReleaseDispatcherLock(DISPATCH_LEVEL); /* Start looping all DPC Entries */ for (i = 0; DpcCalls; DpcCalls--, i++) { /* Call the DPC */ DpcEntry[i].Routine(DpcEntry[i].Dpc, DpcEntry[i].Context, UlongToPtr(SystemTime.LowPart), UlongToPtr(SystemTime.HighPart)); } /* Lower IRQL if we need to */ if (OldIrql != DISPATCH_LEVEL) KeLowerIrql(OldIrql); } else { /* Unlock the dispatcher */ KiReleaseDispatcherLock(OldIrql); } }
VOID ExGetNextWakeTime ( OUT PULONGLONG DueTime, OUT PTIME_FIELDS TimeFields, OUT PVOID *TimerObject ) { PLIST_ENTRY Link; PETIMER ExTimer; PETIMER BestTimer; KIRQL OldIrql; ULONGLONG TimerDueTime; ULONGLONG BestDueTime; ULONGLONG InterruptTime; LARGE_INTEGER SystemTime; LARGE_INTEGER CmosTime; ExAcquireSpinLock(&ExpWakeTimerListLock, &OldIrql); BestDueTime = 0; BestTimer = NULL; Link = ExpWakeTimerList.Flink; while (Link != &ExpWakeTimerList) { ExTimer = CONTAINING_RECORD(Link, ETIMER, WakeTimerListEntry); Link = Link->Flink; if (ExTimer->WakeTimer) { TimerDueTime = KeQueryTimerDueTime(&ExTimer->KeTimer); TimerDueTime = 0 - TimerDueTime; // // Is this timers due time closer? // if (TimerDueTime > BestDueTime) { BestDueTime = TimerDueTime; BestTimer = ExTimer; } } else { // // Timer is not an active wake timer, remove it // RemoveEntryList(&ExTimer->WakeTimerListEntry); ExTimer->WakeTimerListEntry.Flink = NULL; } } ExReleaseSpinLock(&ExpWakeTimerListLock, OldIrql); if (BestDueTime) { // // Convert time to timefields // KeQuerySystemTime (&SystemTime); InterruptTime = KeQueryInterruptTime (); BestDueTime = 0 - BestDueTime; SystemTime.QuadPart += BestDueTime - InterruptTime; // // Many system alarms are only good to 1 second resolution. // Add one sceond to the target time so that the timer is really // elasped if this is the wake event. // SystemTime.QuadPart += 10000000; ExSystemTimeToLocalTime(&SystemTime,&CmosTime); RtlTimeToTimeFields(&CmosTime, TimeFields); } *DueTime = BestDueTime; *TimerObject = BestTimer; }
VOID KiCalibrateTimeAdjustment ( PADJUST_INTERRUPT_TIME_CONTEXT Adjust ) /*++ Routine Description: This function calibrates the adjustment of time on all processors. Arguments: Adjust - Supplies the operation context. Return Value: None. --*/ { ULONG cl; ULONG divisor; BOOLEAN Enable; LARGE_INTEGER InterruptTime; ULARGE_INTEGER li; PERFINFO_PO_CALIBRATED_PERFCOUNTER LogEntry; LARGE_INTEGER NewTickCount; ULONG NewTickOffset; LARGE_INTEGER PerfCount; LARGE_INTEGER PerfFreq; LARGE_INTEGER SetTime; // // As each processor arrives, decrement the remaining processor count. If // this is the last processor to arrive, then compute the time change, and // signal all processor when to apply the performance counter change. // if (InterlockedDecrement((PLONG)&Adjust->KiNumber)) { Enable = KeDisableInterrupts(); // // It is possible to deadlock if one or more of the other processors // receives and processes a freeze request while this processor has // interrupts disabled. Poll for a freeze request until all processors // are known to be in this code. // do { KiPollFreezeExecution(); } while (Adjust->KiNumber != (ULONG)-1); // // Wait to perform the time set. // while (Adjust->Barrier); } else { // // Set timer expiration dpc to scan the timer queues once for any // expired timers. // KeRemoveQueueDpc(&KiTimerExpireDpc); KeInsertQueueDpc(&KiTimerExpireDpc, ULongToPtr(KiQueryLowTickCount() - TIMER_TABLE_SIZE), NULL); // // Disable interrupts and indicate that this processor is now // in final portion of this code. // Enable = KeDisableInterrupts(); InterlockedDecrement((PLONG) &Adjust->KiNumber); // // Adjust Interrupt Time. // InterruptTime.QuadPart = KeQueryInterruptTime() + Adjust->Adjustment; SetTime.QuadPart = Adjust->Adjustment; // // Get the current times // PerfCount = KeQueryPerformanceCounter(&PerfFreq); // // Compute performance counter for current time. // // Multiply SetTime * PerfCount and obtain 96-bit result in cl, // li.LowPart, li.HighPart. Then divide the 96-bit result by // 10,000,000 to get new performance counter value. // li.QuadPart = RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.LowPart).QuadPart; cl = li.LowPart; li.QuadPart = li.HighPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.LowPart, (ULONG)PerfFreq.HighPart).QuadPart; li.QuadPart = li.QuadPart + RtlEnlargedUnsignedMultiply((ULONG)SetTime.HighPart, (ULONG)PerfFreq.LowPart).QuadPart; li.HighPart = li.HighPart + SetTime.HighPart * PerfFreq.HighPart; divisor = 10000000; Adjust->NewCount.HighPart = RtlEnlargedUnsignedDivide(li, divisor, &li.HighPart); li.LowPart = cl; Adjust->NewCount.LowPart = RtlEnlargedUnsignedDivide(li, divisor, NULL); Adjust->NewCount.QuadPart += PerfCount.QuadPart; // // Compute tick count and tick offset for current interrupt time. // NewTickCount = RtlExtendedLargeIntegerDivide(InterruptTime, KeMaximumIncrement, &NewTickOffset); // // Apply changes to interrupt time, tick count, tick offset, and the // performance counter. // KiTickOffset = KeMaximumIncrement - NewTickOffset; KeInterruptTimeBias += Adjust->Adjustment; SharedUserData->TickCount.High2Time = NewTickCount.HighPart; #if defined(_WIN64) SharedUserData->TickCountQuad = NewTickCount.QuadPart; #else SharedUserData->TickCount.LowPart = NewTickCount.LowPart; SharedUserData->TickCount.High1Time = NewTickCount.HighPart; #endif // // N.B. There is no global tick count variable on AMD64. // #if defined(_X86_) KeTickCount.High2Time = NewTickCount.HighPart; KeTickCount.LowPart = NewTickCount.LowPart; KeTickCount.High1Time = NewTickCount.HighPart; #endif #if defined(_AMD64_) SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; *((volatile ULONG64 *)&SharedUserData->InterruptTime) = InterruptTime.QuadPart; #else SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart; SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart; SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart; #endif // // Apply the performance counter change. // Adjust->Barrier = 0; } KeGetCurrentPrcb()->TickOffset = KiTickOffset; #if defined(_AMD64_) KeGetCurrentPrcb()->MasterOffset = KiTickOffset; #endif HalCalibratePerformanceCounter((LONG volatile *)&Adjust->HalNumber, (ULONGLONG)Adjust->NewCount.QuadPart); // // Log an event that the performance counter has been calibrated // properly and indicate the new performance counter value. // if (PERFINFO_IS_GROUP_ON(PERF_POWER)) { LogEntry.PerformanceCounter = KeQueryPerformanceCounter(NULL); PerfInfoLogBytes(PERFINFO_LOG_TYPE_PO_CALIBRATED_PERFCOUNTER, &LogEntry, sizeof(LogEntry)); } KeEnableInterrupts(Enable); return; }
NTSTATUS NTAPI CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension, IN ULONG Tag, IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel, IN OPTIONAL LONG AtRate, IN PVOID Buffer, IN ULONG BufferLength, OUT PULONG ReturnedLength) { NTSTATUS Status; PVOID QueryData = NULL; ULONG QueryLength = 0; ULONG RemainingTime = 0; ANSI_STRING TempString; UNICODE_STRING TempString2; WCHAR InfoBuffer[256]; WCHAR TempBuffer[256]; UNICODE_STRING InfoString; ULONG RemainingCapacity; BATTERY_REPORTING_SCALE BatteryReportingScale[2]; LONG Rate; PAGED_CODE(); if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n", Tag, FdoExtension->DeviceId, InfoLevel); /* Check ACPI Data */ Status = CmBattVerifyStaticInfo(FdoExtension, Tag); if (!NT_SUCCESS(Status)) return Status; /* Check what caller wants */ switch (InfoLevel) { case BatteryInformation: /* Just return our static information */ QueryData = &FdoExtension->BatteryInformation; QueryLength = sizeof(BATTERY_INFORMATION); break; case BatteryGranularityInformation: /* Return our static information, we have two scales */ BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1; BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1; BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2; BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity; QueryData = BatteryReportingScale; QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2; break; case BatteryEstimatedTime: /* Check if it's been more than 2 1/2 minutes since the last change */ if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime)) { /* Get new battery status */ CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag); /* If the caller didn't specify a rate, use our static one */ Rate = AtRate; if (!Rate) Rate = FdoExtension->Rate; /* If we don't have a valid negative rate, use unknown value */ if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE; /* Grab the remaining capacity */ RemainingCapacity = FdoExtension->RemainingCapacity; /* See if we don't know one or the other */ if ((Rate == BATTERY_UNKNOWN_RATE) || (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)) { /* If the battery is discharging, we can't give out a time */ if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) && (CmBattDebug & CMBATT_GENERIC_WARNING)) DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n"); /* Check if we don't have a rate and capacity is going down */ if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) && (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG)) { /* We have to fail, since we lack data */ Status = STATUS_INVALID_DEVICE_REQUEST; if (CmBattDebug & CMBATT_GENERIC_WARNING) DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n"); } /* If we don't have capacity, the rate is useless */ if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY) { /* We have to fail the request */ Status = STATUS_INVALID_DEVICE_REQUEST; if (CmBattDebug & CMBATT_GENERIC_WARNING) DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n"); } } else { /* We have data, but is it valid? */ if (RemainingCapacity > 0x123456) { /* The capacity seems bogus, so don't use it */ if (CmBattDebug & CMBATT_ACPI_WARNING) DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n"); } else { /* Compute the remaining time in seconds, based on rate */ RemainingTime = (RemainingCapacity * 3600) / -Rate; } } } /* Return the remaining time */ QueryData = &RemainingTime; QueryLength = sizeof(ULONG); break; case BatteryDeviceName: /* Build the model number string */ RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); /* Convert it to Unicode */ InfoString.Buffer = InfoBuffer; InfoString.MaximumLength = sizeof(InfoBuffer); Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); /* Return the unicode buffer */ QueryData = InfoString.Buffer; QueryLength = InfoString.Length; break; case BatteryTemperature: case BatteryManufactureDate: /* We don't support these */ Status = STATUS_INVALID_DEVICE_REQUEST; break; case BatteryManufactureName: /* Build the OEM info string */ RtlInitAnsiString(&TempString, FdoExtension->OemInfo); /* Convert it to Unicode */ InfoString.Buffer = InfoBuffer; InfoString.MaximumLength = sizeof(InfoBuffer); Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); /* Return the unicode buffer */ QueryData = InfoString.Buffer; QueryLength = InfoString.Length; break; case BatteryUniqueID: /* Build the serial number string */ RtlInitAnsiString(&TempString, FdoExtension->SerialNumber); /* Convert it to Unicode */ InfoString.Buffer = InfoBuffer; InfoString.MaximumLength = sizeof(InfoBuffer); RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); /* Setup a temporary string for concatenation */ TempString2.Buffer = TempBuffer; TempString2.MaximumLength = sizeof(TempBuffer); /* Check if there's an OEM string */ if (FdoExtension->OemInfo[0]) { /* Build the OEM info string */ RtlInitAnsiString(&TempString, FdoExtension->OemInfo); /* Convert it to Unicode and append it */ RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); RtlAppendUnicodeStringToString(&InfoString, &TempString2); } /* Build the model number string */ RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); /* Convert it to Unicode and append it */ RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); RtlAppendUnicodeStringToString(&InfoString, &TempString2); /* Return the final appended string */ QueryData = InfoString.Buffer; QueryLength = InfoString.Length; break; default: /* Everything else is unknown */ Status = STATUS_INVALID_PARAMETER; break; } /* Return the required length and check if the caller supplied enough */ *ReturnedLength = QueryLength; if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL; /* Copy the data if there's enough space and it exists */ if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength); /* Return function result */ return Status; }
NTSTATUS NTAPI CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, IN ULONG Tag) { ULONG PsrData = 0; NTSTATUS Status; ULONG BstState; ULONG DesignVoltage, PresentRate, RemainingCapacity; PAGED_CODE(); if (CmBattDebug & CMBATT_GENERIC_INFO) DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag); /* Validate ACPI data */ Status = CmBattVerifyStaticInfo(DeviceExtension, Tag); if (!NT_SUCCESS(Status)) return Status; /* Check for delayed status notifications */ if (DeviceExtension->DelayNotification) { /* Process them now and don't do any other work */ CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); return Status; } /* Get _BST from ACPI */ Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData); if (!NT_SUCCESS(Status)) { /* Fail */ InterlockedExchange(&DeviceExtension->ArLockValue, 0); return Status; } /* Clear current BST information */ DeviceExtension->State = 0; DeviceExtension->RemainingCapacity = 0; DeviceExtension->PresentVoltage = 0; DeviceExtension->Rate = 0; /* Get battery state */ BstState = DeviceExtension->BstData.State; /* Is the battery both charging and discharging? */ if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) && (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) DbgPrint("************************ ACPI BIOS BUG ********************\n* " "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n" "* One battery cannot be charging and discharging at the same time.\n", BstState); /* Is the battery discharging? */ if (BstState & ACPI_BATT_STAT_DISCHARG) { /* Set power state and check if it just started discharging now */ DeviceExtension->State |= BATTERY_DISCHARGING; if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG)) { /* Remember the time when the state changed */ DeviceExtension->InterruptTime = KeQueryInterruptTime(); } } else if (BstState & ACPI_BATT_STAT_CHARGING) { /* Battery is charging, update power state */ DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE); } /* Is the battery in a critical state? */ if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL; /* Read the voltage data */ DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage; /* Check if we have an A/C adapter */ if (AcAdapterPdo) { /* Query information on it */ CmBattGetPsrData(AcAdapterPdo, &PsrData); } else { /* Otherwise, check if the battery is charging */ if (BstState & ACPI_BATT_STAT_CHARGING) { /* Then we'll assume there's a charger */ PsrData = 1; } else { /* Assume no charger */ PsrData = 0; } } /* Is there a charger? */ if (PsrData) { /* Set the power state flag to reflect this */ DeviceExtension->State |= BATTERY_POWER_ON_LINE; if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n"); } else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) { DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n"); } /* Get some data we'll need */ DesignVoltage = DeviceExtension->BifData.DesignVoltage; PresentRate = DeviceExtension->BstData.PresentRate; RemainingCapacity = DeviceExtension->BstData.RemainingCapacity; /* Check if we have battery data in Watts instead of Amps */ if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS) { /* Get the data from the BST */ DeviceExtension->RemainingCapacity = RemainingCapacity; DeviceExtension->Rate = PresentRate; /* Check if the rate is invalid */ if (PresentRate > CM_MAX_VALUE) { /* Set an unknown rate and don't touch the old value */ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING)) { DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n"); DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate); } } } else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage)) { /* We have voltage data, what about capacity? */ if (RemainingCapacity == CM_UNKNOWN_VALUE) { /* Unable to calculate it */ DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; if (CmBattDebug & CMBATT_ACPI_WARNING) { DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n"); DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n"); } } else { /* Compute the capacity with the information we have */ DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000; } /* Check if we have a rate */ if (PresentRate != CM_UNKNOWN_VALUE) { /* Make sure the rate isn't too large */ if (PresentRate > (-500 / DesignVoltage)) { /* It is, so set unknown state */ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; if (CmBattDebug & CMBATT_ACPI_WARNING) { DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate); } } /* Compute the rate */ DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000; } else { /* We don't have a rate, so set unknown value */ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; if (CmBattDebug & CMBATT_ACPI_WARNING) { DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n"); } } } else { /* We have no rate, and no capacity, set unknown values */ DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; if (CmBattDebug & CMBATT_ACPI_WARNING) { DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n"); DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage); } } /* Check if we have an unknown rate */ if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE) { /* The battery is discharging but we don't know by how much... this is bad! */ if ((BstState & ACPI_BATT_STAT_DISCHARG) && (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) DbgPrint("CmBattGetBatteryStatus: battery rate is unkown when battery is not charging!\n"); } else if (DeviceExtension->State & BATTERY_DISCHARGING) { /* The battery is discharging, so treat the rate as a negative rate */ DeviceExtension->Rate = -DeviceExtension->Rate; } else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate)) { /* We are not charging, not discharging, but have a rate? Ignore it! */ if (CmBattDebug & CMBATT_GENERIC_WARNING) DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n", DeviceExtension->Rate); DeviceExtension->Rate = 0; } /* Done */ return STATUS_SUCCESS; }
//============================================================================= STDMETHODIMP CMiniportWaveCyclicStream::SetState( IN KSSTATE NewState ) /*++ Routine Description: The SetState function sets the new state of playback or recording for the stream. SetState should run at IRQL PASSIVE_LEVEL Arguments: NewState - KSSTATE indicating the new state for the stream. Return Value: NT status code. --*/ { PAGED_CODE(); DPF_ENTER(("[CMiniportWaveCyclicStream::SetState]")); NTSTATUS ntStatus = STATUS_SUCCESS; // The acquire state is not distinguishable from the stop state for our // purposes. if (NewState == KSSTATE_ACQUIRE) { NewState = KSSTATE_STOP; } if (m_ksState != NewState) { switch(NewState) { case KSSTATE_PAUSE: DPF(D_TERSE, ("KSSTATE_PAUSE")); m_fDmaActive = FALSE; break; case KSSTATE_RUN: DPF(D_TERSE, ("KSSTATE_RUN")); LARGE_INTEGER delay; // Set the timer for DPC. m_ullDmaTimeStamp = KeQueryInterruptTime(); m_ullElapsedTimeCarryForward = 0; m_fDmaActive = TRUE; delay.HighPart = 0; delay.LowPart = m_pMiniport->m_NotificationInterval; KeSetTimerEx(m_pTimer, delay, m_pMiniport->m_NotificationInterval, m_pDpc); break; case KSSTATE_STOP: DPF(D_TERSE, ("KSSTATE_STOP")); m_fDmaActive = FALSE; m_ulDmaPosition = 0; m_ullElapsedTimeCarryForward = 0; m_ulByteDisplacementCarryForward = 0; KeCancelTimer(m_pTimer); // Wait until all work items are completed. if (!m_fCapture) { m_SaveData.WaitAllWorkItems(); } break; } m_ksState = NewState; } return ntStatus; } // SetState