diff -r 578be2adaf3e -r 307f4279f433 Adaptation/GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10-GENID-1-2-1-9-1-6-1-8-1-7-1-6-1.dita --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Adaptation/GUID-C74770A5-ADD4-4AB1-946F-77105E2B8C10-GENID-1-2-1-9-1-6-1-8-1-7-1-6-1.dita Fri Oct 15 14:32:18 2010 +0100 @@ -0,0 +1,167 @@ + + + + + +DMA Request OperationsDescribes 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 must be split into different fragments that are +small enough to be transferred by the DMAC in a single transaction. +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. 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

This is done by the DMA service callback function. +The completion notification is as follows:

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.

/** + 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. + ... + } + }
+
+DMA +Requests +
\ No newline at end of file