dev: Add a DmaCallback class to DmaDevice

This patch introduces the DmaCallback helper class, which registers a callback
to fire after a sequence of (potentially non-contiguous) DMA transfers on a
DmaPort completes.
This commit is contained in:
Michael LeBeane 2016-09-13 23:14:24 -04:00
parent f17a5faf44
commit 6e4c51fa99

View file

@ -184,6 +184,91 @@ class DmaDevice : public PioDevice
};
/**
* DMA callback class.
*
* Allows one to register for a callback event after a sequence of (potentially
* non-contiguous) DMA transfers on a DmaPort completes. Derived classes must
* implement the process() method and use getChunkEvent() to allocate a
* callback event for each participating DMA.
*/
class DmaCallback : public Drainable
{
public:
virtual const std::string name() const { return "DmaCallback"; }
/**
* DmaPort ensures that all oustanding DMA accesses have completed before
* it finishes draining. However, DmaChunkEvents scheduled with a delay
* might still be sitting on the event queue. Therefore, draining is not
* complete until count is 0, which ensures that all outstanding
* DmaChunkEvents associated with this DmaCallback have fired.
*/
DrainState drain() override
{
return count ? DrainState::Draining : DrainState::Drained;
}
protected:
int count;
DmaCallback()
: count(0)
{ }
virtual ~DmaCallback() { }
/**
* Callback function invoked on completion of all chunks.
*/
virtual void process() = 0;
private:
/**
* Called by DMA engine completion event on each chunk completion.
* Since the object may delete itself here, callers should not use
* the object pointer after calling this function.
*/
void chunkComplete()
{
if (--count == 0) {
process();
// Need to notify DrainManager that this object is finished
// draining, even though it is immediately deleted.
signalDrainDone();
delete this;
}
}
/**
* Event invoked by DmaDevice on completion of each chunk.
*/
class DmaChunkEvent : public Event
{
private:
DmaCallback *callback;
public:
DmaChunkEvent(DmaCallback *cb)
: Event(Default_Pri, AutoDelete), callback(cb)
{ }
void process() { callback->chunkComplete(); }
};
public:
/**
* Request a chunk event. Chunks events should be provided to each DMA
* request that wishes to participate in this DmaCallback.
*/
Event *getChunkEvent()
{
++count;
return new DmaChunkEvent(this);
}
};
/**
* Buffered DMA engine helper class
*