diff -r 89d6a7a84779 -r 25a17d01db0c Symbian3/PDK/Source/GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/PDK/Source/GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10.dita Fri Jan 22 18:26:19 2010 +0000 @@ -0,0 +1,165 @@ + + + + + +DMA +Request OperationsThis document describes the operations which a device driver performs +on a DMA request. +

After doing the required DMA initialisation, a driver can start a DMA operation. +To do this, the driver fragments the request and then queues the request.

+
Fragment

A +DMA request can be split into different fragments that are small enough to +be sent to DMAC. The size of each fragment is smaller than or equal to the +maximum transfer size supported by the DMAC. To fragment a DMA request, a +source and destination address, and the size of data to be transferred, must +be provided. If the source and/or destination is in memory, each fragment +points to memory which is physically contiguous.

The kind of transfer +to perform is specified using a set of flags and hardware-specific information. +The flags can be:

+ + + +

KDmaMemSrc

+

Source is the address of a memory buffer

+
+ +

KDmaMmeDest

+

Destination is the address of a memory buffer

+
+ +

KDmaIncSrc

+

Source address must be post-incremented during transfer

+
+ +

KDmaIncDest

+

Destination address must be post-incremented during transfer

+
+ +

KDmaPhysAddrSrc

+

Source address is a physical address (as opposed to a linear one)

+
+ +

KDmaPhysAddrDest

+

Destination address is a physical address (as opposed to a linear +one)

+
+ + +

The following shows an example of fragmenting a DMA request:

/** + Start the DMA transfer. This function fragments the DMA request and + queues it for processing and actually triggers the DMA transfer. + + @param aSource + Source address for DMA transfer + + @param aCount + Size of data to be transferred + + @return KErrNone on success, else standard error code on failure + */ +TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount) + { + ... + // Fragment the DMA request. DDmaRequest::Fragment() creates + // the DMA descriptor with source, destination address, size + // and attributes. + // + // Flags KDmaMemSrc|KDmaIncSrc or KDmaMemDest|KDmaIncDest + // should be set if the source/destination is a memory buffer, + // or cleared if the source/destination is a peripheral. If the address + // specified is physical address instead of linear, + // then specify KDmaPhysAddrSrc or KDmaPhysAddrDest accordingly. + // + TInt retval = iTxDmaRequest->Fragment((TUint32)buf, + (TUint32)(iUartComm->iPortAddr + KHoUART_THR), aCount, + KDmaMemSrc |KDmaIncSrc, // source is a buffer + 0 ); // no HW Flags + if(retval != KErrNone) + { + return retval; + } + ... + }
+
Queue

DMA transfer is initiated by queuing the +DMA request. A device driver queues the request by calling DDmaRequest::Queue() after +fragmenting the DMA request. This is an asynchronous call and the transfer +of DMA will actually start once the request is scheduled.

/** + Start the DMA transfer. This function fragments the DMA request and + queues it for processing and actually triggers the DMA transfer. + @param aSource Source address for DMA transfer + @param aCount Size of data to be transferred + @return KErrNone on success, else standard error code on failure + */ +TInt DExDriverUartTxDma::Start(const TUint8* aSource, TInt aCount) + { + ... + + // Queue the DMA request. DDmaRequest::Queue() queues the + // request on the DFCQ. When it is processed, the SDMAC driver calls + // the helper ChannelTransfer() to start the transfer on the + // device. DMA operation starts at this point. + // + iTxDmaRequest->Queue(); + + ... + }

If the request channel is idle when a request is queued, +the request is transferred immediately. Otherwise, it is queued and transferred +later. The client is responsible for ensuring cache consistency before and/or +after the transfer if necessary.

+
Completion notification

Once the DMA request is +handled by the DMAC, the DMA service callback function is called by the DMA +driver. This runs in a DFC context, that is scheduled from a DMA interrupt +service routine.

The DMA service callback function pointer must be +provided while creating the DMA request:

iTxDmaRequest = new DDmaRequest(*iTxDmaChannel, TxDmaService, this);

The DMA callback function is called for both success and failure of the +request, so it needs to check the request result. On success, the function +should either initiate another DMA request, or stop DMA and close the request. +On failure, the function should stop DMA by cancelling the request.

/** + DMA service callback function for transmit. This static function is + called on the completion of DMA transfer request. This function + pointer is provided while creating the DMA request, i.e. in + DDmaRequest(). After the request is queued, the System DMA controller + completes the request and calls this service function. Here, we do + the processing that needs to be done post the DMA request + completion. + + This function shall be called both when the DMA request succeeds or fails, + so both must be handled appropriately. + + @param aResult + DMA result, can be DDmaRequest::EOk in case of success, else error + + @param aArg pointer passed at time of registration, typically <this> + pointer + + @return none + */ +static void TxDmaService(DDmaRequest::TResult aResult, TAny* aArg) + { + // Check the result of DMA service function call. It can be + // either of the DDmaRequest::TResult enumerated values. + // + if ( aResult != DDmaRequest::EOk) + { + // DMA request failed, so stop the DMA. + Stop (); + + // Notify request completion with an error result + ... + } + else + { + // DMA request was successful. + // The program can start another DMA request, or stop + // the DMA, if no more DMA requests are needed. + // Notify request operation complete with success. + ... + } + }
+
\ No newline at end of file