/* * @implemented */ PVOID NTAPI KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine, IN PVOID Context) { KIRQL OldIrql; PKNMI_HANDLER_CALLBACK NmiData, Next; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Allocate NMI callback data */ NmiData = ExAllocatePoolWithTag(NonPagedPool, sizeof(KNMI_HANDLER_CALLBACK), 'IMNK'); if (!NmiData) return NULL; /* Fill in the information */ NmiData->Callback = CallbackRoutine; NmiData->Context = Context; NmiData->Handle = NmiData; /* Insert it into NMI callback list */ KiAcquireNmiListLock(&OldIrql); NmiData->Next = KiNmiCallbackListHead; Next = InterlockedCompareExchangePointer((PVOID*)&KiNmiCallbackListHead, NmiData, NmiData->Next); ASSERT(Next == NmiData->Next); KiReleaseNmiListLock(OldIrql); /* Return the opaque "handle" */ return NmiData->Handle; }
BOOLEAN NTAPI VideoPortDDCMonitorHelper( PVOID HwDeviceExtension, PVOID I2CFunctions, PUCHAR pEdidBuffer, ULONG EdidBufferSize ) { PDDC_CONTROL ddc = (PDDC_CONTROL)I2CFunctions; PI2C_CALLBACKS i2c = &ddc->I2CCallbacks; INT Count, i; PUCHAR pBuffer = (PUCHAR)pEdidBuffer; BOOL Ack; TRACE_(VIDEOPRT, "VideoPortDDCMonitorHelper()\n"); ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL); if (ddc->Size != sizeof (ddc)) { WARN_(VIDEOPRT, "ddc->Size != %d (%d)\n", sizeof (ddc), ddc->Size); return FALSE; } /* select eeprom */ if (!I2CStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | WRITE)) return FALSE; /* set address */ if (!I2CWrite(HwDeviceExtension, i2c, 0x00)) return FALSE; /* change into read mode */ if (!I2CRepStart(HwDeviceExtension, i2c, DDC_EEPROM_ADDRESS | READ)) return FALSE; /* read eeprom */ RtlZeroMemory(pEdidBuffer, EdidBufferSize); Count = min(128, EdidBufferSize); for (i = 0; i < Count; i++) { Ack = ((i + 1) < Count); pBuffer[i] = I2CRead(HwDeviceExtension, i2c, Ack); } I2CStop(HwDeviceExtension, i2c); /* check EDID header */ if (pBuffer[0] != 0x00 || pBuffer[1] != 0xff || pBuffer[2] != 0xff || pBuffer[3] != 0xff || pBuffer[4] != 0xff || pBuffer[5] != 0xff || pBuffer[6] != 0xff || pBuffer[7] != 0x00) { WARN_(VIDEOPRT, "VideoPortDDCMonitorHelper(): Invalid EDID header!\n"); return FALSE; } INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper(): EDID version %d rev. %d\n", pBuffer[18], pBuffer[19]); INFO_(VIDEOPRT, "VideoPortDDCMonitorHelper() - SUCCESS!\n"); return TRUE; }
/*++ * @name ExUnregisterCallback * @implemented * * Deregisters a CallBack * See: DDK, OSR, links in ExNotifyCallback * * @param CallbackRegistration * Callback Registration Handle * * @return None * * @remarks None * *--*/ VOID NTAPI ExUnregisterCallback(IN PVOID CallbackRegistrationHandle) { PCALLBACK_REGISTRATION CallbackRegistration; PCALLBACK_OBJECT CallbackObject; KIRQL OldIrql; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Convert Handle to valid Structure Pointer */ CallbackRegistration = (PCALLBACK_REGISTRATION)CallbackRegistrationHandle; /* Get the Callback Object */ CallbackObject = CallbackRegistration->CallbackObject; /* Lock the Object */ KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); /* We can't Delete the Callback if it's in use */ while (CallbackRegistration->Busy) { /* Let everyone else know we're unregistering */ CallbackRegistration->UnregisterWaiting = TRUE; /* We are going to wait for the event, so the Lock isn't necessary */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Make sure the event is cleared */ KeClearEvent(&ExpCallbackEvent); /* Wait for the Event */ KeWaitForSingleObject(&ExpCallbackEvent, Executive, KernelMode, FALSE, NULL); /* We need the Lock again */ KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); } /* Remove the Callback */ RemoveEntryList(&CallbackRegistration->Link); /* It's now safe to release the lock */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Delete this registration */ ExFreePoolWithTag(CallbackRegistration, TAG_CALLBACK_REGISTRATION); /* Remove the reference */ ObDereferenceObject(CallbackObject); }
/* * @implemented */ LONG NTAPI KePulseEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD Thread; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Old State */ PreviousState = Event->Header.SignalState; /* Check if we are non-signaled and we have stuff in the Wait Queue */ if (!PreviousState && !IsListEmpty(&Event->Header.WaitListHead)) { /* Set the Event to Signaled */ Event->Header.SignalState = 1; /* Wake the Event */ KiWaitTest(&Event->Header, Increment); } /* Unsignal it */ Event->Header.SignalState = 0; /* Check what wait state was requested */ if (Wait == FALSE) { /* Wait not requested, release Dispatcher Database and return */ KiReleaseDispatcherLock(OldIrql); } else { /* Return Locked and with a Wait */ Thread = KeGetCurrentThread(); Thread->WaitNext = TRUE; Thread->WaitIrql = OldIrql; } /* Return the previous State */ return PreviousState; }
/*++ * @name KeRemoveQueueApc * @implemented NT4 * * The KeRemoveQueueApc routine removes a given APC object from the system * APC queue. * * @param Apc * Pointer to an initialized APC object that was queued by calling * KeInsertQueueApc. * * @return TRUE if the APC Object is in the APC Queue. Otherwise, no operation * is performed and FALSE is returned. * * @remarks If the given APC Object is currently queued, it is removed from the * queue and any calls to the registered routines are cancelled. * * Callers of this routine must be running at IRQL <= DISPATCH_LEVEL. * *--*/ BOOLEAN NTAPI KeRemoveQueueApc(IN PKAPC Apc) { PKTHREAD Thread = Apc->Thread; PKAPC_STATE ApcState; BOOLEAN Inserted; KLOCK_QUEUE_HANDLE ApcLock; ASSERT_APC(Apc); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Get the APC lock */ KiAcquireApcLock(Thread, &ApcLock); /* Check if it's inserted */ Inserted = Apc->Inserted; if (Inserted) { /* Set it as non-inserted and get the APC state */ Apc->Inserted = FALSE; ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex]; /* Acquire the dispatcher lock and remove it from the list */ KiAcquireDispatcherLockAtDpcLevel(); if (RemoveEntryList(&Apc->ApcListEntry)) { /* Set the correct state based on the APC Mode */ if (Apc->ApcMode == KernelMode) { /* No more pending kernel APCs */ ApcState->KernelApcPending = FALSE; } else { /* No more pending user APCs */ ApcState->UserApcPending = FALSE; } } /* Release dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); } /* Release the lock and return */ KiReleaseApcLock(&ApcLock); return Inserted; }
/* * Updates all WNDOBJs of the given WND and calls the change-procs. */ VOID FASTCALL IntEngWindowChanged( PWND Window, FLONG flChanged) { PPROPERTY pprop; WNDGDI *Current; HWND hWnd; ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL); hWnd = Window->head.h; pprop = IntGetProp(Window, AtomWndObj); if (!pprop) { return; } Current = (WNDGDI *)pprop->Data; if ( gcountPWO && Current && Current->Hwnd == hWnd && Current->WndObj.pvConsumer != NULL ) { /* Update the WNDOBJ */ switch (flChanged) { case WOC_RGN_CLIENT: /* Update the clipobj and client rect of the WNDOBJ */ IntEngWndUpdateClipObj(Current, Window); break; case WOC_DELETE: /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */ break; } /* Call the change proc */ IntEngWndCallChangeProc(&Current->WndObj, flChanged); /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */ if (flChanged == WOC_RGN_CLIENT) { IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED); } } }
/* * @implemented */ VOID NTAPI IoQueueWorkItem(IN PIO_WORKITEM IoWorkItem, IN PIO_WORKITEM_ROUTINE WorkerRoutine, IN WORK_QUEUE_TYPE QueueType, IN PVOID Context) { /* Make sure we're called at DISPATCH or lower */ ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Reference the device object */ ObReferenceObject(IoWorkItem->DeviceObject); /* Setup the work item */ IoWorkItem->WorkerRoutine = WorkerRoutine; IoWorkItem->Context = Context; /* Queue the work item */ ExQueueWorkItem(&IoWorkItem->Item, QueueType); }
/* * @implemented */ LONG NTAPI KeResetEvent(IN PKEVENT Event) { KIRQL OldIrql; LONG PreviousState; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Event->Header.SignalState; /* Set it to zero */ Event->Header.SignalState = 0; /* Release Dispatcher Database and return previous state */ KiReleaseDispatcherLock(OldIrql); return PreviousState; }
/*++ * @name KeInsertQueueApc * @implemented NT4 * * The KeInsertQueueApc routine queues a APC for execution when the right * scheduler environment exists. * * @param Apc * Pointer to an initialized control object of type APC for which the * caller provides the storage. * * @param SystemArgument[1,2] * Pointer to a set of two parameters that contain untyped data. * * @param PriorityBoost * Priority Boost to apply to the Thread. * * @return If the APC is already inserted or APC queueing is disabled, FALSE. * Otherwise, TRUE. * * @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered, * and at PASSIVE_LEVEL for the NormalRoutine registered. * * Callers of this routine must be running at IRQL <= DISPATCH_LEVEL. * *--*/ BOOLEAN NTAPI KeInsertQueueApc(IN PKAPC Apc, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN KPRIORITY PriorityBoost) { PKTHREAD Thread = Apc->Thread; KLOCK_QUEUE_HANDLE ApcLock; BOOLEAN State = TRUE; ASSERT_APC(Apc); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Get the APC lock */ KiAcquireApcLock(Thread, &ApcLock); /* Make sure we can Queue APCs and that this one isn't already inserted */ if (!(Thread->ApcQueueable) || (Apc->Inserted)) { /* Fail */ State = FALSE; } else { /* Set the System Arguments and set it as inserted */ Apc->SystemArgument1 = SystemArgument1; Apc->SystemArgument2 = SystemArgument2; Apc->Inserted = TRUE; /* Call the Internal Function */ KiInsertQueueApc(Apc, PriorityBoost); } /* Release the APC lock and return success */ KiReleaseApcLockFromDpcLevel(&ApcLock); KiExitDispatcher(ApcLock.OldIrql); return State; }
/* * @implemented */ LONG NTAPI KeSetEvent(IN PKEVENT Event, IN KPRIORITY Increment, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD Thread; ASSERT_EVENT(Event); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* * Check if this is an signaled notification event without an upcoming wait. * In this case, we can immediately return TRUE, without locking. */ if ((Event->Header.Type == EventNotificationObject) && (Event->Header.SignalState == 1) && !(Wait)) { /* Return the signal state (TRUE/Signalled) */ return TRUE; } /* Lock the Dispathcer Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Event->Header.SignalState; /* Set the Event to Signaled */ Event->Header.SignalState = 1; /* Check if the event just became signaled now, and it has waiters */ if (!(PreviousState) && !(IsListEmpty(&Event->Header.WaitListHead))) { /* Check the type of event */ if (Event->Header.Type == EventNotificationObject) { /* Unwait the thread */ KxUnwaitThread(&Event->Header, Increment); } else { /* Otherwise unwait the thread and unsignal the event */ KxUnwaitThreadForEvent(Event, Increment); } } /* Check what wait state was requested */ if (!Wait) { /* Wait not requested, release Dispatcher Database and return */ KiReleaseDispatcherLock(OldIrql); } else { /* Return Locked and with a Wait */ Thread = KeGetCurrentThread(); Thread->WaitNext = TRUE; Thread->WaitIrql = OldIrql; } /* Return the previous State */ return PreviousState; }
/*++ * @name KeFlushQueueApc * @implemented NT4 * * The KeFlushQueueApc routine flushes all APCs of the given processor mode * from the specified Thread's APC queue. * * @param Thread * Pointer to the thread whose APC queue will be flushed. * * @param PreviousMode * Specifies which APC Queue to flush. * * @return A pointer to the first entry in the flushed APC queue. * * @remarks If the routine returns NULL, it means that no APCs were flushed. * Callers of this routine must be running at DISPATCH_LEVEL or lower. * *--*/ PLIST_ENTRY NTAPI KeFlushQueueApc(IN PKTHREAD Thread, IN KPROCESSOR_MODE PreviousMode) { PKAPC Apc; PLIST_ENTRY FirstEntry, CurrentEntry; KLOCK_QUEUE_HANDLE ApcLock; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Check if this was user mode */ if (PreviousMode == UserMode) { /* Get the APC lock */ KiAcquireApcLock(Thread, &ApcLock); /* Select user list and check if it's empty */ if (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) { /* Don't return anything */ FirstEntry = NULL; goto FlushDone; } } else { /* Select kernel list and check if it's empty */ if (IsListEmpty( &Thread->ApcState.ApcListHead[KernelMode])) { /* Don't return anything */ return NULL; } /* Otherwise, acquire the APC lock */ KiAcquireApcLock(Thread, &ApcLock); } /* Get the first entry and check if the list is empty now */ FirstEntry = Thread->ApcState.ApcListHead[PreviousMode].Flink; if (FirstEntry == &Thread->ApcState.ApcListHead[PreviousMode]) { /* It is, clear the returned entry */ FirstEntry = NULL; } else { /* It's not, remove the first entry */ RemoveEntryList(&Thread->ApcState.ApcListHead[PreviousMode]); /* Loop all the entries */ CurrentEntry = FirstEntry; do { /* Get the APC and make it un-inserted */ Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry); Apc->Inserted = FALSE; /* Get the next entry */ CurrentEntry = CurrentEntry->Flink; } while (CurrentEntry != FirstEntry); /* Re-initialize the list */ InitializeListHead(&Thread->ApcState.ApcListHead[PreviousMode]); } /* Release the lock */ FlushDone: KiReleaseApcLock(&ApcLock); /* Return the first entry */ return FirstEntry; }
/*++ * @name ExRegisterCallback * @implemented * * Allows a function to associate a callback pointer (Function) to * a created Callback object * See: DDK, OSR, links in ExNotifyCallback * * @param CallbackObject * The Object Created with ExCreateCallBack * * @param CallBackFunction * Pointer to the function to be called back * * @param CallBackContext * Block of memory that can contain user-data which will be * passed on to the callback * * @return A handle to a Callback Registration Structure (MSDN Documentation) * * @remarks None * *--*/ PVOID NTAPI ExRegisterCallback(IN PCALLBACK_OBJECT CallbackObject, IN PCALLBACK_FUNCTION CallbackFunction, IN PVOID CallbackContext) { PCALLBACK_REGISTRATION CallbackRegistration = NULL; KIRQL OldIrql; /* Sanity checks */ ASSERT(CallbackFunction); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Create reference to Callback Object */ ObReferenceObject(CallbackObject); /* Allocate memory for the structure */ CallbackRegistration = ExAllocatePoolWithTag(NonPagedPool, sizeof(CALLBACK_REGISTRATION), TAG_CALLBACK_REGISTRATION); if (!CallbackRegistration) { /* Dereference and fail */ ObDereferenceObject (CallbackObject); return NULL; } /* Create Callback Registration */ CallbackRegistration->CallbackObject = CallbackObject; CallbackRegistration->CallbackFunction = CallbackFunction; CallbackRegistration->CallbackContext = CallbackContext; CallbackRegistration->Busy = 0; CallbackRegistration->UnregisterWaiting = FALSE; /* Acquire SpinLock */ KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); /* Check if 1) No Callbacks registered or 2) Multiple Callbacks allowed */ if ((CallbackObject->AllowMultipleCallbacks) || (IsListEmpty(&CallbackObject->RegisteredCallbacks))) { /* Register the callback */ InsertTailList(&CallbackObject->RegisteredCallbacks, &CallbackRegistration->Link); /* Release SpinLock */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); } else { /* Release SpinLock */ KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); /* Free the registration */ ExFreePoolWithTag(CallbackRegistration, TAG_CALLBACK_REGISTRATION); CallbackRegistration = NULL; /* Dereference the object */ ObDereferenceObject(CallbackObject); } /* Return handle to Registration Object */ return (PVOID)CallbackRegistration; }
/* * @implemented */ LONG NTAPI KeReleaseMutant(IN PKMUTANT Mutant, IN KPRIORITY Increment, IN BOOLEAN Abandon, IN BOOLEAN Wait) { KIRQL OldIrql; LONG PreviousState; PKTHREAD CurrentThread = KeGetCurrentThread(); BOOLEAN EnableApc = FALSE; ASSERT_MUTANT(Mutant); ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); /* Lock the Dispatcher Database */ OldIrql = KiAcquireDispatcherLock(); /* Save the Previous State */ PreviousState = Mutant->Header.SignalState; /* Check if it is to be abandonned */ if (Abandon == FALSE) { /* Make sure that the Owner Thread is the current Thread */ if (Mutant->OwnerThread != CurrentThread) { /* Release the lock */ KiReleaseDispatcherLock(OldIrql); /* Raise an exception */ ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED : STATUS_MUTANT_NOT_OWNED); } /* If the thread owns it, then increase the signal state */ Mutant->Header.SignalState++; } else { /* It's going to be abandonned */ Mutant->Header.SignalState = 1; Mutant->Abandoned = TRUE; } /* Check if the signal state is only single */ if (Mutant->Header.SignalState == 1) { /* Check if it's below 0 now */ if (PreviousState <= 0) { /* Remove the mutant from the list */ RemoveEntryList(&Mutant->MutantListEntry); /* Save if we need to re-enable APCs */ EnableApc = Mutant->ApcDisable; } /* Remove the Owning Thread and wake it */ Mutant->OwnerThread = NULL; /* Check if the Wait List isn't empty */ if (!IsListEmpty(&Mutant->Header.WaitListHead)) { /* Wake the Mutant */ KiWaitTest(&Mutant->Header, Increment); } } /* Check if the caller wants to wait after this release */ if (Wait == FALSE) { /* Release the Lock */ KiReleaseDispatcherLock(OldIrql); } else { /* Set a wait */ CurrentThread->WaitNext = TRUE; CurrentThread->WaitIrql = OldIrql; } /* Check if we need to re-enable APCs */ if (EnableApc) KeLeaveCriticalRegion(); /* Return the previous state */ return PreviousState; }