diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-535E5C2A-DCFD-4BCB-B26B-11E88BDB8A8A.dita
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Adaptation/GUID-535E5C2A-DCFD-4BCB-B26B-11E88BDB8A8A.dita Fri Oct 15 14:32:18 2010 +0100
@@ -0,0 +1,295 @@
+
+
+
+
+
+TDmac Derived Class ImplementationImplementing the hardware-specific DMA controller.
+
The TDmac class is part of the PIL. It is a
+container for the DMA controller's channels, descriptors and descriptor
+headers. It also defines virtual functions for operations that require
+a PSL implementation.
+
You need to derive TDmac for each distinct type
+of DMA controller on your device, and implement these virtual functions.
+
+
+
+
+Function
+Mandatory/Conditional
+Description
+
+
+
+
+Transfer()
+Mandatory
+For single buffer and scatter/gather, this starts the DMA transfer.
+For double buffer, this prepares the next fragment to transfer while
+a current transfer is in operation
+
+
+StopTransfer()
+Mandatory
+Stop the specified channel synchronously. Must not return to
+the PSL implementation until the channel has stopped.
+
+
+IsIdle()
+Mandatory
+Returns ETrue if specified channel is idle,
+otherwise EFalse
+
+
+MaxTransferSize()
+Optional
+Takes the parameters and evaluates the maximum transfer size
+in bytes.
+
+
+MemAlignMask()
+Optional
+This applies to DMA v1 only.
+
+
+InitHwDes()
+Optional
+For scatter-gather, initialise the array of memory areas and
+set up the first block of data to be transferred.
+
+
+ChainHwDes()
+Optional
+For scatter-gather, add additional blocks of data to transfer
+to the list of memory areas.
+
+
+AppendHwDes()
+Optional
+For scatter-gather, add to the array of memory areas while
+the transfer is active. This is used in particular for streaming data
+where new descriptors can be added to the end of the chain while data
+earlier in the train is being transferred. E.g. video streaming.
+
+
+UnlinkHwDes()
+Optional
+For scatter-gather, remove items from the array of memory areas.
+
+
+FailNext()
+Optional
+For a sequence of memory transfers, tell the next one to fail.
+
+
+MissNextInterrupts()
+Optional
+DMA transfers start on the next interrupt, but sometimes you
+want to skip the next interrupt for synchronisation or other reasons.
+
+
+Extension()
+Optional
+Pass a command from the application/client down to the DMA
+chipset. Hardware dependent.
+
+
+
+
The TDmac class contains several pure virtual functions that
+must be implemented by the PSL implementation:
+
TDmac::Transfer()
+
TDmac::StopTransfer()
+
TDmac::IsIdle()
+
These functions start and stop transfers on a DMA channel
+and are the main interface between the PIL and the PSL. The implementation
+of these functions depends on the hardware available for performing
+DMA, and on the characteristics used to specify a DMA transfer:
+
the source and
+destination addresses
+
the burst size
+
the maximum transfer
+size
+
the transfer width,
+i.e. number of bits per memory access
+
the memory alignment
+and endianness.
+
The DMA Framework manages the transfer descriptors according
+to the descriptor parameter passed into the TDmac constructor by the derived class constructor; the descriptor parameter
+is a TDmac::SCreateInfo structure. The per-request
+transfer parameters are passed into the descriptors for each request
+issued by a driver.
+The
+transfer function: Transfer()
This function initiates a
+previously constructed request on a specific channel. This is the
+template implementation:
+void TTemplateDmac::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
+//
+// Initiates a (previously constructed) request on a specific channel.
+//
+ {
+ const TUint8 i = static_cast&<TUint8&>(aChannel.PslId());
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::Transfer channel=%d des=0x%08X", i, pD));
+
+ // Load the first descriptor address into the DMAC and start it
+ // by setting the RUN bit.
+ (void) *pD, (void) i;
+
+ }
+
+The
+stop transfer function: StopTransfer()
IsIdle() returns
+the state of a given channel. This is the template implementation:
TBool TTemplateDmac::IsIdle(const TDmaChannel& aChannel)
+//
+// Returns the state of a given channel.
+//
+ {
+ const TUint8 i = static_cast&<TUint8&>(aChannel.PslId());
+
+ __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::IsIdle channel=%d", i));
+
+ return ETrue;
+ }
+
+Implement
+the non-mandatory controller virtual functions
The following
+auxiliary functions are used to implement the scatter-gather transfer
+mode behavior by creating and manipulating the linked list of transfer
+fragment headers that describe a given scatter-gather transaction.
+They are called by the TDmac base class functions
+when the instance of the TDmac derived class reports
+itself as being capable of scatter-gather operations.
+
TDmac::InitHwDes()
+
TDmac::ChainHwDes()
+
TDmac::AppendHwDes()
+
+First
+scatter-gather support function: InitHwDes()
This is a
+function for creating a scatter-gather list. From the information
+in the passed-in request, the function sets up the descriptor with
+that fragment's:
+
source and destination
+address
+
size
+
driver/DMA controller
+specific transfer parameters: memory/peripheral, burst size, transfer
+width.
+
This is the template implementation:
void TTemplateDmac::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
+ TUint aFlags, TUint32 aPslInfo, TUint32 /*aCookie*/)
+//
+// Sets up (from a passed in request) the descriptor with that fragment's source and destination address,
+// the fragment size, and the (driver/DMA controller) specific transfer parameters (mem/peripheral,
+// burst size, transfer width).
+//
+ {
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::InitHwDes 0x%08X", pD));
+
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pD));
+
+ pD-&>iSrcAddr = (aFlags & KDmaPhysAddrSrc) ? aSrc : Epoc::LinearToPhysical(aSrc);
+ pD-&>iDestAddr = (aFlags & KDmaPhysAddrDest) ? aDest : Epoc::LinearToPhysical(aDest);
+ pD-&>iCmd = DcmdReg(aCount, aFlags, aPslInfo);
+ pD-&>iDescAddr = TDmaDesc::KStopBitMask;
+ }
+
+Second
+scatter-gather support function: ChainHwDes()
If the framework
+needs to fragment the client’s request, either because of the transfer
+size or because the memory is not a single contiguous block, then
+the framework calls this function. It chains hardware descriptors
+together by setting the next pointer of the original descriptor to
+the physical address of the descriptor to be chained. It assumes that
+the DMAC channel is quiescent when called.
This is the template
+implementation:
void TTemplateDmac::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
+//
+// Chains hardware descriptors together by setting the next pointer of the original descriptor
+// to the physical address of the descriptor to be chained.
+//
+ {
+ TDmaDesc* pD = HdrToHwDes(aHdr);
+ TDmaDesc* pN = HdrToHwDes(aNextHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("TTemplateDmac::ChainHwDes des=0x%08X next des=0x%08X", pD, pN));
+
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pD) && IsHwDesAligned(pN));
+
+ pD-&>iDescAddr = DesLinToPhys(pN);
+ }
+
+Third
+scatter-gather support function: AppendHwDes()
This function
+is called by the TDmac base class when a driver
+request is called for a channel that is still active, i.e. where the
+intent is to provide data streaming so that the target device is constantly
+provided with data; for example, an audio device playing a track.
+In this case, the function provided by the derived class must:
+
stop the DMAC to
+prevent any corruption of the scatter-gather list while appending
+the new fragment descriptor
+
append the new
+descriptor
+
re-enable the channel,
+ideally before the target has detected the gap in service.
+
This is the template implementation:
void TTemplateDmac::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
+ const SDmaDesHdr& aNewHdr)
+//
+// Appends a descriptor to the chain while the channel is running.
+//
+ {
+ const TUint8 i = static_cast&<TUint8&>(aChannel.PslId());
+
+ TDmaDesc* pL = HdrToHwDes(aLastHdr);
+ TDmaDesc* pN = HdrToHwDes(aNewHdr);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("&>TTemplateDmac::AppendHwDes channel=%d last des=0x%08X new des=0x%08X",
+ i, pL, pN));
+ // Unaligned descriptor? Error in generic layer!
+ __DMA_ASSERTD(IsHwDesAligned(pL) && IsHwDesAligned(pN));
+
+ TPhysAddr newPhys = DesLinToPhys(pN);
+
+ const TInt irq = NKern::DisableAllInterrupts();
+ StopTransfer(aChannel);
+
+ pL-&>iDescAddr = newPhys;
+ const TTemplateSgChannel& channel = static_cast&<const TTemplateSgChannel&&>(aChannel);
+ TDmaDesc* pD = channel.iTmpDes;
+
+ (void) *pD, (void) i;
+
+ NKern::RestoreInterrupts(irq);
+
+ __KTRACE_OPT(KDMA, Kern::Printf("&<TTemplateDmac::AppendHwDes"));
+ }
+
+
+DMA
+Technology Guide
+DMA
+Implementation Guide
+
\ No newline at end of file