summaryrefslogtreecommitdiff
path: root/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c')
-rw-r--r--arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c2750
1 files changed, 2750 insertions, 0 deletions
diff --git a/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c
new file mode 100644
index 000000000000..f14d19d1bd60
--- /dev/null
+++ b/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c
@@ -0,0 +1,2750 @@
+/******************************************************************************
+ *
+ * Copyright 2007-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ ******************************************************************************
+ *
+ * File: iapiHigh.c
+ *
+ * $Id iapiHigh.c $
+ *
+ * Description:
+ * This library is written in C to guarantee functionality and integrity in
+ * the usage of SDMA virtual DMA channels. This API (Application Programming
+ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
+ * fashion.
+ * These are the HIGH level functions of the I.API.
+ *
+ *
+ * /
+ *
+ * $Log iapiHigh.c $
+ *
+ *****************************************************************************/
+
+/* ****************************************************************************
+ * Include File Section
+ *****************************************************************************/
+#include <stdarg.h>
+#include <string.h>
+
+#include "epm.h"
+#include "iapi.h"
+
+/* ****************************************************************************
+ * External Reference Section (for compatibility with already developed code)
+ *****************************************************************************/
+static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p,
+ void *data);
+
+/* ****************************************************************************
+ * Global Variable Section
+ *****************************************************************************/
+#define MAX_CHANNEL 32
+
+static dataNodeDescriptor *dnd_read_control_struct[MAX_CHANNEL];
+
+/* MASK to get Nullify all the bits of Status in Data Node descriptor apart from L, E and D*/
+
+#define GET_LED_MASK 0xE0
+
+/*Table defines mapping of Data Node Descriptor to Buffer Descriptor status*/
+
+static unsigned char dnd_2_bd_status[] = {
+ 0x85, /*00 L = 0, E = 0, D = 0 */
+ 0x00, /*01 */
+ 0x00, /*02 */
+ 0x00, /*03 */
+ 0x00, /*04 */
+ 0x00, /*05 */
+ 0x00, /*06 */
+ 0x00, /*07 */
+ 0x00, /*08 */
+ 0x00, /*09 */
+ 0x00, /*0A */
+ 0x00, /*0B */
+ 0x00, /*0C */
+ 0x00, /*0D */
+ 0x00, /*0E */
+ 0x00, /*0F */
+ 0x00, /*10 */
+ 0x00, /*11 */
+ 0x00, /*12 */
+ 0x00, /*13 */
+ 0x00, /*14 */
+ 0x00, /*15 */
+ 0x00, /*16 */
+ 0x00, /*17 */
+ 0x00, /*18 */
+ 0x00, /*19 */
+ 0x00, /*1A */
+ 0x00, /*1B */
+ 0x00, /*1C */
+ 0x00, /*1D */
+ 0x00, /*1E */
+ 0x00, /*1F */
+ 0x84, /*20 L = 0, E = 0, D = 1 */
+ 0x00, /*21 */
+ 0x00, /*22 */
+ 0x00, /*23 */
+ 0x00, /*24 */
+ 0x00, /*25 */
+ 0x00, /*26 */
+ 0x00, /*27 */
+ 0x00, /*28 */
+ 0x00, /*29 */
+ 0x00, /*2A */
+ 0x00, /*2B */
+ 0x00, /*2C */
+ 0x00, /*2D */
+ 0x00, /*2E */
+ 0x00, /*2F */
+ 0x00, /*30 */
+ 0x00, /*31 */
+ 0x00, /*32 */
+ 0x00, /*33 */
+ 0x00, /*34 */
+ 0x00, /*35 */
+ 0x00, /*36 */
+ 0x00, /*37 */
+ 0x00, /*38 */
+ 0x00, /*39 */
+ 0x00, /*3A */
+ 0x00, /*3B */
+ 0x00, /*3C */
+ 0x00, /*3D */
+ 0x00, /*3E */
+ 0x00, /*3F */
+ 0xAB, /*40 L = 0, E = 1, D = 0 */
+ 0x00, /*41 */
+ 0x00, /*42 */
+ 0x00, /*43 */
+ 0x00, /*44 */
+ 0x00, /*45 */
+ 0x00, /*46 */
+ 0x00, /*47 */
+ 0x00, /*48 */
+ 0x00, /*49 */
+ 0x00, /*4A */
+ 0x00, /*4B */
+ 0x00, /*4C */
+ 0x00, /*4D */
+ 0x00, /*4E */
+ 0x00, /*4F */
+ 0x00, /*50 */
+ 0x00, /*51 */
+ 0x00, /*52 */
+ 0x00, /*53 */
+ 0x00, /*54 */
+ 0x00, /*55 */
+ 0x00, /*56 */
+ 0x00, /*57 */
+ 0x00, /*58 */
+ 0x00, /*59 */
+ 0x00, /*5A */
+ 0x00, /*5B */
+ 0x00, /*5C */
+ 0x00, /*5D */
+ 0x00, /*5E */
+ 0x00, /*5F */
+ 0xAA, /*60 L = 0, E = 1, D = 1 */
+ 0x00, /*61 */
+ 0x00, /*62 */
+ 0x00, /*63 */
+ 0x00, /*64 */
+ 0x00, /*65 */
+ 0x00, /*66 */
+ 0x00, /*67 */
+ 0x00, /*68 */
+ 0x00, /*69 */
+ 0x00, /*6A */
+ 0x00, /*6B */
+ 0x00, /*6C */
+ 0x00, /*6D */
+ 0x00, /*6E */
+ 0x00, /*6F */
+ 0x00, /*70 */
+ 0x00, /*71 */
+ 0x00, /*72 */
+ 0x00, /*73 */
+ 0x00, /*74 */
+ 0x00, /*75 */
+ 0x00, /*76 */
+ 0x00, /*77 */
+ 0x00, /*78 */
+ 0x00, /*79 */
+ 0x00, /*7A */
+ 0x00, /*7B */
+ 0x00, /*7C */
+ 0x00, /*7D */
+ 0x00, /*7E */
+ 0x00, /*7F */
+ 0xC5, /*80 L = 1, E = 0, D = 0 */
+ 0x00, /*81 */
+ 0x00, /*82 */
+ 0x00, /*83 */
+ 0x00, /*84 */
+ 0x00, /*85 */
+ 0x00, /*86 */
+ 0x00, /*87 */
+ 0x00, /*88 */
+ 0x00, /*89 */
+ 0x00, /*8A */
+ 0x00, /*8B */
+ 0x00, /*8C */
+ 0x00, /*8D */
+ 0x00, /*8E */
+ 0x00, /*8F */
+ 0x00, /*90 */
+ 0x00, /*91 */
+ 0x00, /*92 */
+ 0x00, /*93 */
+ 0x00, /*94 */
+ 0x00, /*95 */
+ 0x00, /*96 */
+ 0x00, /*97 */
+ 0x00, /*98 */
+ 0x00, /*99 */
+ 0x00, /*9A */
+ 0x00, /*9B */
+ 0x00, /*9C */
+ 0x00, /*9D */
+ 0x00, /*9E */
+ 0x00, /*9F */
+ 0xC4, /*A0 L = 1, E = 0, D = 1 */
+ 0x00, /*A1 */
+ 0x00, /*A2 */
+ 0x00, /*A3 */
+ 0x00, /*A4 */
+ 0x00, /*A5 */
+ 0x00, /*A6 */
+ 0x00, /*A7 */
+ 0x00, /*A8 */
+ 0x00, /*A9 */
+ 0x00, /*AA*/ 0x00, /*AB*/ 0x00, /*AC*/ 0x00, /*AD*/ 0x00, /*AE*/ 0x00, /*AF*/ 0x00, /*B0 */
+ 0x00, /*B1 */
+ 0x00, /*B2 */
+ 0x00, /*B3 */
+ 0x00, /*B4 */
+ 0x00, /*B5 */
+ 0x00, /*B6 */
+ 0x00, /*B7 */
+ 0x00, /*B8 */
+ 0x00, /*B9 */
+ 0x00, /*BA*/ 0x00, /*BB*/ 0x00, /*BC*/ 0x00, /*BD*/ 0x00, /*BE*/ 0x00, /*BF*/ 0xEB, /*C0 L = 1, E = 1, D = 0 */
+ 0x00, /*C1 */
+ 0x00, /*C2 */
+ 0x00, /*C3 */
+ 0x00, /*C4 */
+ 0x00, /*C5 */
+ 0x00, /*C6 */
+ 0x00, /*C7 */
+ 0x00, /*C8 */
+ 0x00, /*C9 */
+ 0x00, /*CA*/ 0x00, /*CB*/ 0x00, /*CC*/ 0x00, /*CD*/ 0x00, /*CE*/ 0x00, /*CF*/ 0x00, /*D0 */
+ 0x00, /*D1 */
+ 0x00, /*D2 */
+ 0x00, /*D3 */
+ 0x00, /*D4 */
+ 0x00, /*D5 */
+ 0x00, /*D6 */
+ 0x00, /*D7 */
+ 0x00, /*D8 */
+ 0x00, /*D9 */
+ 0x00, /*DA*/ 0x00, /*DB*/ 0x00, /*DC*/ 0x00, /*DD*/ 0x00, /*DE*/ 0x00, /*DF*/ 0xEA, /*E0 L = 1, E = 1, D = 1 */
+ 0x00, /*E1 */
+ 0x00, /*E2 */
+ 0x00, /*E3 */
+ 0x00, /*E4 */
+ 0x00, /*E5 */
+ 0x00, /*E6 */
+ 0x00, /*E7 */
+ 0x00, /*E8 */
+ 0x00, /*E9 */
+ 0x00, /*EA*/ 0x00, /*EB*/ 0x00, /*EC*/ 0x00, /*ED*/ 0x00, /*EE*/ 0x00, /*EF*/ 0x00, /*F0 */
+ 0x00, /*F1 */
+ 0x00, /*F2 */
+ 0x00, /*F3 */
+ 0x00, /*F4 */
+ 0x00, /*F5 */
+ 0x00, /*F6 */
+ 0x00, /*F7 */
+ 0x00, /*F8 */
+ 0x00, /*F9 */
+ 0x00, /*FA*/
+ 0x00, /*FB*/ 0x00, /*FC*/ 0x00, /*FD*/ 0x00, /*FE*/ 0x00 /*FF*/
+};
+
+/* ****************************************************************************
+ * Function Section
+ *****************************************************************************/
+
+/* ***************************************************************************/
+/**Opens an SDMA channel to be used by the library.
+ *
+ * <b>Algorithm:</b>\n
+ *
+ * - Check if initialization is necessary.
+ * - Check that user initialized OS dependant functions.
+ * - Test validity of input parameters
+ * - Check whole channel control block data structure
+ * - Finish initializations (tables with default values)
+ * - Initialize channel 0 is dedicated to communications with SDMA
+ * - Check channel control block definition
+ * - if the channel descriptor is not initialized, initialize it with
+ * the default value
+ * - If buffer descriptor already allocated, exit with iapi_errno filled
+ * complete the lowest bits with the number of 'D' bits set
+ * - Buffer Descriptors allocation
+ * - Channel's configuration properties (mcu side only)
+ * - read/write direction => enable/disable channel setting
+ *
+ * @param *cd_p -If channelNumber is 0, it is pointer to channel descriptor for the channnel 0 to be opened and
+ * has default values.
+ * For other channels,this function should be called after channel 0 has been opened, and it is channel descriptor for
+ * channel 0.Must be allocated.
+ * @param channelNumber channel to be opened
+ *
+ * @return
+ * - IAPI_SUCCESS : OK
+ * - -iapi_errno : close failed, return negated value of iapi_errno
+ */
+int iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber)
+{
+ channelControlBlock *ccb_p;
+ channelControlBlock *local_ccb_p;
+ channelDescriptor *local_cd_p;
+ bufferDescriptor *bd_p;
+ unsigned char index = 0;
+ int result = IAPI_SUCCESS;
+#ifdef MCU
+ volatile unsigned long *channelPriorityMatx;
+#endif /* MCU */
+
+ /*
+ * 1. Check if initialization is necessary
+ */
+ if (cd_p == NULL) {
+ result = IAPI_ERR_CD_UNINITIALIZED |
+ IAPI_ERR_CH_AVAILABLE | channelNumber;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Verify these functions every time */
+ if ((iapi_GetChannel == NULL) || (iapi_ReleaseChannel == NULL)) {
+ result = IAPI_ERR_NO_OS_FN | channelNumber;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Try to aquire channel */
+ if (iapi_GetChannel(channelNumber) != 0) {
+ result = IAPI_ERR_CH_IN_USE | channelNumber;
+ iapi_errno = result;
+ return -result;
+ }
+
+ if (channelNumber == 0 && cd_p->ccb_ptr == NULL) {
+ /* Verify that the user initialized all OS dependant functions required
+ * by the library.
+ */
+ if ((iapi_Malloc == NULL) || (iapi_Free == NULL)
+ || (iapi_Virt2Phys == NULL) || (iapi_Phys2Virt == NULL)
+ || (iapi_GotoSleep == NULL) || (iapi_WakeUp == NULL)
+ || (iapi_InitSleep == NULL) || (iapi_memset == NULL)
+ || (iapi_memcpy == NULL)) {
+ result = IAPI_ERR_NO_OS_FN | channelNumber;
+ iapi_errno = result;
+ iapi_ReleaseChannel(channelNumber);
+ return -result;
+ }
+ /* Whole channel control block data structure */
+ ccb_p = (channelControlBlock *)
+ MALLOC(CH_NUM * sizeof(channelControlBlock), SDMA_IRAM);
+ if (ccb_p == NULL) {
+ result = IAPI_ERR_CCB_ALLOC_FAILED |
+ IAPI_ERR_CH_AVAILABLE | channelNumber;
+ iapi_errno = result;
+ iapi_ReleaseChannel(channelNumber);
+ return -result;
+ }
+ /* Zero-out the CCB structures array just allocated */
+ iapi_memset(ccb_p, 0x00, CH_NUM * sizeof(channelControlBlock));
+ /* Save the address of the CCB structures array */
+ iapi_CCBHead = ccb_p;
+
+ cd_p->ccb_ptr = (struct iapi_channelControlBlock *)ccb_p;
+ ccb_p->channelDescriptor = cd_p;
+#ifdef MCU
+ /* finish initializations */
+ iapi_InitChannelTables();
+#endif /* MCU */
+ /* Channel 0 is dedicated to communications with SDMA */
+ cd_p->ownership = ((DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
+ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
+ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
+ cd_p->bufferDescNumber = 1;
+ }
+
+ /*
+ * 2. Check channel control block
+ */
+ ccb_p = cd_p->ccb_ptr;
+ if (ccb_p == NULL) {
+ result =
+ IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE |
+ channelNumber;
+ iapi_errno = result;
+ iapi_ReleaseChannel(channelNumber);
+ return -result;
+ }
+
+ /* Control block & Descriptor associated with the channel being worked on */
+ local_ccb_p = &ccb_p[channelNumber];
+ local_cd_p = ccb_p[channelNumber].channelDescriptor;
+
+ /* If the channel is not initialized, initialize it with the default value */
+ if (local_cd_p == NULL) {
+ result = iapi_AllocChannelDesc(&local_cd_p, channelNumber);
+ if (result != IAPI_SUCCESS) {
+ iapi_ReleaseChannel(channelNumber);
+ /* is allready negated from iapi_AllocChannelDesc */
+ return result;
+ }
+
+ local_cd_p->ccb_ptr =
+ (struct iapi_channelControlBlock *)local_ccb_p;
+ local_ccb_p->channelDescriptor = local_cd_p;
+ }
+
+ /*
+ * 3. If buffer descriptor already allocated, exit with iapi_errno filled
+ */
+ if (local_ccb_p->baseBDptr != NULL) {
+ bd_p =
+ (bufferDescriptor *) iapi_Phys2Virt(local_ccb_p->baseBDptr);
+ result = IAPI_ERR_BD_ALLOCATED;
+ for (index = 1; index < local_cd_p->bufferDescNumber; index++) {
+ if ((bd_p->mode.status & BD_DONE) == BD_DONE) {
+ /* complete the lowest bits with the number of 'D' bits set */
+ result++;
+ }
+ bd_p++;
+ }
+ iapi_errno = result;
+ iapi_ReleaseChannel(channelNumber);
+ return -result;
+ }
+
+ /*
+ * 4. Buffer Descriptors allocation
+ */
+ iapi_InitializeMemory(local_ccb_p);
+
+#ifdef MCU
+ /*
+ * 5. Channel's configuration properties (mcu side only)
+ */
+ iapi_ChannelConfig(channelNumber,
+ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_EVT) &
+ 1UL,
+ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_MCU) &
+ 1UL,
+ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_DSP) &
+ 1UL);
+#endif /* MCU */
+
+ /* Setting interrupt handling */
+ iapi_ChangeCallbackISR(local_cd_p, local_cd_p->callbackISR_ptr);
+
+ /* Call initialization fn for polling synch on this channel */
+ INIT_SLEEP(channelNumber);
+
+ /* No user arg pointer yet */
+ userArgTable[cd_p->channelNumber] = NULL;
+
+ /*
+ * 6. read/write direction => enable/disable channel
+ */
+#ifdef MCU
+ channelPriorityMatx = &SDMA_CHNPRI_0;
+ channelPriorityMatx[channelNumber] = 1;
+#endif /* MCU */
+
+ local_ccb_p->status.openedInit = TRUE;
+ iapi_ReleaseChannel(channelNumber);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/** Attempts to read nbyte from the data buffer descriptor associated with the
+ * channel channelNumber, into the user's data buffer pointed to by buf.
+ *
+ * <b>Algorithm:</b>\n
+ * - Check data structures are properly initialized:
+ * - Channel descriptor validity
+ * - Control block & Descriptor associated with the channel being worked on
+ * - Check initialization has been done for trusted channels
+ * - If transfer data size is used, check validity of combination transfer
+ * size/requested bytes
+ * - Set the 'D' done bits on all buffer descriptors
+ * - Starting of the channel
+ * - Synchronization mechanism handling:
+ * - for callback: just exit function
+ * - for polling: call the synchronization function then read data from
+ * buffer until either nbyte parameter is reached or all buffer descriptors
+ * have been processed.
+ *
+ * <b>Notes:</b>\n
+ * 1) Virtual DMA SDMA channels are unidirectional, an iapi_Read authorized
+ * on a channel means that we are expecting to receive from the SDMA. The
+ * meaning of an interrupt received from the SDMA is therefore that the
+ * data has been copied from the SDMA to the host's data buffers and is
+ * already passed on upper layers of the application.\n
+ *
+ * @param *cd_p chanenl descriptor for the channel to read from
+ * @param *buf buffer to receive the data
+ * @param nbyte number of bytes to read from channel
+ *
+ * @return
+ * - number of bytes read
+ * - -iapi_errno : in case of failure return negated value of iapi_errno
+ */
+int iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte)
+{
+ int index = 0;
+ int readBytes;
+ int toRead;
+ int result = IAPI_SUCCESS;
+ unsigned int copyFinished;
+ int bufsize;
+ bufferDescriptor *bd_p;
+ channelControlBlock *ccb_p;
+ unsigned char *local_buf;
+ unsigned char chNum;
+ unsigned char div;
+
+ iapi_errno = IAPI_ERR_NO_ERROR;
+
+ /*
+ * 1. Check data structures are properly initialized
+ */
+ /* Channel descriptor validity */
+ if (cd_p == NULL) {
+ result = IAPI_ERR_CD_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Channel control block validity */
+ if (cd_p->ccb_ptr == NULL) {
+ result = IAPI_ERR_CCB_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Control block & Descriptor associated with the channel being worked on */
+ chNum = cd_p->channelNumber;
+ ccb_p = cd_p->ccb_ptr;
+
+ /* Try to aquire channel */
+ if (iapi_GetChannel(chNum) != 0) {
+ result = IAPI_ERR_CH_IN_USE | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Check if channel is already opened/initialized */
+ if (ccb_p->status.openedInit == FALSE) {
+ result =
+ IAPI_ERR_CHANNEL_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE |
+ chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+
+ /* Buffer descriptor validity */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ if (bd_p == NULL) {
+ result =
+ IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+
+ /* Check initialization has been done for trusted channels */
+ if (cd_p->trust == TRUE) {
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if ((bd_p->bufferAddr == NULL)
+ || (bd_p->mode.count == 0)) {
+ result =
+ IAPI_ERR_BD_UNINITIALIZED |
+ IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ }
+
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ /*If transfer data size is used, check that the required read length is
+ * divisible by transfer data size expressed in bytes
+ */
+ if (cd_p->useDataSize) {
+ /*Check for divisibility only if data size different then 8bit */
+ if (cd_p->dataSize != TRANSFER_8BIT) {
+ switch (cd_p->dataSize) {
+ case TRANSFER_32BIT:
+ div = 4;
+ break;
+ case TRANSFER_16BIT:
+ div = 2;
+ break;
+ case TRANSFER_24BIT:
+ div = 3;
+ break;
+ /*we should not get to default */
+ default:
+ result = IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ /*check the total number of bytes requested */
+ if ((nbyte % div) != 0) {
+ result = IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ /*now check the length of every BD */
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if ((bd_p->mode.count % div) != 0) {
+ result =
+ IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ }
+ }
+
+ /*
+ * 2. Set the 'D' done bits on all buffer descriptors
+ */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ bd_p->mode.status |= BD_DONE;
+ bd_p++;
+ }
+
+ /*
+ * 3. Starting of the channel
+ */
+ iapi_lowStartChannel(chNum);
+ ccb_p->status.execute = TRUE;
+ readBytes = 0;
+
+ /*
+ * 4. Synchronization mechanism handling
+ */
+ if (cd_p->callbackSynch == DEFAULT_POLL) {
+ iapi_SynchChannel(chNum);
+
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ toRead = nbyte;
+ copyFinished = FALSE;
+ local_buf = (unsigned char *)buf;
+
+ /*
+ * Check the 'RROR' bit on all buffer descriptors, set error number
+ * and return IAPI_FAILURE if set.
+ */
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if (bd_p->mode.status & BD_RROR) {
+ result = IAPI_ERR_RROR_BIT_READ | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+
+ /*
+ * 5. Read loop
+ */
+
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ while (!copyFinished) {
+ if (!(bd_p->mode.status & BD_DONE)) {
+ if (cd_p->trust == FALSE) {
+ bufsize = cd_p->bufferSize;
+ } else {
+ bufsize = bd_p->mode.count;
+ }
+ /*if L bit is set, read only "count" bytes and exit the loop */
+ if (bd_p->mode.status & BD_LAST) {
+ bufsize = bd_p->mode.count;
+ copyFinished = TRUE;
+ }
+ if (toRead > bufsize) {
+ if (cd_p->trust == FALSE) {
+ iapi_memcpy(local_buf,
+ iapi_Phys2Virt
+ (bd_p->bufferAddr),
+ bufsize);
+ local_buf += bufsize;
+ }
+ readBytes += bufsize;
+ toRead -= bufsize;
+ /*advance bd_p only if bit L is not set. The loop will exit anyway. */
+ if (!(bd_p->mode.status & BD_LAST)) {
+ if (bd_p->mode.status & BD_WRAP) {
+ bd_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt
+ (ccb_p->baseBDptr);
+ } else if (((bufferDescriptor *)
+ iapi_Phys2Virt
+ (ccb_p->baseBDptr)
+ +
+ (cd_p->bufferDescNumber
+ -
+ 1) *
+ sizeof
+ (bufferDescriptor))
+ != bd_p) {
+ bd_p++;
+ } else {
+ /* finished here : end of buffer descriptors */
+ copyFinished = TRUE;
+ }
+ }
+ } else {
+ if (cd_p->trust == FALSE) {
+ iapi_memcpy(local_buf,
+ iapi_Phys2Virt
+ (bd_p->bufferAddr),
+ toRead);
+ local_buf += toRead;
+ }
+ readBytes += toRead;
+ toRead = 0;
+ /* finished successfully : readBytes = nbytes */
+ copyFinished = TRUE;
+ }
+ } else {
+ /* finished here : buffer not already done */
+ copyFinished = TRUE;
+ }
+ }
+ iapi_ReleaseChannel(chNum);
+ }
+
+ /*
+ *If synchronization type is callback, the user of I.API must
+ *release the channel
+ */
+ return readBytes;
+}
+
+/* ***************************************************************************/
+/*Attempts to write nbyte from the buffer pointed to by buf to the channel
+ * data buffers associated with the opened channel number channelNumber
+ *
+ * <b>Algorithm:</b>\n
+ *
+ * - Check data structures are properly initialized:
+ * - Channel descriptor validity
+ * - Channel control block validity
+ * - Buffer descriptor validity
+ * - If transfer data size is used, check validity of combination transfer
+ * size/requested bytes
+ * - Write loop\n
+ * Write occurs in the buffer acceded form buffer descriptor and continues
+ * to the "next" buffer which can be:\n
+ * -# the last BD of the ring so re-start from beginning\n
+ * -# the last BD of the BD array but no ring so finish\n
+ * -# (general case) the next BD in the BD array\n
+ * And copy continues until data fit in the current buffer or the nbyte
+ * parameter is reached.
+ * - Starting of the channel
+ *
+ * <b>Notes:</b>\n
+ * 1) Virtual DMA SDMA channels are unidirectionnal, an iapi_Write authorized
+ * on a channel means that we are expecting to send to the SDMA. The
+ * meaning of an interrupt received from the SDMA is therfore that the
+ * data has been delivered to the SDMA.
+ *
+ * @param *cd_p chanenl descriptor for the channel to write to
+ * @param *buf buffer with data to be written
+ * @param nbyte number of bytes to write to channel
+ *
+ * @return
+ * - number of bytes written
+ * - -iapi_errno if failure
+ */
+int iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte)
+{
+ unsigned int writtenBytes = 0;
+ unsigned int toWrite;
+ int result = IAPI_SUCCESS;
+ unsigned int copyFinished;
+ unsigned int buffsize;
+ unsigned int index = 0;
+ bufferDescriptor *bd_p;
+ channelControlBlock *ccb_p;
+ unsigned char *local_buf;
+ unsigned char chNum;
+ unsigned char div;
+
+ iapi_errno = IAPI_ERR_NO_ERROR;
+
+ /*
+ * 1. Check data structures are properly initialized
+ */
+ /* Channel descriptor validity */
+ if (cd_p == NULL) {
+ result = IAPI_ERR_CD_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Channel control block validity */
+ if (cd_p->ccb_ptr == NULL) {
+ result = IAPI_ERR_CCB_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Control block & Descriptpor associated with the channel being worked on */
+ chNum = cd_p->channelNumber;
+ ccb_p = cd_p->ccb_ptr;
+
+ /* Try to aquire channel */
+ if (iapi_GetChannel(chNum) != 0) {
+ result = IAPI_ERR_CH_IN_USE | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Buffer descriptor validity */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ if (bd_p == NULL) {
+ result =
+ IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+
+ /* Check initialization has been done for trusted channels */
+ if (cd_p->trust == TRUE) {
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if ((bd_p->bufferAddr == NULL)
+ || (bd_p->mode.count == 0)) {
+ result =
+ IAPI_ERR_BD_UNINITIALIZED |
+ IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ }
+
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ /*If transfer data size is used, check that the required write length is
+ * divisible by transfer data size expressed in bytes
+ */
+ if (cd_p->useDataSize) {
+ /*Check for divisibility only if data size different then 8bit */
+ if (cd_p->dataSize != TRANSFER_8BIT) {
+ switch (cd_p->dataSize) {
+ case TRANSFER_32BIT:
+ div = 4;
+ break;
+ case TRANSFER_16BIT:
+ div = 2;
+ break;
+ case TRANSFER_24BIT:
+ div = 3;
+ break;
+ /*we should not get to default */
+ default:
+ result = IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ /*check the total number of bytes requested */
+ if ((nbyte % div) != 0) {
+ result = IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ /*now check the length of every BD */
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if ((bd_p->mode.count % div) != 0) {
+ result =
+ IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ }
+ }
+
+ /*
+ * 2. Write loop
+ */
+
+ local_buf = (unsigned char *)buf;
+ toWrite = nbyte;
+ copyFinished = FALSE;
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+
+ while (!copyFinished) {
+
+ /* variable buffsize contains the nb of bytes that the SDMA will transfer at each pass of the while loop */
+
+ /* in NON trusted mode, buffsize is copied from Channel descriptor bufferSize (same size for all transfers) */
+ if (cd_p->trust == FALSE) {
+ buffsize = cd_p->bufferSize;
+ }
+ /* in TRUSTED mode, it's up to the user to specify the size of each buffer thru an IoCtl call */
+ /* This IoCtl has directly modified the bd_p->mode.count */
+ /* therefore, buffersize is copied from the bd_p->mode.count */
+ else {
+ buffsize = bd_p->mode.count;
+ }
+
+ /* in any mode (trusted or non trusted), the transfer size must be overridden by */
+ /* "toWrite" when there is less remaining bytes to transfer than the current buffer size */
+ if (toWrite < buffsize) {
+ buffsize = toWrite;
+ }
+
+ if (!(bd_p->mode.status & BD_DONE)) {
+ /* More data to write than a single buffer can contain */
+ if (cd_p->trust == FALSE) {
+ iapi_memcpy(iapi_Phys2Virt(bd_p->bufferAddr),
+ local_buf, buffsize);
+ local_buf += buffsize;
+ }
+
+ /* update the BD count that will be used by the SDMA to transfer the proper nb of bytes */
+ bd_p->mode.count = buffsize;
+
+ bd_p->mode.status |= BD_DONE;
+ writtenBytes += buffsize;
+ toWrite -= buffsize;
+ /* Prepares access to the "next" buffer */
+ /* - case 1 - finished successfully : writtenBytes = nbytes */
+ if (toWrite == 0) {
+ copyFinished = TRUE;
+ }
+ /* - case 2 - Last BD and WRAP bit set so re-start from beginning */
+ /*else if ((bd_p->mode.status & BD_WRAP)){
+ bd_p = (bufferDescriptor *)iapi_Phys2Virt(ccb_p->baseBDptr);
+ } */
+ /* - case 3 - Last BD of the BD but nor ring */
+ else if (((bufferDescriptor *)
+ iapi_Phys2Virt(ccb_p->baseBDptr) +
+ (cd_p->bufferDescNumber -
+ 1) * sizeof(bufferDescriptor)) == bd_p) {
+ copyFinished = TRUE;
+ }
+ /* - case 4 - general : next BD in the BD array */
+ else {
+ bd_p++;
+ }
+
+ } else {
+ /* finished here : buffer not already done */
+ copyFinished = TRUE;
+ }
+ }
+
+ ccb_p->currentBDptr = ccb_p->baseBDptr;
+
+ /*
+ * 3. Starting of the channel
+ */
+ iapi_lowStartChannel(chNum);
+ ccb_p->status.execute = TRUE;
+
+ if (cd_p->callbackSynch == DEFAULT_POLL) {
+ iapi_SynchChannel(chNum);
+ /*
+ * Check the 'RROR' bit on all buffer descriptors, set error number
+ * and return IAPI_FAILURE if set.
+ */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ for (index = 0; index < cd_p->bufferDescNumber; index++) {
+ if (bd_p->mode.status & BD_RROR) {
+ result = IAPI_ERR_RROR_BIT_WRITE | chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ iapi_ReleaseChannel(chNum);
+ }
+
+ /*
+ *If synchronization type is callback, the user of I.API must
+ *release the channel
+ */
+ return writtenBytes;
+}
+
+/* ***************************************************************************/
+/* This function is used to receive data from the SDMA.
+ *
+ * <b>Algorithm:</b>\n
+ *
+ * The data control structure would be copied to IPCv1 complied Buffer
+ * Descriptor Array. This array shall be allocated from non cacheable memory.
+ * It would then provide this buffer descriptor array as an input to SDMA using
+ * channel control block and then configure the Host Enable (HE) or
+ * DSP enable (DE) bit of SDMA for the channel used for this transfer depending
+ * on the source.
+ *
+ * <b>Notes:</b>\n
+ * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized
+ * on a channel means that source processor is expecting to send to the destination
+ * processor. The meaning of an interrupt received from the SDMA notifies that the
+ * data has been delivered to the destination processor.
+ *
+ * @param *cd_p chanenl descriptor for the channel to receive from
+ * @param *data_control_struct_ipcv2
+
+ * Data Control structure:
+ * -------------------------
+ * | Data Node Descriptor 1|
+ * -------------------------
+ * | Data Node Descriptor 2|
+ * -------------------------
+ * | : |
+ * | : |
+ * -------------------------
+ * |Data Node Descriptor n |
+ * -------------------------
+ *
+ * Data Node Descriptor (Buffer Descriptor):
+ *------------------------------------------------------------------------------
+ *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0|
+ *------------------------------------------------------------------------------
+ *| L E D R R R R R |<---- Reserved ----> |<- Length-> |
+ *------------------------------------------------------------------------------
+ *| <---------------------------- Data Ptr ----------------------------------->|
+ *------------------------------------------------------------------------------
+ *
+ * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame
+ * E bit (END): If set, we reached the end of the buffers passed to the function
+ * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been
+ * filled by the SDMA.
+ * Length: Length of data pointed by this node in bytes
+ * Data Ptr: Pointer to the data pointed to by this node.
+ * The Function Shall not be called for the same channel unless the Read callback has been
+ * received for channel for which it has been called already.
+ *
+ * @return
+ * - IAPI_SUCCESS on success, IAPI_ERROR otherwise
+ *
+ *- -iapi_errno if failure
+ */
+
+int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2)
+{
+ channelControlBlock *ccb_p;
+
+/* The Parameters passed are considered to be validated by the upper layers*/
+
+ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p;
+ dataNodeDescriptor *dnd_p =
+ (dataNodeDescriptor *) data_control_struct_ipcv2;
+
+ ccb_p = cd_p->ccb_ptr;
+ iapi_errno = IAPI_ERR_NO_ERROR;
+
+ if (ccb_p->baseBDptr == NULL) {
+ iapi_errno = IAPI_ERR_BD_UNINITIALIZED;
+ return -(IAPI_ERR_BD_UNINITIALIZED);
+ }
+
+ ccb_p->currentBDptr = ccb_p->baseBDptr;
+
+ /* Copy the data Node descriptor information to new BDs */
+ bd_ipcv2_p =
+ (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->baseBDptr);
+
+ while (1) {
+ bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr;
+ bd_ipcv2_p->mode.count = dnd_p->mode.count;
+#ifdef MCU
+ bd_ipcv2_p->mode.endianness = 1;
+#endif
+#ifdef DSP
+ bd_ipcv2_p->mode.endianness = 0;
+#endif
+
+ bd_ipcv2_p->mode.status =
+ dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK];
+
+ if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) {
+ /* Break the loop at End of Transfer */
+ break;
+
+ }
+ bd_ipcv2_p++;
+ dnd_p++;
+
+ }
+ /*
+ * Store the buffer address
+ */
+ dnd_read_control_struct[cd_p->channelNumber] =
+ (dataNodeDescriptor *) data_control_struct_ipcv2;
+ /*
+ * Register the Call Back
+ */
+
+ iapi_AttachCallbackISR(cd_p, iapi_read_ipcv2_callback);
+
+ /*
+ * Starting of the channel
+ */
+ iapi_lowStartChannel(cd_p->channelNumber);
+ ccb_p->status.execute = TRUE;
+
+ return IAPI_SUCCESS;
+
+}
+
+/* ***************************************************************************/
+/*
+ * The function is used send a group of buffers to SDMA.
+ * <b>Algorithm:</b>\n
+ *
+ * The data control structure would be copied to IPCv1 complied Buffer
+ * Descriptor Array. This array shall be allocated from non cacheable memory.
+ * It would then provide this buffer descriptor array as an input to SDMA using
+ * channel control block and then configure the Host Enable (HE) or
+ * DSP enable (DE) bit of SDMA for the channel used for this transfer depending
+ * on the source.
+ * The Function Shall not be called for the same channel unless the Read callback has been
+ * received for channel for which it has been called already.
+ *
+ * <b>Notes:</b>\n
+ * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized
+ * on a channel means that source processor is expecting to send to the destination
+ * processor. The meaning of an interrupt received from the SDMA notifies that the
+ * data has been delivered to the destination processor.
+ *
+ * @param *cd_p chanenl descriptor for the channel to write to
+ * @param *data_control_struct_ipcv2
+
+ * Data Control structure:
+ * -------------------------
+ * | Data Node Descriptor 1|
+ * -------------------------
+ * | Data Node Descriptor 2|
+ * -------------------------
+ * | : |
+ * | : |
+ * -------------------------
+ * |Data Node Descriptor n |
+ * -------------------------
+ *
+ * Data Node Descriptor (Buffer Descriptor):
+ *------------------------------------------------------------------------------
+ *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 0|
+ *------------------------------------------------------------------------------
+ *| L E D R R R R R |<---- Reserved ----> |<- Length-> |
+ *------------------------------------------------------------------------------
+ *| <---------------------------- Data Ptr ----------------------------------->|
+ *------------------------------------------------------------------------------
+ *
+ * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame
+ * E bit (END): If set, we reached the end of the buffers passed to the function
+ * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been
+ * filled by the SDMA.
+ * Length: Length of data pointed by this node in bytes
+ * Data Ptr: Pointer to the data pointed to by this node.
+ *
+ *
+ * @return
+ * - iapi sucess on success.
+ * - -iapi_errno if failure
+ */
+
+int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2)
+{
+
+ channelControlBlock *ccb_p;
+
+/* The Parameters passed are considered to be validated by the upper layers*/
+
+ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p;
+ dataNodeDescriptor *dnd_p =
+ (dataNodeDescriptor *) data_control_struct_ipcv2;
+ ccb_p = cd_p->ccb_ptr;
+ iapi_errno = IAPI_ERR_NO_ERROR;
+
+ if (ccb_p->baseBDptr == NULL) {
+ iapi_errno = IAPI_ERR_BD_UNINITIALIZED;
+ return -(IAPI_ERR_BD_UNINITIALIZED);
+ }
+
+ ccb_p->currentBDptr = ccb_p->baseBDptr;
+
+ bd_ipcv2_p =
+ (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(ccb_p->currentBDptr);
+ /* Copy the data Node descriptor information to new BDs */
+ while (1) {
+ bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr;
+ bd_ipcv2_p->mode.count = dnd_p->mode.count;
+
+#ifdef MCU
+ bd_ipcv2_p->mode.endianness = 1;
+#endif
+#ifdef DSP
+ bd_ipcv2_p->mode.endianness = 0;
+#endif
+
+ bd_ipcv2_p->mode.status =
+ dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK];
+
+ if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) {
+ /* Break the loop at End of Transfer */
+ break;
+ }
+ bd_ipcv2_p++;
+ dnd_p++;
+
+ }
+
+ /*
+ * Starting of the channel
+ */
+ iapi_lowStartChannel(cd_p->channelNumber);
+ ccb_p->status.execute = TRUE;
+
+ return IAPI_SUCCESS;
+
+}
+
+/* ***************************************************************************/
+/** Call back ISR for the IPCv2 Receive.
+ *
+ * <b>Algorithm:</b>\n
+ * - This would copy back the informationfrom IPCv1 BD to IPCv2 BD on
+ * the receiving processor
+ *
+ * @return
+ * - void
+ */
+
+void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, void *data)
+{
+ /*cd_p->ccb_ptr->channelDNDBuffer; */
+ dataNodeDescriptor *dnd_p = dnd_read_control_struct[cd_p->channelNumber];
+ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p =
+ (bufferDescriptor_ipcv1_v2 *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ int index = MAX_BD_NUM - 1;
+
+ do {
+ dnd_p->mode.status = 0;
+ dnd_p->mode.count = bd_ipcv2_p->mode.count;
+
+ dnd_p->mode.status |=
+ bd_ipcv2_p->mode.status & BD_DONE ? 0x00 : DND_DONE;
+ dnd_p->mode.status |=
+ bd_ipcv2_p->
+ mode.status & BD_IPCV2_END_OF_FRAME ? DND_END_OF_FRAME :
+ 0x00;
+ dnd_p->mode.status |=
+ bd_ipcv2_p->mode.status & BD_LAST ? DND_END_OF_XFER : 0x00;
+ cd_p->ccb_ptr->currentBDptr =
+ (bufferDescriptor *) iapi_Virt2Phys(bd_ipcv2_p);
+
+ if ((bd_ipcv2_p->mode.status & BD_LAST) != 0 ||
+ (bd_ipcv2_p->mode.status & BD_CONT) == 0)
+ break;
+ dnd_p++;
+ bd_ipcv2_p++;
+
+ } while (index--);
+
+ /*Call back the Original ISR */
+ cd_p->callbackISR_ptr(cd_p, data);
+}
+
+/* ***************************************************************************/
+/**Terminates a channel.
+ *
+ * <b>Algorithm:</b>\n
+ * - Check input parameters ans data structures
+ * - Check that all buffes have been processed (test all 'D' bits)
+ * - Stop the channel execution
+ * - Free alocated memory structures
+ * - Re-instantiate default interrupt handling
+ *
+ * @param *cd_p chanenl descriptor for the channel to close
+ *
+ * @return
+ * - IAPI_SUCCESS : OK
+ * - -iapi_errno : close failed
+ */
+int iapi_Close(channelDescriptor *cd_p)
+{
+ int index = 0;
+ int result = IAPI_SUCCESS;
+ unsigned char chNum;
+ bufferDescriptor *bd_p;
+ channelControlBlock *ccb_p;
+
+ /*
+ * 1. Check input parameters ans data structures
+ */
+ if (cd_p != NULL) {
+ if (cd_p->ccb_ptr != NULL) {
+ chNum = cd_p->channelNumber;
+ ccb_p = cd_p->ccb_ptr;
+ } else {
+ result =
+ IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE;
+ iapi_errno = result;
+ return -result;
+ }
+ } else {
+ result = IAPI_ERR_CD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE;
+ iapi_errno = result;
+ return -result;
+ }
+ /* Try to aquire channel */
+ if (iapi_GetChannel(chNum) != 0) {
+ result = IAPI_ERR_CH_IN_USE | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /*
+ * 2. Check that all buffes have been processed (test all 'D' bits),
+ * only if the forceClose bit in channel descriptor is set to FALSE
+ */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ if (bd_p == NULL) {
+ result =
+ IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+ if (cd_p->forceClose == FALSE) {
+ for (index = cd_p->bufferDescNumber; index > 0; index--) {
+ if (bd_p->mode.status & BD_DONE) {
+ result =
+ IAPI_ERR_CLOSE | IAPI_ERR_CH_AVAILABLE |
+ chNum;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ }
+ bd_p++;
+ }
+ }
+ /*if the closing is forced,mark channel unused,set BD ownership to processor */
+ else {
+ ccb_p->status.execute = FALSE;
+ for (index = cd_p->bufferDescNumber; index > 0; index--) {
+ bd_p->mode.status &= ~BD_DONE;
+ bd_p++;
+ }
+ }
+
+ /*
+ * 3. Stop the channel execution
+ */
+ iapi_lowStopChannel(chNum);
+
+ /*
+ * 4. Free alocated memory structures
+ */
+ if (cd_p->trust == FALSE) {
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr);
+ for (index = cd_p->bufferDescNumber; index > 0; index--) {
+ FREE(iapi_Phys2Virt(bd_p->bufferAddr));
+ bd_p++;
+ }
+ }
+
+ /*
+ * 5. Re-instantiate default interrupt handling
+ */
+ iapi_DetachCallbackISR(cd_p);
+ FREE((bufferDescriptor *) iapi_Phys2Virt(ccb_p->baseBDptr));
+ FREE(cd_p);
+ ccb_p->baseBDptr = NULL;
+ ccb_p->currentBDptr = NULL;
+ ccb_p->channelDescriptor = NULL;
+ ccb_p->status.openedInit = FALSE;
+
+ iapi_ReleaseChannel(chNum);
+
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**The request argument selects the control function to be performed.
+ *
+ * <b>Algorithm:</b>\n
+ *
+ * - Check data structures are properly initialized:
+ * - Channel descriptor validity
+ * - Channel control block validity
+ * - The ctlRequest parameter contains in the lower 16 bits the control code of
+ * the change to be performed, and in the upper 16 bits, the BD to be
+ * modified if the change affects a BD od the channel.
+ * - Selection of the parameter to change and appropriate sanity checks:
+ * - Channel Descriptor: changes the pointer to the channel descriptor
+ * structure, the pointer to the new channel descriptor is given in the third
+ * argument call
+ * - Buffer Descriptor Number: changes the number of buffer descriptor for the
+ * channel
+ * - Buffer size: changes the size of the data buffers pointed to by the
+ * buffer descriptor; note that all buffer descriptors are assumed to have the
+ * same size for a given buffer descripotr chain
+ * - Blocking policy: changes the blocking policy for the read and write calls
+ * - Ownership: changes direction: turnaround
+ * - Synchronization method: changes the callback type, default or user. The*
+ * callback function table is set accordingly
+ * - Trust property: trust can only be changed through ChangeChannelDesc first
+ * request, this guarantees the close/open sequence for the channel
+ * - Callback Interrupt service routine pointer: changes the callback function
+ * pointer, when this method is used, to replace it with a new one
+ * - Channel control block pointer: not available
+ * - Priority: changes the channel priority directly in SDMA register
+ * - Watermark level: changes the value of the peripheral watermark level that
+ * passed to the script. The new value is passed in the third parameter call.
+ * - Wrap bit: changes to set to 1 the Wrap bit of the last buffer descriptor
+ *
+ * @param *cd_p channel descriptor for the channel to modify
+ * @param ctlRequest request control code and, if tha case, number of BD to be
+ * changed
+ * @param param parameter for the modification
+ *
+ * @return
+ * - IAPI_SUCCESS : OK
+ * - -iapi_errno : operation failed
+ */
+int
+iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest,
+ unsigned long param)
+{
+ int retvalue;
+ int result = IAPI_SUCCESS;
+ unsigned char chNum;
+ unsigned long clean_ctlRequest; /* lower 16 bits of the ctlRequest */
+ unsigned long bd_num; /* upper 16 bits of the ctlRequest */
+
+ /*
+ * 1. Check data structures are properly initialized
+ */
+ /* Channel descriptor validity */
+ if (cd_p == NULL) {
+ result = IAPI_ERR_CD_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Channel control block validity */
+ if (cd_p->ccb_ptr == NULL) {
+ result = IAPI_ERR_CCB_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Control block & Descriptor associated with the channel being worked on */
+ chNum = cd_p->channelNumber;
+
+ /* Remove, if exists, BD number specified in upper bits of ctlRequest */
+ clean_ctlRequest = ctlRequest & (~BD_NUM_MASK);
+
+ /* Extract, if exists, BD number specified in upper bits of ctlRequest */
+ bd_num = (ctlRequest & BD_NUM_MASK) >> BD_NUM_OFFSET;
+
+ /* Check that the bd_num is valid */
+ if (bd_num > cd_p->bufferDescNumber) {
+ result = IAPI_ERR_INVALID_PARAMETER | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /*All checks OK, try to aquire channel */
+ if (iapi_GetChannel(chNum) != 0) {
+ result = IAPI_ERR_CH_IN_USE | chNum;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /*
+ * 2. Selection of the parameter to change and appropriate sanity checks
+ */
+ switch (clean_ctlRequest) {
+
+ /*
+ * Channel Descriptor
+ * --- Changes the pointer to the channel descriptor structure: the pointer
+ * to the new channel descriptor is given in the third argument call.
+ */
+ case IAPI_CHANGE_CHANDESC:
+ if ((void *)param == NULL) {
+ result = IAPI_ERR_INVALID_PARAMETER;
+ iapi_errno = result;
+ iapi_ReleaseChannel(chNum);
+ return -result;
+ } else {
+ channelDescriptor *chParam =
+ (channelDescriptor *) param;
+ if (chParam->channelNumber != chNum) {
+ /* Release ch so it can be aquired by the Close fn */
+ iapi_ReleaseChannel(chNum);
+ result = iapi_Close(cd_p);
+ if (result == IAPI_SUCCESS) {
+ FREE((void *)cd_p);
+ iapi_AllocChannelDesc(&cd_p,
+ chParam->channelNumber);
+ iapi_memcpy((void *)cd_p,
+ (void *)chParam,
+ sizeof(channelDescriptor));
+ /* Channel is released allready, so Open can get the channel */
+ result =
+ iapi_Open(cd_p,
+ chParam->channelNumber);
+ if (result != IAPI_SUCCESS) {
+ return result; /* error code already set in iapi_Open */
+ }
+ } else {
+ return result; /* error code already set in iapi_Close */
+ }
+ } else {
+ result =
+ IAPI_ERR_CD_CHANGE | IAPI_ERR_CH_AVAILABLE |
+ cd_p->channelNumber;
+ iapi_ReleaseChannel(chNum);
+ iapi_errno = result;
+ return -result;
+ }
+ return IAPI_SUCCESS;
+ }
+
+ /*
+ * Buffer Descriptor Number
+ * --- Changes the number of buffer descriptor for the channel.
+ */
+ case IAPI_CHANGE_BDNUM:
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Buffer size
+ * --- Changes the size of the data buffers pointed to by the buffer
+ * descriptor; note that all buffer descriptors are assumed to have the
+ * same size for a given buffer descripotr chain.
+ */
+ case IAPI_CHANGE_BUFFSIZE:
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Blocking policy
+ * --- Changes the blocking policy for the read and write calls.
+ */
+ case IAPI_CHANGE_CHANBLOCK:
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_BLOCKING, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Ownership
+ * --- Changes direction: turnaround
+ */
+ case IAPI_CHANGE_OWNERSHIP:
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_OWNERSHIP, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Synchronization method
+ * --- Changes the callback type, default or user. The callback function
+ * table is set accordingly.
+ */
+ case IAPI_CHANGE_SYNCH:
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKSYNCH, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Trust property
+ * --- trust can only be changed through ChangeChannelDesc first request,
+ * this guarantees the close/open sequence for the channel.
+ */
+ case IAPI_CHANGE_TRUST:
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Callback Interrupt service routine pointer
+ * --- Cahnges the callback function pointer, when this method is used, to
+ * replace it with a new one.
+ */
+ case IAPI_CHANGE_CALLBACKFUNC:
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKISR_PTR, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+ /*
+ * Channel control block pointer
+ * --- NA
+ */
+ case IAPI_CHANGE_CHANCCB:
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_CCB_PTR, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+
+#ifdef MCU
+ /*
+ * Priority
+ * --- Changes the channel priority directly in SDMA register
+ */
+ case IAPI_CHANGE_PRIORITY:
+ {
+ volatile unsigned long *ChannelPriorities =
+ &SDMA_CHNPRI_0;
+ if (param < MAX_CH_PRIORITY) {
+ ChannelPriorities[cd_p->channelNumber] = param;
+ } else {
+ iapi_ReleaseChannel(chNum);
+ return IAPI_FAILURE;
+ }
+ }
+ break;
+#endif /* MCU */
+
+ /*
+ * Wrap
+ * --- Set to 1 the wrap bit of the last buffer descriptor of the array.
+ * it provides the possibility to have a circular buffer structure.
+ */
+ case IAPI_CHANGE_BDWRAP:
+ {
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_BDWRAP, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+ }
+
+ /*
+ * Watermark
+ * --- Changes the value of the peripheral watermark level that triggers
+ * a DMA request. It impacts context of the channel, therefore channel 0
+ * must be started to update the context with this new value.
+ */
+ case IAPI_CHANGE_WATERMARK:
+ {
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_WML, param);
+ iapi_ReleaseChannel(chNum);
+ return result;
+ }
+ /*
+ * INTR
+ * --- Set the INTR bit on specified BD or on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_SET_BDINTR:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status |= BD_INTR;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status |= BD_INTR;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * INTR
+ * --- Unset the INTR bit on specified BD or on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_UNSET_BDINTR:
+ {
+ bufferDescriptor *bde_p;
+
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status &= ~BD_INTR;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status &= ~BD_INTR;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+/*
+ * EventMask1
+ * --- Changes the value of the eventMask1
+ */
+ case IAPI_CHANGE_EVTMASK1:
+ {
+ cd_p->eventMask1 = param;
+ }
+ break;
+ /*
+ * EventMask2
+ * --- Changes the value of the eventMask2
+ */
+ case IAPI_CHANGE_EVTMASK2:
+ {
+ cd_p->eventMask2 = param;
+ }
+ break;
+ /*
+ * Peripheral Address
+ * --- Changes the value of the peripheralAddr
+ */
+ case IAPI_CHANGE_PERIPHADDR:
+ {
+ cd_p->peripheralAddr = param;
+ }
+ break;
+ /*
+ * Cont
+ * --- Set the CONT bit on specified BD on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_SET_BDCONT:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status |= BD_CONT;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status |= BD_CONT;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * Cont
+ * --- Unset the CONT bit on specified BD or on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_UNSET_BDCONT:
+ {
+ bufferDescriptor *bde_p;
+
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status &= ~BD_CONT;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status &= ~BD_CONT;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+
+ /*
+ * EXTD
+ * --- Set the EXTD bit on specified BD or on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_SET_BDEXTD:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status |= BD_EXTD;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status |= BD_EXTD;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * EXTD
+ * --- Unset the EXTD bit on specified BD or on all BD's if SET_BIT_ALL
+ * is passed as parameter.
+ */
+ case IAPI_CHANGE_UNSET_BDEXTD:
+ {
+ bufferDescriptor *bde_p;
+
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.status &= ~BD_EXTD;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.status &= ~BD_EXTD;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+
+ /*
+ * TRANSFER SIZE to be used for this channel
+ * --- Set the transfer size used indicator and code for transfer size in
+ * the CD
+ */
+ case IAPI_CHANGE_SET_TRANSFER_CD:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+ retvalue = IAPI_SUCCESS;
+ if ((param == TRANSFER_8BIT)
+ || (param == TRANSFER_16BIT)
+ || (param == TRANSFER_24BIT)
+ || (param == TRANSFER_32BIT)) {
+ cd_p->useDataSize = TRUE;
+ cd_p->dataSize = param;
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.command = param;
+ bde_p++;
+ }
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+
+ /*
+ * USER_ARG
+ * --- Set the user selectable pointer to be received by the callback
+ * function, if IRQ synch is used
+ */
+ case IAPI_CHANGE_USER_ARG:
+ {
+ userArgTable[cd_p->channelNumber] = (void *)param;
+ iapi_ReleaseChannel(chNum);
+ return IAPI_SUCCESS;
+ }
+ /*
+ * FORCE_CLOSE
+ * --- Set the forceClose bit in channelDescriptor to value passed in param.
+ * If this bit is TRUE, the channel in closed even if some BD are still
+ * owned by the SDMA.
+ */
+ case IAPI_CHANGE_FORCE_CLOSE:
+ {
+ retvalue = IAPI_SUCCESS;
+ if ((param == TRUE) || (param == FALSE)) {
+ cd_p->forceClose = param;
+ } else {
+ iapi_errno =
+ IAPI_ERR_INVALID_PARAMETER |
+ cd_p->channelNumber;
+ retvalue = -iapi_errno;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * TRANSFER type
+ * --- Set the last 2 bits in the command field of the BD to specify the
+ * transfer type 8, 16, 24, or 32 bits on all BD's, allready set in the CD
+ */
+ case IAPI_CHANGE_SET_TRANSFER:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if ((param == TRANSFER_8BIT)
+ || (param == TRANSFER_16BIT)
+ || (param == TRANSFER_24BIT)
+ || (param == TRANSFER_32BIT)) {
+ bde_p = cd_p->ccb_ptr->baseBDptr;
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.command = param;
+ bde_p++;
+ }
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * BUFFER address
+ * --- Change buffer address in BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_SET_BUFFERADDR:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+
+ /* DO NOT translate address to physical */
+ bde_p->bufferAddr = (void *)param;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * BUFFER address
+ * --- Get the buffer address from the BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_GET_BUFFERADDR:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Translate to virtual */
+ *((unsigned long *)param) =
+ (unsigned long)bde_p->bufferAddr;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * EXTENDED BUFFER address
+ * --- Change extended buffer address in BD specified in the upper 16 bits
+ * of the ctlRequest.
+ */
+ case IAPI_CHANGE_SET_EXTDBUFFERADDR:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+
+ /* DO NOT translate address to physical. The user might want something else
+ *here
+ */
+ bde_p->extBufferAddr = (void *)param;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * EXTENDED BUFFER address
+ * --- Get extended buffer address from the BD specified in the upper 16 bits
+ * of the ctlRequest.
+ */
+ case IAPI_CHANGE_GET_EXTDBUFFERADDR:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+
+ /* DO NOT translate address to vitual - user knows what is here.
+ */
+ *((unsigned long *)param) =
+ (unsigned long)bde_p->extBufferAddr;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * COMMAND field
+ * --- Change command field in BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_SET_COMMAND:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Update command field */
+ bde_p->mode.command = param;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * COMMAND field
+ * --- Get the command field from the BD specified in the upper 16 bits
+ * of the ctlRequest.
+ */
+ case IAPI_CHANGE_GET_COMMAND:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Get the command field */
+ *((unsigned long *)param) = bde_p->mode.command;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * COUNT field
+ * --- Change count field in BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_SET_COUNT:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Update count field */
+ bde_p->mode.count = param;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * COUNT field
+ * --- Get the count field of the BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_GET_COUNT:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Update count field */
+ *((unsigned long *)param) = bde_p->mode.count;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * STATUS field
+ * --- Change status field in BD specified in the upper 16 bits of the
+ * ctlRequest.
+ */
+ case IAPI_CHANGE_SET_STATUS:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Update status field */
+ bde_p->mode.status = param;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+ /*
+ * STATUS field
+ * --- Get the status field of the BD specified in the upper 16 bits
+ * of the ctlRequest.
+ */
+ case IAPI_CHANGE_GET_STATUS:
+ {
+ bufferDescriptor *bde_p;
+ retvalue = IAPI_SUCCESS;
+
+ /* Get pointer to the BD structure to change */
+ bde_p =
+ (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bde_p += bd_num;
+ /* Update status field */
+ *((unsigned long *)param) = bde_p->mode.status;
+
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+
+#ifdef MCU
+ /*
+ * Endianness
+ * --- Set the ENDIANNESS indicator in the command filed of the specified BD
+ * or on all BD's if SET_BIT_ALL is passed as parameter.
+ */
+ case IAPI_CHANGE_SET_ENDIANNESS:
+ {
+ bufferDescriptor *bde_p;
+ int j = 0;
+
+ retvalue = IAPI_SUCCESS;
+ if (param == SET_BIT_ALL) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
+ for (j = 0; j < cd_p->bufferDescNumber; j++) {
+ bde_p->mode.command = CHANGE_ENDIANNESS;
+ bde_p++;
+ }
+ } else if (param < cd_p->bufferDescNumber) {
+ bde_p =
+ (bufferDescriptor *)
+ iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr)
+ + param;
+ bde_p->mode.command = CHANGE_ENDIANNESS;
+ } else {
+ retvalue = IAPI_FAILURE;
+ }
+ iapi_ReleaseChannel(chNum);
+ return retvalue;
+ }
+#endif
+
+#ifdef SDMA_SKYE
+#ifdef MCU
+
+ /*
+ * SDMA State
+ * --- Enter the SDMA into LOCK Mode. No RAM updation allowed except same Context
+ * update with same PC Value.
+ */
+ case IAPI_ENTER_LOCK_MODE:
+ {
+ if (param == RESET_CLEAR_LOCK) {
+ SDMA_SDMA_LOCK = (1 << RESET_CLR_BIT_OFFSET);
+ SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET);
+ iapi_SdmaState = LOCK;
+ } else if (param == RESET_NOCLEAR_LOCK) {
+ SDMA_SDMA_LOCK = (1 << LOCK_BIT_OFFSET);
+ iapi_SdmaState = LOCK;
+ }
+
+ }
+ break;
+
+#endif
+#endif
+ default:
+ retvalue =
+ IAPI_ERR_CD_CHANGE_UNKNOWN | IAPI_ERR_CH_AVAILABLE | chNum;
+ iapi_errno = retvalue;
+ iapi_ReleaseChannel(chNum);
+ return -retvalue;
+ }
+
+ iapi_ReleaseChannel(chNum);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**Initialization of the SDMA - opening of channel 0, download RAM image.
+ *
+ * <b>Algorithm:</b>\n
+ * - open channel 0
+ * - if ram_image pointer passed is not NULL, download RAM image to SDMA
+ *
+ * @param
+ * - cd_p channel descriptor pointer for channel 0
+ * - ram_image pointer to RAM image to download, or NULL if this operation
+ * is not required
+ * - code_size size of the RAM image, in bytes
+ * - start_addr start address for the RAM image
+ *
+ * @return
+ * - IAPI_SUCCESS if all operations were successful
+ * - negated I.API error code if any operation failed
+ */
+#ifdef MCU
+int
+iapi_Init(channelDescriptor *cd_p, configs_data *config_p,
+ unsigned short *ram_image, unsigned short code_size,
+ unsigned long start_addr)
+{
+#endif
+#ifdef DSP
+ int
+ iapi_Init(channelDescriptor *cd_p) {
+#endif
+
+ int retvalue = IAPI_SUCCESS; /* Variable to store the results from I.API calls */
+
+ /* Check initialization not allredy done */
+ if (iapi_CCBHead != NULL) {
+ retvalue = IAPI_ERR_NOT_ALLOWED;
+ iapi_errno = retvalue;
+ return -retvalue;
+ }
+ /* Be sure SDMA has not started yet */
+#ifdef MCU
+ SDMA_H_C0PTR = 0x0;
+#endif
+#ifdef DSP
+ SDMA_D_C0PTR = 0x0;
+#endif
+
+ /*Try to open channel 0 */
+ retvalue = iapi_Open(cd_p, 0);
+ if (retvalue != IAPI_SUCCESS) {
+ return retvalue;
+ }
+#ifdef MCU
+ /* Set Command Channel (Channel Zero) */
+ SDMA_CHN0ADDR = 0x4050;
+
+ /* Set bits of CONFIG register but with static context switching */
+ SDMA_H_CONFIG =
+ (config_p->
+ dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr
+ << 4) | (0);
+
+ /* Send the address for the host channel table to the SDMA */
+ SDMA_H_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead);
+ /* If required, download the RAM image for SDMA */
+ if (ram_image != NULL) {
+ retvalue =
+ iapi_SetScript(cd_p, (void *)ram_image, code_size,
+ start_addr);
+ }
+
+ /* Set bits of CONFIG register with given context switching mode */
+ SDMA_H_CONFIG =
+ (config_p->
+ dspdma << 12) | (config_p->rtdobs << 11) | (config_p->acr
+ << 4) |
+ (config_p->csm);
+
+#endif
+#ifdef DSP
+ /* Send the address for the host channel table to the SDMA */
+ SDMA_D_C0PTR = (unsigned long)iapi_Virt2Phys(iapi_CCBHead);
+#endif
+
+#ifdef SDMA_SKYE
+ iapi_SdmaState = OPEN;
+#endif
+
+ return retvalue;
+ }
+
+/* ***************************************************************************/
+/**High layer interface for starting a channel
+ *
+ * <b>Algorithm:</b>\n
+ * - call low layer function for starting a channel
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_StartChannel(unsigned char channel)
+{
+ iapi_lowStartChannel(channel);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface for stopping a channel
+ *
+ * <b>Algorithm:</b>\n
+ * - call low layer function for stopping a channel
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_StopChannel(unsigned char channel)
+{
+ iapi_lowStopChannel(channel);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface for synchronising a channel
+ *
+ * <b>Algorithm:</b>\n
+ * - call low layer function for stopping a channel
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_SynchChannel(unsigned char channel)
+{
+ iapi_lowSynchChannel(channel);
+ return IAPI_SUCCESS;
+}
+
+#ifdef MCU
+/* ***************************************************************************/
+/**High layer interface for getting program memory data from SDMA
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_GetScript(channelDescriptor *cd_p, void *buf,
+ unsigned short size, unsigned long address)
+{
+ iapi_lowGetScript(cd_p, buf, size, address);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface for getting data memory from SDMA
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_GetContext(channelDescriptor *cd_p, void *buf,
+ unsigned char channel)
+{
+ iapi_lowGetContext(cd_p, buf, channel);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface for set program memory data to SDMA - e.g. scripts
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_SetScript(channelDescriptor *cd_p, void *buf,
+ unsigned short nbyte, unsigned long destAddr)
+{
+ iapi_lowSetScript(cd_p, buf, nbyte, destAddr);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface for set data memory to SDMA - e.g. contexts.
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_SetContext(channelDescriptor *cd_p, void *buf,
+ unsigned char channel)
+{
+ iapi_lowSetContext(cd_p, buf, channel);
+ return IAPI_SUCCESS;
+}
+
+/* ***************************************************************************/
+/**High layer interface used to associate specified channel with a script.
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p)
+{
+ /* VERIFY THAT THE CHANNEL IT IS OPENED !!!! */
+ return iapi_lowAssignScript(cd_p, data_p);
+}
+
+/* ***************************************************************************/
+/**High layer interface used to associate specified channel with a script.
+ *
+ * <b>Algorithm:</b>\n
+ * - call coresponding low layer function
+ *
+ * @return
+ * - IAPI_SUCCESS
+ */
+int iapi_SetChannelEventMapping(unsigned char event,
+ unsigned long channel_map)
+{
+ return iapi_lowSetChannelEventMapping(event, channel_map);
+}
+#endif
+
+#ifdef DSP
+#define SDMA_DI SDMA_D_INTR
+ void IRQ_Handler();
+#pragma interrupt IRQ_Handler
+#endif
+
+#ifdef MCU
+#define SDMA_DI SDMA_H_INTR
+#endif
+
+#ifndef IRQ_KEYWORD
+#define IRQ_KEYWORD
+#endif /* IRQ_KEYWORD */
+
+/* ***************************************************************************/
+/**
+ *@brief Find the first set bit in data parameter.
+ *
+ * Find the first set bit in unsigned integer parameter data. Data is scanned
+ * from MSB to LSB, searching for the set bit. The value returned is the
+ * offset from the most significant bit of data. If bit 31 is set, the value
+ * returned is zero. If no bits are set, a value of 32 is returned. This is compliant
+ * with the MCore FF1 instruction.
+ *
+ *
+ *
+ * @param
+ * - data: variable to check
+ *
+ * @return
+ * - the offset of the most significant bit set from the MSB
+ */
+unsigned int quartz_FF1(unsigned int data)
+{
+ register unsigned int result = 0;
+ while ((result <= 31) && !(data & 0x80000000U)) {
+ data <<= 1U;
+ result++;
+ }
+
+ return result;
+}
+
+IRQ_KEYWORD void IRQ_Handler(void)
+{
+ unsigned int intrReg; /* interrupt register mask for clearing the interrupt bit */
+ unsigned char chNum; /* SDMA channel number generating the a IRQ */
+
+ /* Disable interrupts */
+ iapi_DisableInterrupts();
+ /*
+ * Clear interrupt in SDMA DI register => ACK to the SDMA the IT request.
+ * Get each interrupt number, clear them one after the other.
+ */
+ if (SDMA_DI != 0) {
+ chNum =
+ (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI));
+ intrReg = (unsigned int)(1 << chNum);
+ } else {
+ chNum = 32;
+ intrReg = 0;
+ }
+
+ while (intrReg != 0) {
+ SDMA_DI &= intrReg;
+ iapi_SDMAIntr |= intrReg;
+ iapi_WakeUp(chNum);
+ if (callbackIsrTable[chNum] != NULL) {
+ /* release channel before callback, so IoCtl's are available */
+ iapi_ReleaseChannel(chNum);
+ callbackIsrTable[chNum] (iapi_CCBHead
+ [chNum].channelDescriptor,
+ userArgTable[chNum]);
+ }
+
+ chNum =
+ (unsigned char)(CH_NUM - 1 - quartz_FF1(SDMA_DI));
+ intrReg = (unsigned int)(1 << chNum);
+ }
+
+ /* Enable interrupts */
+ iapi_EnableInterrupts();
+}
+
+/* ***************************************************************************/
+/**
+ *@brief Perform a memory copy operation, in the memory of the same processor
+ *
+ * Size bytes are copied from the src address to dest address. It is used
+ * the channel pointed by cd_p, which must be configured prior to this call:
+ * opened, associated with the script to perform the operation - DSP_2_DSP,
+ * or MCU_2_MCU - and have the synchronization option set.
+ *
+ *
+ *
+ * @param
+ * - cd_p: channel configured to perform DSP_2_DSP or MCU_2_MCU transfers
+ * - dest: destination memory address
+ * - src : source memory address
+ * - size: number of bytes to copy from src to dest
+ *
+ * @return
+ * - the offset of the most significant bit set from the MSB
+ */
+
+int iapi_MemCopy(channelDescriptor *cd_p, void *dest, void *src,
+ unsigned long size)
+{
+ int result = IAPI_SUCCESS;
+ bufferDescriptor *bd_p;
+
+ /* Channel descriptor validity */
+ if (cd_p == NULL) {
+ result = IAPI_ERR_CD_UNINITIALIZED;
+ iapi_errno = result;
+ return -result;
+ }
+
+ /* Check and set correct parameter */
+ if (cd_p->trust != TRUE) {
+ result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, TRUE);
+ }
+
+ if (cd_p->bufferDescNumber != 1) {
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER,
+ 1);
+ if (result != IAPI_SUCCESS) {
+ return result;
+ }
+ }
+
+ if (cd_p->bufferSize != size) {
+ result =
+ iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, size);
+ if (result != IAPI_SUCCESS) {
+ return result;
+ }
+ }
+ /* Set addresses */
+ bd_p = (bufferDescriptor *) iapi_Phys2Virt(cd_p->
+ ccb_ptr->baseBDptr);
+ bd_p->bufferAddr = iapi_Virt2Phys(src);
+ bd_p->extBufferAddr = iapi_Virt2Phys(dest);
+
+ /* Set mode */
+ bd_p->mode.count = size;
+ bd_p->mode.command = 0x00;
+ bd_p->mode.status = BD_INTR | BD_EXTD | BD_DONE | BD_WRAP;
+
+ /*Decide if we sleep or not */
+ if (cd_p->callbackSynch == DEFAULT_POLL) {
+ iapi_StartChannel(cd_p->channelNumber);
+ /* Call synchronization routine */
+ iapi_SynchChannel(cd_p->channelNumber);
+ } else {
+ /* Just start the channel */
+ iapi_StartChannel(cd_p->channelNumber);
+ }
+
+ return result;
+}
+
+/* ***************************************************************************/
+/**Return the channel number from the channel descriptor
+ *
+ * @param cd_p pointer to channel descriptor to obtain the channel number
+ *
+ * @return
+ * - the channel number
+ *
+ */
+int iapi_GetChannelNumber(channelDescriptor *cd_p)
+{
+ return cd_p->channelNumber;
+}
+
+/* ***************************************************************************/
+/**Return the error bit from the current BD of the channel
+ *
+ *
+ * @param cd_p pointer to channel descriptor
+ *
+ * @return
+ * - 0 if no error detected
+ * - BD_RROR | DATA_ERROR if error detected
+ *
+ */
+unsigned long iapi_GetError(channelDescriptor *cd_p)
+{
+ return (cd_p->ccb_ptr->currentBDptr->mode.status & BD_RROR) |
+ (*(unsigned long *)&cd_p->ccb_ptr->status & DATA_ERROR);
+}
+
+/* ***************************************************************************/
+/**Return the count from the current BD of the channel
+ *
+ *
+ * @param cd_p pointer to channel descriptor
+ *
+ * @return
+ * - count field of the current BD for the channel
+ *
+ */
+int iapi_GetCount(channelDescriptor *cd_p)
+{
+ return (int)(cd_p->ccb_ptr->currentBDptr->mode.count);
+}
+
+/* ***************************************************************************/
+/**Return the sum of counts for all the BD's owned by the processor for
+ * the channel specified by the received parameter.
+ *
+ *
+ * @param cd_p pointer to channel descriptor
+ *
+ * @return
+ * - sum of count fields
+ *
+ */
+int iapi_GetCountAll(channelDescriptor *cd_p)
+{
+ int retval = 0;
+ int i = 0;
+ bufferDescriptor *bd_p;
+
+ bd_p = cd_p->ccb_ptr->baseBDptr;
+
+ while ((i < cd_p->bufferDescNumber)
+ && ((bd_p->mode.status & BD_DONE) == 0)) {
+ retval += bd_p->mode.count;
+ i++;
+ bd_p++;
+ }
+ return retval;
+}