Beispiel #1
0
/*
 * @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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
/*++
 * @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);
}
Beispiel #4
0
/*
 * @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;
}
Beispiel #5
0
/*++
 * @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;
}
Beispiel #6
0
/*
 * 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);
     }
  }
}
Beispiel #7
0
/*
 * @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);
}
Beispiel #8
0
/*
 * @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;
}
Beispiel #9
0
/*++
 * @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;
}
Beispiel #10
0
/*
 * @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;
}
Beispiel #11
0
/*++
 * @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;
}
Beispiel #12
0
/*++
 * @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;
}
Beispiel #13
0
/*
 * @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;
}