Exemplo n.º 1
0
/*! \brief DPC function for releasing cbmiec_wait_for_listener()

 \param Dpc
   Pointer to the KDPC

 \param Fdo
   Pointer to the FDO

 \param Irp
   Pointer to the Irp. UNUSED.

 \param Context
   Caller-supplied Context. UNUSED.

 \param Result 
   Pointer to the variable which will hold the return value.
   After return, it will contain 1 if there was an EOI, 0 otherwise.

 \return 
   If the routine succeeds, it returns STATUS_SUCCESS. Otherwise, it
   returns one of the error status values.
*/
VOID
cbmiec_dpc(IN PKDPC Dpc, IN PDEVICE_OBJECT Fdo, IN PIRP Irp, IN PVOID Context)
{
    PDEVICE_EXTENSION pdx;

    FUNC_ENTER();

    UNREFERENCED_PARAMETER(Dpc);
    UNREFERENCED_PARAMETER(Irp);
    UNREFERENCED_PARAMETER(Context);

    DBG_DPC((DBG_PREFIX "DPC called"));

    pdx = Fdo->DeviceExtension;

    // Set the event that we are ready to quit cbmiec_wait_for_listener()

    DBG_IRQL( <= DISPATCH_LEVEL);
    KeSetEvent(&pdx->EventWaitForListener, IO_SOUND_INCREMENT, FALSE);

    FUNC_LEAVE();
}
Exemplo n.º 2
0
/*! \brief Cancel routine if we are waiting

 This function is the cancel routine while a IRP is in the
 cbmiec_wait_for_listener() function.

 \param Fdo
   Pointer to the Fdo

 \param Irp
   Pointer to the IRP which is to be cancelled.

 This function does not cancel the IRP itself, but it only
 releases cbmiec_wait_for_listener().
*/
static VOID
WaitCancelRoutine(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
{
    PDEVICE_EXTENSION pdx;

    FUNC_ENTER();

    pdx = Fdo->DeviceExtension;

    // We do not need the cancel spin lock anymore

    DBG_DPC((DBG_PREFIX "Cancelling IRP 0x%p", Irp));
    DBG_IRQL( == DISPATCH_LEVEL);
    IoReleaseCancelSpinLock(Irp->CancelIrql);

    // Just release cbmiec_wait_for_listener(), but do NOT cancel the IRP!
    // This is left for cbmiec_wait_for_listener() as an exercise...

    DBG_IRQL( <= DISPATCH_LEVEL);
    KeSetEvent(&pdx->EventWaitForListener, IO_NO_INCREMENT, FALSE);

    FUNC_LEAVE();
}
Exemplo n.º 3
0
/*! \brief Wait until listener is ready to receive

 This function waits until a listener is ready.

 \param Pdx
   Pointer to the device extension.

 \param SendEoi
   TRUE if we want to signal an EOI.
   FALSE otherwise.
*/
VOID
cbmiec_wait_for_listener(IN PDEVICE_EXTENSION Pdx, IN BOOLEAN SendEoi)
{
    ULONG NumberOfAcks = SendEoi ? 2 : 1;

    FUNC_ENTER();

    PERF_EVENT_VERBOSE(0x1100, NumberOfAcks);

    // This function has two incarnations. The first one
    // is used if we have successfully allocated the interrupt.
    // In this case, we just wait until the ISR has done the
    // essential work

    // When entering this function, DATA_IN should not be active

    DBG_ASSERT(CBMIEC_GET(PP_DATA_IN));

    if (Pdx->ParallelPortAllocatedInterrupt)
    {
        LONG ret;

        // This is implementation 1. It needs a working
        // ISR. The main work is done there

        // Tell the ISR how many interrupts to wait for

        PERF_EVENT_VERBOSE(0x1101, NumberOfAcks);
        ret = InterlockedExchange(&Pdx->IrqCount, NumberOfAcks);
        DBG_ASSERT(ret==0);
        PERF_EVENT_VERBOSE(0x1102, ret);

        // in the sequel, allow interrupts to occur

        DBG_IRQ(("Allow Interrupts"));
        CBMIEC_SET(PP_LP_IRQ);

        /*! \todo Shouldn't we make sure that there
         * is no spurious interrupt until now?
         */

        // Give the LISTENer the sign: We want to send something

        DBG_IRQ(("Release CLK_OUT"));
        CBMIEC_RELEASE(PP_CLK_OUT);

#ifdef USE_DPC

        // set the cancel routine which will wake us up if we do not get
        // an IRQ, and a cancellation is requested

        PERF_EVENT_VERBOSE(0x1103, 0);
        DBG_VERIFY(IoSetCancelRoutine(Pdx->IrpQueue.CurrentIrp, WaitCancelRoutine) DBGDO(== NULL));

        // Now, wait until we have been signalled

        PERF_EVENT_VERBOSE(0x1104, 0);
        DBG_DPC((DBG_PREFIX "CALL KeWaitForSingleObject()"));
        KeWaitForSingleObject(&Pdx->EventWaitForListener, Executive, KernelMode, FALSE, NULL);
        DBG_DPC((DBG_PREFIX "RETURN from KeWaitForSingleObject()"));

        PERF_EVENT_VERBOSE(0x1105, 0);

        // we do not need the cancel routine anymore:

        if (IoSetCancelRoutine(Pdx->IrpQueue.CurrentIrp, NULL) == NULL)
        {
            PERF_EVENT_VERBOSE(0x1106, -1);
            // the cancel routine was called!

            // Make sure the IrqCount is resetted to zero.

            InterlockedExchange(&Pdx->IrqCount, 0);
        }

#else

        // Wait until the listener has told us that it is able to listen

        while (!QueueShouldCancelCurrentIrp(&Pdx->IrpQueue) && Pdx->IrqCount)
        {
            cbmiec_schedule_timeout(libiec_global_timeouts.T_WaitForListener_Granu_T_H);
        }
#endif

        DBG_IRQ(("IrqCount = 0"));

        // from here on, no interrupts will be generated anymore

        CBMIEC_RELEASE(PP_LP_IRQ);
        DBG_IRQ(("No more Interrupts"));
    }