Main Page | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

waitlistener.c

Go to the documentation of this file.
00001 /*
00002  *  This program is free software; you can redistribute it and/or
00003  *  modify it under the terms of the GNU General Public License
00004  *  as published by the Free Software Foundation; either version
00005  *  2 of the License, or (at your option) any later version.
00006  *
00007  *  Copyright 1999-2004 Michael Klein <michael(dot)klein(at)puffin(dot)lb(dot)shuttle(dot)de>
00008  *  Copyright 2001-2004 Spiro Trikaliotis
00009  *
00010  */
00011 
00023 #include <wdm.h>
00024 #include "cbm_driver.h"
00025 #include "i_iec.h"
00026 
00027 #ifdef USE_DPC
00028 
00043 static VOID
00044 WaitCancelRoutine(IN PDEVICE_OBJECT Fdo, IN PIRP Irp)
00045 {
00046     PDEVICE_EXTENSION pdx;
00047 
00048     FUNC_ENTER();
00049 
00050     pdx = Fdo->DeviceExtension;
00051 
00052     // We do not need the cancel spin lock anymore
00053 
00054     DBG_DPC((DBG_PREFIX "Cancelling IRP 0x%p", Irp));
00055     DBG_IRQL( == DISPATCH_LEVEL);
00056     IoReleaseCancelSpinLock(Irp->CancelIrql);
00057 
00058     // Just release cbmiec_wait_for_listener(), but do NOT cancel the IRP!
00059     // This is left for cbmiec_wait_for_listener() as an exercise...
00060 
00061     DBG_IRQL( <= DISPATCH_LEVEL);
00062     KeSetEvent(&pdx->EventWaitForListener, IO_NO_INCREMENT, FALSE);
00063 
00064     FUNC_LEAVE();
00065 }
00066 
00067 #endif // #ifdef USE_DPC
00068 
00080 VOID
00081 cbmiec_wait_for_listener(IN PDEVICE_EXTENSION Pdx, IN BOOLEAN SendEoi)
00082 {
00083     ULONG NumberOfAcks = SendEoi ? 2 : 1;
00084 
00085     FUNC_ENTER();
00086 
00087     PERF_EVENT_VERBOSE(0x1100, NumberOfAcks);
00088 
00089     // This function has two incarnations. The first one
00090     // is used if we have successfully allocated the interrupt.
00091     // In this case, we just wait until the ISR has done the
00092     // essential work
00093 
00094     // When entering this function, DATA_IN should not be active
00095 
00096     DBG_ASSERT(CBMIEC_GET(PP_DATA_IN));
00097 
00098     if (Pdx->ParallelPortAllocatedInterrupt)
00099     {
00100         LONG ret;
00101 
00102         // This is implementation 1. It needs a working
00103         // ISR. The main work is done there
00104 
00105         // Tell the ISR how many interrupts to wait for
00106 
00107         PERF_EVENT_VERBOSE(0x1101, NumberOfAcks);
00108         ret = InterlockedExchange(&Pdx->IrqCount, NumberOfAcks);
00109         DBG_ASSERT(ret==0);
00110         PERF_EVENT_VERBOSE(0x1102, ret);
00111 
00112         // in the sequel, allow interrupts to occur
00113 
00114         DBG_IRQ(("Allow Interrupts"));
00115         CBMIEC_SET(PP_LP_IRQ);
00116 
00121         // Give the LISTENer the sign: We want to send something
00122 
00123         DBG_IRQ(("Release CLK_OUT"));
00124         CBMIEC_RELEASE(PP_CLK_OUT);
00125 
00126 #ifdef USE_DPC
00127 
00128         // set the cancel routine which will wake us up if we do not get
00129         // an IRQ, and a cancellation is requested
00130 
00131         PERF_EVENT_VERBOSE(0x1103, 0);
00132         DBG_VERIFY(IoSetCancelRoutine(Pdx->IrpQueue.CurrentIrp, WaitCancelRoutine) DBGDO(== NULL));
00133 
00134         // Now, wait until we have been signalled
00135 
00136         PERF_EVENT_VERBOSE(0x1104, 0);
00137         DBG_DPC((DBG_PREFIX "CALL KeWaitForSingleObject()"));
00138         KeWaitForSingleObject(&Pdx->EventWaitForListener, Executive, KernelMode, FALSE, NULL);
00139         DBG_DPC((DBG_PREFIX "RETURN from KeWaitForSingleObject()"));
00140 
00141         PERF_EVENT_VERBOSE(0x1105, 0);
00142 
00143         // we do not need the cancel routine anymore:
00144 
00145         if (IoSetCancelRoutine(Pdx->IrpQueue.CurrentIrp, NULL) == NULL)
00146         {
00147             PERF_EVENT_VERBOSE(0x1106, -1);
00148             // the cancel routine was called!
00149 
00150             // Make sure the IrqCount is resetted to zero.
00151 
00152             InterlockedExchange(&Pdx->IrqCount, 0);
00153         }
00154 
00155 #else
00156 
00157         // Wait until the listener has told us that it is able to listen
00158 
00159         while (!QueueShouldCancelCurrentIrp(&Pdx->IrpQueue) && Pdx->IrqCount)
00160         {
00161             cbmiec_schedule_timeout(libiec_global_timeouts.T_WaitForListener_Granu_T_H);
00162         }
00163 #endif
00164 
00165         DBG_IRQ(("IrqCount = 0"));
00166 
00167         // from here on, no interrupts will be generated anymore
00168 
00169         CBMIEC_RELEASE(PP_LP_IRQ);
00170         DBG_IRQ(("No more Interrupts"));
00171     }
00172     else
00173     {
00174         // This is implementation 2. We do not have a working
00175         // ISR. Due to this, we have to busy wait until the LISTENer
00176         // has told us that it will accept our data.
00177 
00178         // This solution isn't good, as we have to busy wait
00179         // and the acknowledgement can take very long.
00180 
00181         // As we need very exact timing, don't allow anyone to
00182         // disturb us
00183 
00188         cbmiec_block_irq(Pdx);
00189 
00190         // Give the LISTENer the sign: We want to send something
00191 
00192         CBMIEC_RELEASE(PP_CLK_OUT);
00193 
00194         // Wait until the listener has told us that it is able to listen
00195 
00196         while (!QueueShouldCancelCurrentIrp(&Pdx->IrpQueue) && NumberOfAcks)
00197         {
00198             while (!QueueShouldCancelCurrentIrp(&Pdx->IrpQueue) && CBMIEC_GET(PP_DATA_IN))
00199             {
00200                 // Wait for 1 us:
00201                 KeStallExecutionProcessor(1);
00202             }
00203 
00204             if (!CBMIEC_GET(PP_DATA_IN))
00205             {
00206                 if (--NumberOfAcks == 0)
00207                 {
00208                     CBMIEC_SET(PP_CLK_OUT);
00209                     DBG_SUCCESS((DBG_PREFIX "continue to send%s EOI", SendEoi ? "" : " no"));
00210                 }
00211                 else 
00212                 {
00213                     while (!QueueShouldCancelCurrentIrp(&Pdx->IrpQueue) && !CBMIEC_GET(PP_DATA_IN))
00214                     {
00215                         // Wait for 1 us:
00216                         KeStallExecutionProcessor(1);
00217                     }
00218                 }
00219             }
00220         }
00221 
00222         // Our timing is not critical anymore, go back to the old IRQL
00223 
00224         cbmiec_release_irq(Pdx);
00225     }
00226 
00227     PERF_EVENT_VERBOSE(0x1107, 0);
00228     FUNC_LEAVE();
00229 }

Generated on Sun Apr 30 18:46:01 2006 for opencbm by  doxygen 1.4.2