--- a/kernel/eka/drivers/dma/dmapil.cpp Tue Jan 19 13:48:03 2010 +0000
+++ b/kernel/eka/drivers/dma/dmapil.cpp Mon Jan 18 21:31:10 2010 +0200
@@ -475,6 +475,15 @@
// append request to queue and link new descriptor list to existing one.
iChannel.Wait();
+
+ TUint32 req_count = iChannel.iQueuedRequests++;
+ if (req_count == 0)
+ {
+ iChannel.Signal();
+ iChannel.QueuedRequestCountChanged();
+ iChannel.Wait();
+ }
+
if (!(iChannel.iIsrDfc & (TUint32)TDmaChannel::KCancelFlagMask))
{
iQueued = ETrue;
@@ -482,8 +491,18 @@
*iChannel.iNullPtr = iFirstHdr;
iChannel.iNullPtr = &(iLastHdr->iNext);
iChannel.DoQueue(*this);
+ iChannel.Signal();
}
- iChannel.Signal();
+ else
+ {
+ // Someone is cancelling all requests...
+ req_count = --iChannel.iQueuedRequests;
+ iChannel.Signal();
+ if (req_count == 0)
+ {
+ iChannel.QueuedRequestCountChanged();
+ }
+ }
__DMA_INVARIANT();
}
@@ -586,14 +605,19 @@
TDmaChannel::TDmaChannel()
- : iNullPtr(&iCurHdr),
- iDfc(Dfc, NULL, 0)
+ : iController(NULL),
+ iPslId(0),
+ iCurHdr(NULL),
+ iNullPtr(&iCurHdr),
+ iDfc(Dfc, NULL, 0),
+ iMaxDesCount(0),
+ iAvailDesCount(0),
+ iIsrDfc(0),
+ iReqQ(),
+ iReqCount(0),
+ iQueuedRequests(0),
+ iCancelInfo(NULL)
{
- // iController = NULL;
- // iPslId = 0;
- // iCurHdr = NULL;
- // iMaxDesCount = iAvailDesCount = 0;
- // iReqCount = 0;
__DMA_INVARIANT();
}
@@ -640,6 +664,8 @@
__DMA_ASSERTD(IsQueueEmpty());
__DMA_ASSERTD(iReqCount == 0);
+ __DMA_ASSERTD(iQueuedRequests == 0);
+
// descriptor leak? bug in request code
__DMA_ASSERTD(iAvailDesCount == iMaxDesCount);
@@ -665,8 +691,10 @@
TBool wait = FALSE;
TDmaCancelInfo c;
TDmaCancelInfo* waiters = 0;
+
NKern::ThreadEnterCS();
Wait();
+ const TUint32 req_count_before = iQueuedRequests;
NThreadBase* dfcnt = iDfc.Thread();
__e32_atomic_store_ord32(&iIsrDfc, (TUint32)KCancelFlagMask);
// ISRs after this point will not post a DFC, however a DFC may already be queued or running or both
@@ -683,6 +711,7 @@
SDblQueLink* pL;
while ((pL = iReqQ.GetFirst()) != NULL)
{
+ iQueuedRequests--;
DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink);
pR->OnDeque();
}
@@ -709,12 +738,21 @@
wait = TRUE;
iDfc.Enque();
}
+ const TUint32 req_count_after = iQueuedRequests;
Signal();
if (waiters)
waiters->Signal();
if (wait)
NKern::FSWait(&c.iSem);
NKern::ThreadLeaveCS();
+
+ // Only call PSL if there were requests queued when we entered AND there
+ // are now no requests left on the queue.
+ if ((req_count_before != 0) && (req_count_after == 0))
+ {
+ QueuedRequestCountChanged();
+ }
+
__DMA_INVARIANT();
}
@@ -740,6 +778,8 @@
const TBool error = w & (TUint32)KErrorFlagMask;
TBool stop = w & (TUint32)KCancelFlagMask;
__DMA_ASSERTD(count>0 || stop);
+ const TUint32 req_count_before = iQueuedRequests;
+ TUint32 req_count_after = 0;
while(count && !stop)
{
@@ -767,6 +807,7 @@
{
pCompletedReq = pCurReq;
pCurReq->iLink.Deque();
+ iQueuedRequests--;
if (iReqQ.IsEmpty())
iNullPtr = &iCurHdr;
pCompletedReq->OnDeque();
@@ -814,6 +855,7 @@
// reset the ISR count - new requests can now be processed
__e32_atomic_store_rel32(&iIsrDfc, 0);
+ req_count_after = iQueuedRequests;
Signal();
// release threads doing CancelAll()
@@ -832,6 +874,7 @@
SDblQueLink* pL;
while ((pL = q.GetFirst()) != NULL)
{
+ iQueuedRequests--;
DDmaRequest* pR = _LOFF(pL, DDmaRequest, iLink);
__KTRACE_OPT(KDMA, Kern::Printf("Removing request from queue and notifying client"));
pR->OnDeque();
@@ -844,10 +887,22 @@
Wait();
}
}
+ req_count_after = iQueuedRequests;
Signal();
}
else
+ {
+ req_count_after = iQueuedRequests;
Signal();
+ }
+
+ // Only call PSL if there were requests queued when we entered AND there
+ // are now no requests left on the queue (after also having executed all
+ // client callbacks).
+ if ((req_count_before != 0) && (req_count_after == 0))
+ {
+ QueuedRequestCountChanged();
+ }
__DMA_INVARIANT();
}
@@ -870,6 +925,21 @@
{
}
+
+/** PSL may override */
+void TDmaChannel::QueuedRequestCountChanged()
+ {
+#ifdef _DEBUG
+ Wait();
+ __KTRACE_OPT(KDMA,
+ Kern::Printf("TDmaChannel::QueuedRequestCountChanged() %d",
+ iQueuedRequests));
+ __DMA_ASSERTA(iQueuedRequests >= 0);
+ Signal();
+#endif
+ }
+
+
#ifdef _DEBUG
void TDmaChannel::Invariant()