Week 12 contribution of API Specs and fix SDK submission
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --><!-- This component and the accompanying materials are made available under the terms of the License "Eclipse Public License v1.0" which accompanies this distribution, and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --><!-- Initial Contributors: Nokia Corporation - initial contribution.Contributors: --><!DOCTYPE concept PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"><concept id="GUID-A4C19890-2380-5498-A5F8-3B6D95CEFEF4" xml:lang="en"><title>PSLImplementation</title><shortdesc>Describes how to create the PSL implementation.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody><p>To create a port of the DMA Framework, you must create an implementationof the PSL for the DMA controller hardware.</p><section id="GUID-8664FA8F-E53A-5DBA-999F-A0B800C1F54B"><title>Define andimplement PSL-specific channel classes</title> <p>The choice of class to beused for implementing DMA channels is governed by the mode of operation tobe supported: </p> <ul><li id="GUID-C254C7CA-D010-5885-811D-05BEAF068EDD"><p>single-buffer channelsshould use <xref href="GUID-A8B4AD1B-770C-363E-A0DE-C78A9786CBDC.dita"><apiname>TDmaSbChannel</apiname></xref> </p> </li><li id="GUID-91DDE5AD-16E5-5FCE-86E9-80069F2CCDDB"><p>double-buffer channelsshould use <xref href="GUID-FD76AF08-6250-3054-8A06-16343E385B23.dita"><apiname>TDmaDbChannel</apiname></xref> </p> </li><li id="GUID-994E863D-2C32-5AE3-931A-B852855883CA"><p>scatter-gather channelsshould use <xref href="GUID-2D4CFBB1-8D64-3CF5-B6F0-B24D16D5BAD4.dita"><apiname>TDmaSgChannel</apiname></xref> </p> </li></ul> <p>These three classes are defined in <filepath>dma.h</filepath>. </p> <p>Inaddition, the PSL may need to store channel-specific data. One way of achievingthis is by deriving a PSL-specific class from one of the generic ones. Forexample, the template scatter-gather implementation defines a <codeph>TTemplateSgChannel</codeph> classderived from <codeph>TDmaSgChannel</codeph> for storing data when appendingnew descriptors to a running channel: </p> <codeblock id="GUID-C4807321-01A3-5893-800A-6E22B8B5E131" xml:space="preserve">class TTemplateSgChannel : public TDmaSgChannel {public: TDmaDesc* iTmpDes; TPhysAddr iTmpDesPhysAddr; }; </codeblock> </section><section id="GUID-0991CFB7-B37E-57B9-BC1F-4A69FEDAF5A5"><title>Define andimplement the controller classes</title> <p>A controller can either be a physicalcontroller, or a logical one depending on which <xref href="GUID-97F97D7B-D5A3-5471-A359-77B805ED198C.dita">DMAmode you intend to support</xref>. </p> <p>The PSL (platform-specific layer)must define one concrete controller class per supported controller. A controllerclass is derived from <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref>. The concrete class must implementall the pure virtual functions defined in <codeph>TDmac</codeph>, and, optionallythe functions used to manipulate hardware descriptors. </p> <p>Taking thetemplate port as an example, the class is defined as: </p> <codeblock id="GUID-1C275111-6597-5616-822A-9EABF40BFE77" xml:space="preserve">class TTemplateDmac : public TDmac {public: TTemplateDmac(); TInt Create();private: // from TDmac (PIL pure virtual) virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr); virtual void StopTransfer(const TDmaChannel& aChannel); virtual TBool IsIdle(const TDmaChannel& aChannel); virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo); // from TDmac (PIL virtual) virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount, TUint aFlags, TUint32 aPslInfo, TUint32 aCookie); virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr); virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr, const SDmaDesHdr& aNewHdr); virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr); // other static void Isr(TAny* aThis); inline TDmaDesc* HdrToHwDes(const SDmaDesHdr& aHdr);private: static const SCreateInfo KInfo;public: TTemplateSgChannel iChannels[KChannelCount]; };</codeblock> <p>Notes: </p> <ul><li id="GUID-4E8059FF-0BBC-5F65-9F66-3C96BC86FE55"><p>The array of channelsmust be defined in the PSL controller class because only the PSL knows whatkind of channels are used. </p> </li><li id="GUID-66E7787B-E933-5E17-9169-E0D245B9D27A"><p>The PSL controller classmust be allocated in the BSS section of the DMA kernel extension. The secondphase constructor must be called from the extension entry point. </p> </li><li id="GUID-7306F4CB-5D0F-5E82-AC61-E068A48C9C9B"><p>The C++ constructormust pass a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure to the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructor.This structure defines what the PIL (platform-independent layer) needs toknow about the underlying DMA controller. The template <codeph>TTemplateDmac</codeph> constructorjust passes a <codeph>TDmac::ScreateInfo</codeph> structure, which definesthe layout of the (base class managed) descriptor pool to the base class constructorthrough a ctor list: </p> <codeblock id="GUID-E00DD5C0-0976-58A0-B3C0-22DFD9216BC0" xml:space="preserve">TTemplateDmac::TTemplateDmac()//// Constructor.// : TDmac(KInfo) {} </codeblock> <p>where KInfo is a <codeph>TDmac::ScreateInfo</codeph> type. </p> </li><li id="GUID-4C6FB95D-BE6F-5938-8AC3-824B3BB508EE"><p>The PSL controller classneeds a second phase constructor. This is the <codeph>Create()</codeph> function,which must: </p> <ol id="GUID-33DC912F-C5B4-5F33-A427-62700522D958"><li id="GUID-F0E8A497-B09F-5DA0-A94A-3B08FC28707C"><p>call the second phaseconstructor of the base class: <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref>. </p> </li><li id="GUID-1FD43FAD-4F43-557E-9EF0-19C725DD5FF5"><p>perform any hardware-specificinitialisation. </p> </li><li id="GUID-A522B8D4-744B-5C5B-B684-C82F34462171"><p>bind and enable theDMA interrupt(s). </p> </li></ol> <p>In the template port, <codeph>Create()</codeph> calls the base class <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-9B0C8C35-F149-3358-90B8-B4670CFE888F"><apiname>TDmac::Create()</apiname></xref> functionand then initialises the template specific channel object members (the temporarydescriptor fields used for appending requests to live channels), and performsplatform specific initialisation for the interrupt dispatch of DMA interruptevents: </p> <codeblock id="GUID-FBCC8132-129C-53A4-99B7-290B56C3035D" xml:space="preserve">TInt TTemplateDmac::Create()//// Second phase construction.// { TInt r = TDmac::Create(KInfo); // Base class Create() if (r == KErrNone) { __DMA_ASSERTA(ReserveSetOfDes(KChannelCount) == KErrNone); for (TInt i=0; i < KChannelCount; ++i) { TDmaDesc* pD = HdrToHwDes(*iFreeHdr); iChannels[i].iTmpDes = pD; iChannels[i].iTmpDesPhysAddr = DesLinToPhys(pD); iFreeHdr = iFreeHdr->iNext; } r = Interrupt::Bind(EAsspIntIdDma, Isr, this); if (r == KErrNone) { // TO DO: Map DMA clients (requests) to DMA channels here. r = Interrupt::Enable(EAsspIntIdDma); } } return r; } </codeblock> </li></ul> </section><section id="GUID-0DBA2E68-7759-5447-B34B-14F237369CB1"><title>Implement thechannel allocator</title> <p>Channel allocation is implemented in the PSL(platform-specific layer) because this is a hardware-specific operation. Thereare two basic options: </p> <ul><li id="GUID-A9246754-F21B-5BFC-9FDB-2CE5C92D1FA3"><p>Preallocate, at designtime, one channel per DMA-aware peripheral. This is the simplest approach,and it should be acceptable for most Symbian platform devices because theset of supported peripherals is closed. In this case, cookies passed by clientdevice drivers map uniquely to DMA channels. </p> </li><li id="GUID-C1164FA0-9B70-55C1-9C5A-2D02728FA67A"><p>Full dynamic allocation.This is a simple approach too, but DMA channels are, in general, not completelyidentical. For example, some channels may have greater priorities than others. </p> </li></ul> <p>Mixed schemes are also possible, for example, client device drivercookies could be used to select a subset of channels, and dynamic allocationused inside this subset. </p> <p>Whatever option is chosen, the PSL must providean implementation for the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-934F46B3-1DF9-3870-87EE-A8E2DEF82810"><apiname>DmaChannelMgr::Open()</apiname></xref>.The template implementation is: </p> <codeblock id="GUID-9C7F5850-F72B-5A16-9DA0-606FBABAB5F0" xml:space="preserve">TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)////// { __KTRACE_OPT(KDMA, Kern::Printf(">DmaChannelMgr::Open aOpenId=%d", aOpenId)); __DMA_ASSERTA(aOpenId < static_cast<TUint32>(KChannelCount)); TDmaChannel* pC = Controller.iChannels + aOpenId; if (pC->IsOpened()) pC = NULL; else { pC->iController = &Controller; pC->iPslId = aOpenId; } return pC; } </codeblock> <p>The template DMA channel manager returns a pointer toa DMA channel if the channel has not been previously allocated. Note thatsince channels possess preset priorities, the device drivers must be awareof which channel(s) they require DMA service from and configure the DMA controllerto route sources to allocated channels accordingly. </p> <p>The platform-specificcookies passed by client device drivers to the PSL must be defined somewhereso that client device drivers can access them. </p> </section><section id="GUID-6B35E9A7-11D6-5B26-B562-934169503412"><title>[Optionally]implement channel cleanup</title> <p>In the template PSL (platform-specificlayer), the function <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-909D795A-7303-3A76-9C8E-3B07A97DD716"><apiname>DmaChannelMgr::Close()</apiname></xref> is a no-operation.This function is called by the PIL (platform-independent layer) when clientdevice drivers call <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-8204AFBD-2A60-372E-B626-35BD19851FF7"><apiname>TDmaChannel::Close()</apiname></xref>. If the PSL needsto perform any hardware-specific operation when the channel is closed, thenthe implementation of <codeph>DmaChannelMgr::Close()</codeph> should be updatedto reflect that. </p> </section><section id="GUID-C9439F04-0BCC-5BC7-B18B-5C1B88515340"><title>Implement themandatory controller virtual functions</title> <p>The <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> classcontains several pure virtual functions that must be implemented by the PSL(platform-specific layer): </p> <ul><li id="GUID-FF533DDF-E4B1-5AD1-9CBD-19A1D94AB07D"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-81921A9D-41F5-34BC-B882-60CC4CD807FB"><apiname>TDmac::Transfer()</apiname></xref> </p> </li><li id="GUID-F6D6524A-09E3-54C0-AEB6-1D6BAB29210C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-B738D1B9-80FA-334D-ABEB-DFFF093E0B9D"><apiname>TDmac::StopTransfer()</apiname></xref> </p> </li><li id="GUID-6209F3C7-9E3C-58BF-ABA4-6DF4BBF44A82"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-7422834D-CE6B-32DB-A040-7762A8BAB7D7"><apiname>TDmac::IsIdle()</apiname></xref> </p> </li></ul> <p>These functions start and stop transfers on a DMA channel and arethe main interface between the PIL (platform-independent layer) and the PSL.The implementation of these functions depends on the hardware available forperforming DMA, and on the characteristics used to specify a DMA transfer: </p> <ul><li id="GUID-81DA9FED-18F0-5205-9597-33542B0CB3CC"><p>the source and destinationaddresses </p> </li><li id="GUID-D6684249-31CC-544B-8CEE-DD1D7FC8A8A1"><p>the burst size </p> </li><li id="GUID-91D910DB-E1D7-5993-9ADB-6823662249D0"><p>the maximum transfersize </p> </li><li id="GUID-C1926D7D-8349-5BA1-8E21-AB5D90486443"><p>the transfer width,i.e. number of bits per memory access </p> </li><li id="GUID-C091D505-1088-56CA-8630-F1099B0A2234"><p>the memory alignmentand endianness. </p> </li></ul> <p>The DMA Framework manages the transfer descriptors according to thedescriptor parameter passed into the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> constructorby the derived class constructor; the descriptor parameter is a <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-BBD2153C-4B41-357C-9299-D710930AFCBE"><apiname>TDmac::SCreateInfo</apiname></xref> structure.The per-request transfer parameters are passed into the descriptors for eachrequest issued by a driver. </p> <p><b>Thetransfer function: Transfer()</b> </p> <p>This function initiates a previouslyconstructed request on a specific channel. This is the template implementation: </p> <codeblock id="GUID-80B95C0E-B30D-5A10-8512-68317D404DB3" xml:space="preserve">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)); // TO DO (for instance): Load the first descriptor address into the DMAC and start it // by setting the RUN bit. (void) *pD, (void) i; } </codeblock> <p><b>Thestop transfer function: StopTransfer()</b> </p> <p>This function requiresthat the RUN mode is cleared. This is the template implementation: </p> <codeblock id="GUID-1BF7A5B4-2723-5A18-98E0-1F79A4928121" xml:space="preserve">void TTemplateDmac::StopTransfer(const TDmaChannel& aChannel)//// Stops a running channel.// { const TUint8 i = static_cast<TUint8>(aChannel.PslId()); __KTRACE_OPT(KDMA, Kern::Printf(">TTemplateDmac::StopTransfer channel=%d", i)); // TO DO (for instance): Clear the RUN bit of the channel. (void) i; } </codeblock> <p><b>Thefunction: IsIdle()</b> </p> <p> <codeph>IsIdle()</codeph> returns the stateof a given channel. This is the template implementation: </p> <codeblock id="GUID-C7CC986E-986B-5C5E-AA3D-86851131BE93" xml:space="preserve">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)); // TO DO (for instance): Return the state of the RUN bit of the channel. // The return value should reflect the actual state. (void) i; return ETrue; } </codeblock> </section><section id="GUID-A362A7CF-3674-525C-8114-485315E6594B"><title>Implement thenon-mandatory controller virtual functions</title> <p>The following auxiliaryfunctions are used to implement the scatter-gather transfer mode behaviourby creating and manipulating the linked list of transfer fragment headersthat describe a given scatter-gather transaction. They are called by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> baseclass functions when the instance of the <codeph>TDmac</codeph> derived classreports itself as being capable of scatter-gather operations. </p> <ul><li id="GUID-D401D7C8-B086-56CD-BAE0-96EEB0AA7E38"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-90AC3E58-E589-3F91-85F7-16A4ADFFFA69"><apiname>TDmac::InitHwDes()</apiname></xref> </p> </li><li id="GUID-58633367-FE56-53B7-A967-21828DA85F5C"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-05021B05-75DE-3F75-92C6-8B9445EB86D3"><apiname>TDmac::ChainHwDes()</apiname></xref> </p> </li><li id="GUID-94F81366-77D4-5AF6-9933-53E964863301"><p> <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> </p> </li></ul> <p><b>Firstscatter-gather support function: InitHwDes()</b> </p> <p>This is a functionfor creating a scatter-gather list. From the information in the passed-inrequest, the function sets up the descriptor with that fragment's: </p> <ul><li id="GUID-098E886D-D98D-5AC9-BB25-7FF8E6F0D05B"><p>source and destinationaddress </p> </li><li id="GUID-83440454-B955-55C8-BF10-DF86CDA0C466"><p>size </p> </li><li id="GUID-294D3B08-0A64-534D-858F-F43759A2DC59"><p>driver/DMA controllerspecific transfer parameters: memory/peripheral, burst size, transfer width. </p> </li></ul> <p>This is the template implementation: </p> <codeblock id="GUID-EB6F9C76-EC23-5464-A6C5-AB0B36717D2B" xml:space="preserve">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; } </codeblock> <p><b>Secondscatter-gather support function: ChainHwDes()</b> </p> <p>If the frameworkneeds to fragment the client’s request, for transfer size or memory discontiguousnessreasons, then the framework calls this function. It chains hardware descriptorstogether by setting the next pointer of the original descriptor to the physicaladdress of the descriptor to be chained. It assumes that the DMAC channelis quiescent when called. </p> <p>This is the template implementation: </p> <codeblock id="GUID-7979A1FB-5FA1-5078-8762-3874A62E6C63" xml:space="preserve">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)); // TO DO: Modify pD->iCmd so that no end-of-transfer interrupt gets raised any longer. pD->iDescAddr = DesLinToPhys(pN); }</codeblock> <p><b>Thirdscatter-gather support function: AppendHwDes()</b> </p> <p>This function iscalled by the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita"><apiname>TDmac</apiname></xref> base class when a driver request iscalled for a channel that is still active, i.e. where the intent is to providedata streaming so that the target device is constantly provided with data;for example, an audio device playing a track. In this case, the function providedby the derived class must: </p> <ul><li id="GUID-F94FBAA8-2A0D-5863-BA09-0EC1D61005A9"><p>stop the DMAC to preventany corruption of the scatter-gather list while appending the new fragmentdescriptor </p> </li><li id="GUID-AEF81B78-73D8-5B70-AFE4-0AEA7862CB74"><p>append the new descriptor </p> </li><li id="GUID-2304F2D4-833E-5F75-B88E-C794DF9D984E"><p>re-enable the channel,ideally before the target has detected the gap in service. </p> </li></ul> <p>This is the template implementation: </p> <codeblock id="GUID-18512439-C781-5267-ADBC-B9047942F800" xml:space="preserve">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; // TO DO: Implement the appropriate algorithm for appending a descriptor here. (void) *pD, (void) i; NKern::RestoreInterrupts(irq); __KTRACE_OPT(KDMA, Kern::Printf("<TTemplateDmac::AppendHwDes")); } </codeblock> </section><section id="GUID-F5968000-0C3E-5E53-A2D5-120B81F3140F"><title>Implement aninterrupt service routine</title> <p>The interrupt service routine needs todo the following: </p> <ul><li id="GUID-CE55E999-0886-5620-87BA-99A36D694FD4"><p>identify the channelthat raised the interrupt </p> </li><li id="GUID-02467F17-DC1E-552C-B1C2-D3C2CCE12347"><p>decide whether the interruptwas raised because of a successful data transfer or because of an error </p> </li><li id="GUID-0D5FDA57-A45E-54E5-A69C-64D22B916AB4"><p>call the base classfunction <codeph>TDmac::HandleIsr()</codeph>, which queues a DFC, or incrementsthe number of pending interrupts if a DFC is already queued. </p> </li></ul> <p>This is the template implementation: </p> <codeblock id="GUID-4CFCA5A1-9657-55F1-BE3C-AFF1F3974F80" xml:space="preserve">void TTemplateDmac::Isr(TAny* aThis)//// This ISR reads the interrupt identification and calls back into the base class// interrupt service handler with the channel identifier and an indication whether the// transfer completed correctly or with an error.// { TTemplateDmac& me = *static_cast<TTemplateDmac*>(aThis); // TO DO: Implement the behaviour described above, call HandleIsr(). HandleIsr(me.iChannels[5], 0); // Example } </codeblock> </section><section id="GUID-D7F410A1-DC70-515D-A00D-3955B534C62F"><title>Implement thetest support table and function</title> <p>The DMA Framework comes with atest harness that can be used to validate the port if the underlying DMA controllersupports memory to memory transfers. </p> <p>The test harness needs to knowabout the capabilities of the port being tested. The PSL provides the globalfunction <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> that returns a <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref> objectthat contains this information. In the template PSL, this structure is initialisedto binary zeroes. Before using the test harness, it must be initialised withvalid values. </p> <p>See <xref href="GUID-59EE15C1-19E7-3AA7-8339-A80CCC074D64.dita"><apiname>TDmaTestInfo</apiname></xref>, <xref href="GUID-3D0A9A03-E210-30EE-A1A1-7DA06E668CAA.dita"><apiname>DmaTestInfo()</apiname></xref> and <xref href="GUID-8552E66E-73D6-51DA-8F53-DDF437186CD6.dita">Validation</xref>. </p> </section><section id="GUID-D452D2CD-D251-50F4-818E-E7125501CE8F"><title>Optimise theperformance of critical functions</title> <p>You can optionally optimise criticalfunctions by writing them in assembler. The two candidates for an assemblerrewrite are: </p> <ul><li id="GUID-157E6F4A-0310-5923-B446-040F75E469D4"><p>The interrupt serviceroutine </p> </li><li id="GUID-74C9D4DB-9CA9-5C5E-A475-B6840EBC2245"><p>In scatter-gather mode,the <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-AFCDDA16-991D-3BDA-B90B-87BCAFF66E5C"><apiname>TDmac::AppendHwDes()</apiname></xref> function if it needs to suspenda transfer when appending a new descriptor chain to an existing one. </p> </li></ul> </section><section id="GUID-A2AF293F-558A-5F69-821F-EC2B202A5A4F"><title>Extend theframework with platform-specific functionality</title> <p>There are two waysof extending the DMA Framework: </p> <ol id="GUID-D6C660FC-FF23-55B2-B91E-4BC04C592059"><li id="GUID-4453F4C2-3444-5A3E-94C7-BE6320B1EF89"><p>to provide platform-specificfunctionality on a per-channel basis. </p> </li><li id="GUID-C0C6A072-134A-5753-A6DC-185F3975C2A6"><p>to provide platform-specificfunctionality on a <i>channel independent</i> basis. </p> </li></ol> <p>In the first case, the PSL provides an implementation of the virtualfunction <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. The default implementationjust returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-2CF7498E-F5D2-3C4A-8E98-47504F9FC404"><apiname>TDmaChannel::Extension()</apiname></xref> calls <xref href="GUID-25398075-927B-36E4-B953-16785EC4086C.dita#GUID-25398075-927B-36E4-B953-16785EC4086C/GUID-D6D011E9-9D75-3881-87D8-1986FFBBA106"><apiname>TDmac::Extension()</apiname></xref>. </p> <p>In the second case, the PSL provides an implementation of the staticfunction <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. The templatePSL implementation just returns <xref href="GUID-F89DA3F0-2A48-3F9B-8F08-29350E92D0E4.dita"><apiname>KErrNotSupported</apiname></xref>. </p> <p> <xref href="GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37.dita#GUID-83882548-FAC5-3EFF-92ED-14D1D9A85D37/GUID-75562653-1F27-39D3-96D8-55A94BA9B68B"><apiname>TDmaChannel::StaticExtension()</apiname></xref> calls <xref href="GUID-176B8E0D-0422-341B-A134-7C85432E1303.dita#GUID-176B8E0D-0422-341B-A134-7C85432E1303/GUID-C733B302-4269-3391-8ADE-617CFF198B56"><apiname>DmaChannelMgr::StaticExtension()</apiname></xref>. </p> </section></conbody></concept>