/* * ======== WMD_MSG_DeleteQueue ======== * Delete a MSG queue allocated in WMD_MSG_CreateQueue. */ void WMD_MSG_DeleteQueue(struct MSG_QUEUE *hMsgQueue) { struct MSG_MGR *hMsgMgr = hMsgQueue->hMsgMgr; u32 refCount; DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); hMsgQueue->fDone = true; /* Unblock all threads blocked in MSG_Get() or MSG_Put(). */ refCount = hMsgQueue->refCount; while (refCount) { /* Unblock thread */ SYNC_SetEvent(hMsgQueue->hSyncDone); /* Wait for acknowledgement */ SYNC_WaitOnEvent(hMsgQueue->hSyncDoneAck, SYNC_INFINITE); refCount = hMsgQueue->refCount; } /* Remove message queue from hMsgMgr->queueList */ (void)SYNC_EnterCS(hMsgMgr->hSyncCS); LST_RemoveElem(hMsgMgr->queueList, (struct LST_ELEM *)hMsgQueue); /* Free the message queue object */ DeleteMsgQueue(hMsgQueue, hMsgQueue->uMaxMsgs); if (!hMsgMgr->msgFreeList) goto func_cont; if (LST_IsEmpty(hMsgMgr->msgFreeList)) SYNC_ResetEvent(hMsgMgr->hSyncEvent); func_cont: (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); }
/* * ======== NTFY_Notify ======== * Purpose: * Execute notify function (signal event) for every * element in the notification list that is to be notified about the * event specified in uEventMask. */ void NTFY_Notify(struct NTFY_OBJECT *hNtfy, u32 uEventMask) { struct NOTIFICATION *pNotify; DBC_Require(MEM_IsValidHandle(hNtfy, NTFY_SIGNATURE)); /* * Go through notifyList and notify all clients registered for * uEventMask events. */ (void) SYNC_EnterCS(hNtfy->hSync); pNotify = (struct NOTIFICATION *)LST_First(hNtfy->notifyList); while (pNotify != NULL) { if (pNotify->uEventMask & uEventMask) { /* Notify */ if (pNotify->uNotifyType == DSP_SIGNALEVENT) (void)SYNC_SetEvent(pNotify->hSync); } pNotify = (struct NOTIFICATION *)LST_Next(hNtfy->notifyList, (struct list_head *)pNotify); } (void) SYNC_LeaveCS(hNtfy->hSync); }
/* * ======== STRM_Select ======== * Purpose: * Selects a ready stream. */ DSP_STATUS STRM_Select(IN struct STRM_OBJECT **aStrmTab, u32 nStrms, OUT u32 *pMask, u32 uTimeout) { u32 uIndex; struct CHNL_INFO chnlInfo; struct WMD_DRV_INTERFACE *pIntfFxns; struct SYNC_OBJECT **hSyncEvents = NULL; u32 i; DSP_STATUS status = DSP_SOK; DBC_Require(cRefs > 0); DBC_Require(aStrmTab != NULL); DBC_Require(pMask != NULL); DBC_Require(nStrms > 0); GT_4trace(STRM_debugMask, GT_ENTER, "STRM_Select: aStrmTab: 0x%x \tnStrms: " "0x%x\tpMask: 0x%x\tuTimeout: 0x%x\n", aStrmTab, nStrms, pMask, uTimeout); *pMask = 0; for (i = 0; i < nStrms; i++) { if (!MEM_IsValidHandle(aStrmTab[i], STRM_SIGNATURE)) { status = DSP_EHANDLE; break; } } if (DSP_FAILED(status)) goto func_end; /* Determine which channels have IO ready */ for (i = 0; i < nStrms; i++) { pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns; status = (*pIntfFxns->pfnChnlGetInfo)(aStrmTab[i]->hChnl, &chnlInfo); if (DSP_FAILED(status)) { break; } else { if (chnlInfo.cIOCs > 0) *pMask |= (1 << i); } } if (DSP_SUCCEEDED(status) && uTimeout > 0 && *pMask == 0) { /* Non-zero timeout */ hSyncEvents = (struct SYNC_OBJECT **)MEM_Alloc(nStrms * sizeof(struct SYNC_OBJECT *), MEM_PAGED); if (hSyncEvents == NULL) { status = DSP_EMEMORY; } else { for (i = 0; i < nStrms; i++) { pIntfFxns = aStrmTab[i]->hStrmMgr->pIntfFxns; status = (*pIntfFxns->pfnChnlGetInfo) (aStrmTab[i]->hChnl, &chnlInfo); if (DSP_FAILED(status)) break; else hSyncEvents[i] = chnlInfo.hSyncEvent; } } if (DSP_SUCCEEDED(status)) { status = SYNC_WaitOnMultipleEvents(hSyncEvents, nStrms, uTimeout, &uIndex); if (DSP_SUCCEEDED(status)) { /* Since we waited on the event, we have to * reset it */ SYNC_SetEvent(hSyncEvents[uIndex]); *pMask = 1 << uIndex; } } } func_end: if (hSyncEvents) MEM_Free(hSyncEvents); DBC_Ensure((DSP_SUCCEEDED(status) && (*pMask != 0 || uTimeout == 0)) || (DSP_FAILED(status) && *pMask == 0)); return status; }
/* * ======== WMD_CHNL_GetIOC ======== * Optionally wait for I/O completion on a channel. Dequeue an I/O * completion record, which contains information about the completed * I/O request. * Note: Ensures Channel Invariant (see notes above). */ DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, u32 dwTimeOut, OUT struct CHNL_IOC *pIOC) { DSP_STATUS status = DSP_SOK; struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; struct CHNL_IRP *pChirp; DSP_STATUS statSync; bool fDequeueIOC = true; struct CHNL_IOC ioc = { NULL, 0, 0, 0, 0 }; u8 *pHostSysBuf = NULL; struct WMD_DEV_CONTEXT *dev_ctxt; struct DEV_OBJECT *dev_obj; /* Check args: */ if (pIOC == NULL) { status = DSP_EPOINTER; } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { status = DSP_EHANDLE; } else if (dwTimeOut == CHNL_IOCNOWAIT) { if (LST_IsEmpty(pChnl->pIOCompletions)) status = CHNL_E_NOIOC; } dev_obj = DEV_GetFirst(); DEV_GetWMDContext(dev_obj, &dev_ctxt); if (!dev_ctxt) status = DSP_EHANDLE; if (DSP_FAILED(status)) goto func_end; ioc.status = CHNL_IOCSTATCOMPLETE; if (dwTimeOut != CHNL_IOCNOWAIT && LST_IsEmpty(pChnl->pIOCompletions)) { if (dwTimeOut == CHNL_IOCINFINITE) dwTimeOut = SYNC_INFINITE; statSync = SYNC_WaitOnEvent(pChnl->hSyncEvent, dwTimeOut); if (statSync == DSP_ETIMEOUT) { /* No response from DSP */ ioc.status |= CHNL_IOCSTATTIMEOUT; fDequeueIOC = false; } else if (statSync == DSP_EFAIL) { /* This can occur when the user mode thread is * aborted (^C), or when _VWIN32_WaitSingleObject() * fails due to unkown causes. */ /* Even though Wait failed, there may be something in * the Q: */ if (LST_IsEmpty(pChnl->pIOCompletions)) { ioc.status |= CHNL_IOCSTATCANCEL; fDequeueIOC = false; } } } /* See comment in AddIOReq */ SYNC_EnterCS(pChnl->pChnlMgr->hCSObj); omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX); if (fDequeueIOC) { /* Dequeue IOC and set pIOC; */ DBC_Assert(!LST_IsEmpty(pChnl->pIOCompletions)); pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIOCompletions); /* Update pIOC from channel state and chirp: */ if (pChirp) { pChnl->cIOCs--; /* If this is a zero-copy channel, then set IOC's pBuf * to the DSP's address. This DSP address will get * translated to user's virtual addr later. */ { pHostSysBuf = pChirp->pHostSysBuf; ioc.pBuf = pChirp->pHostUserBuf; } ioc.cBytes = pChirp->cBytes; ioc.cBufSize = pChirp->cBufSize; ioc.dwArg = pChirp->dwArg; ioc.status |= pChirp->status; /* Place the used chirp on the free list: */ LST_PutTail(pChnl->pFreeList, (struct list_head *)pChirp); } else { ioc.pBuf = NULL; ioc.cBytes = 0; } } else { ioc.pBuf = NULL; ioc.cBytes = 0; ioc.dwArg = 0; ioc.cBufSize = 0; } /* Ensure invariant: If any IOC's are queued for this channel... */ if (!LST_IsEmpty(pChnl->pIOCompletions)) { /* Since DSPStream_Reclaim() does not take a timeout * parameter, we pass the stream's timeout value to * WMD_CHNL_GetIOC. We cannot determine whether or not * we have waited in User mode. Since the stream's timeout * value may be non-zero, we still have to set the event. * Therefore, this optimization is taken out. * * if (dwTimeOut == CHNL_IOCNOWAIT) { * ... ensure event is set.. * SYNC_SetEvent(pChnl->hSyncEvent); * } */ SYNC_SetEvent(pChnl->hSyncEvent); } else { /* else, if list is empty, ensure event is reset. */ SYNC_ResetEvent(pChnl->hSyncEvent); } omap_mbox_enable_irq(dev_ctxt->mbox, IRQ_RX); SYNC_LeaveCS(pChnl->pChnlMgr->hCSObj); if (fDequeueIOC && (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)) { if (!(ioc.pBuf < (void *) USERMODE_ADDR)) goto func_cont; /* If the addr is in user mode, then copy it */ if (!pHostSysBuf || !ioc.pBuf) { status = DSP_EPOINTER; goto func_cont; } if (!CHNL_IsInput(pChnl->uMode)) goto func_cont1; /*pHostUserBuf */ status = copy_to_user(ioc.pBuf, pHostSysBuf, ioc.cBytes); if (status) { if (current->flags & PF_EXITING) status = 0; } if (status) status = DSP_EPOINTER; func_cont1: kfree(pHostSysBuf); } func_cont: /* Update User's IOC block: */ *pIOC = ioc; func_end: return status; }
/* * ======== WMD_CHNL_GetIOC ======== * Optionally wait for I/O completion on a channel. Dequeue an I/O * completion record, which contains information about the completed * I/O request. * Note: Ensures Channel Invariant (see notes above). */ DSP_STATUS WMD_CHNL_GetIOC(struct CHNL_OBJECT *hChnl, u32 dwTimeOut, OUT struct CHNL_IOC *pIOC) { DSP_STATUS status = DSP_SOK; struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; struct CHNL_IRP *pChirp; DSP_STATUS statSync; bool fDequeueIOC = true; struct CHNL_IOC ioc = { NULL, 0, 0, 0, 0 }; u8 *pHostSysBuf = NULL; DBG_Trace(DBG_ENTER, "> WMD_CHNL_GetIOC pChnl %p CHNL_IsOutput %x " "uChnlType %x\n", pChnl, CHNL_IsOutput(pChnl->uMode), pChnl->uChnlType); /* Check args: */ if (pIOC == NULL) { status = DSP_EPOINTER; } else if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { status = DSP_EHANDLE; } else if (dwTimeOut == CHNL_IOCNOWAIT) { if (LST_IsEmpty(pChnl->pIOCompletions)) status = CHNL_E_NOIOC; } if (DSP_FAILED(status)) goto func_end; ioc.status = CHNL_IOCSTATCOMPLETE; if (dwTimeOut != CHNL_IOCNOWAIT && LST_IsEmpty(pChnl->pIOCompletions)) { if (dwTimeOut == CHNL_IOCINFINITE) dwTimeOut = SYNC_INFINITE; statSync = SYNC_WaitOnEvent(pChnl->hSyncEvent, dwTimeOut); if (statSync == DSP_ETIMEOUT) { /* No response from DSP */ ioc.status |= CHNL_IOCSTATTIMEOUT; fDequeueIOC = false; } else if (statSync == DSP_EFAIL) { /* This can occur when the user mode thread is * aborted (^C), or when _VWIN32_WaitSingleObject() * fails due to unkown causes. */ /* Even though Wait failed, there may be something in * the Q: */ if (LST_IsEmpty(pChnl->pIOCompletions)) { ioc.status |= CHNL_IOCSTATCANCEL; fDequeueIOC = false; } } } /* See comment in AddIOReq */ SYNC_EnterCS(pChnl->pChnlMgr->hCSObj); disable_irq(MAILBOX_IRQ); if (fDequeueIOC) { /* Dequeue IOC and set pIOC; */ DBC_Assert(!LST_IsEmpty(pChnl->pIOCompletions)); pChirp = (struct CHNL_IRP *)LST_GetHead(pChnl->pIOCompletions); /* Update pIOC from channel state and chirp: */ if (pChirp) { pChnl->cIOCs--; /* If this is a zero-copy channel, then set IOC's pBuf * to the DSP's address. This DSP address will get * translated to user's virtual addr later. */ { pHostSysBuf = pChirp->pHostSysBuf; ioc.pBuf = pChirp->pHostUserBuf; } ioc.cBytes = pChirp->cBytes; ioc.cBufSize = pChirp->cBufSize; ioc.dwArg = pChirp->dwArg; ioc.status |= pChirp->status; /* Place the used chirp on the free list: */ LST_PutTail(pChnl->pFreeList, (struct LST_ELEM *) pChirp); } else { ioc.pBuf = NULL; ioc.cBytes = 0; } } else { ioc.pBuf = NULL; ioc.cBytes = 0; ioc.dwArg = 0; ioc.cBufSize = 0; } /* Ensure invariant: If any IOC's are queued for this channel... */ if (!LST_IsEmpty(pChnl->pIOCompletions)) { /* Since DSPStream_Reclaim() does not take a timeout * parameter, we pass the stream's timeout value to * WMD_CHNL_GetIOC. We cannot determine whether or not * we have waited in User mode. Since the stream's timeout * value may be non-zero, we still have to set the event. * Therefore, this optimization is taken out. * * if (dwTimeOut == CHNL_IOCNOWAIT) { * ... ensure event is set.. * SYNC_SetEvent(pChnl->hSyncEvent); * } */ SYNC_SetEvent(pChnl->hSyncEvent); } else { /* else, if list is empty, ensure event is reset. */ SYNC_ResetEvent(pChnl->hSyncEvent); } enable_irq(MAILBOX_IRQ); SYNC_LeaveCS(pChnl->pChnlMgr->hCSObj); if (fDequeueIOC && (pChnl->uChnlType == CHNL_PCPY && pChnl->uId > 1)) { if (!(ioc.pBuf < (void *) USERMODE_ADDR)) goto func_cont; /* If the addr is in user mode, then copy it */ if (!pHostSysBuf || !ioc.pBuf) { status = DSP_EPOINTER; DBG_Trace(DBG_LEVEL7, "System buffer NULL in IO completion.\n"); goto func_cont; } if (!CHNL_IsInput(pChnl->uMode)) goto func_cont1; /*pHostUserBuf */ status = copy_to_user(ioc.pBuf, pHostSysBuf, ioc.cBytes); #ifndef RES_CLEANUP_DISABLE if (status) { if (current->flags & PF_EXITING) { DBG_Trace(DBG_LEVEL7, "\n2current->flags == PF_EXITING, " " current->flags;0x%x\n", current->flags); status = 0; } else { DBG_Trace(DBG_LEVEL7, "\n2current->flags != PF_EXITING, " " current->flags;0x%x\n", current->flags); } } #endif if (status) { DBG_Trace(DBG_LEVEL7, "Error copying kernel buffer to user, %d" " bytes remaining. in_interupt %d\n", status, in_interrupt()); status = DSP_EPOINTER; } func_cont1: MEM_Free(pHostSysBuf); } func_cont: /* Update User's IOC block: */ *pIOC = ioc; func_end: DBG_Trace(DBG_ENTER, "< WMD_CHNL_GetIOC pChnl %p\n", pChnl); return status; }
/* * ======== WMD_MSG_Put ======== * Put a message onto a MSG queue. */ DSP_STATUS WMD_MSG_Put(struct MSG_QUEUE *hMsgQueue, IN CONST struct DSP_MSG *pMsg, u32 uTimeout) { struct MSG_FRAME *pMsgFrame; struct MSG_MGR *hMsgMgr; bool fPutMsg = false; struct SYNC_OBJECT *hSyncs[2]; u32 uIndex; DSP_STATUS status = DSP_SOK; DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); DBC_Require(pMsg != NULL); hMsgMgr = hMsgQueue->hMsgMgr; if (!hMsgMgr->msgFreeList) { status = DSP_EHANDLE; goto func_end; } (void) SYNC_EnterCS(hMsgMgr->hSyncCS); /* If a message frame is available, use it */ if (!LST_IsEmpty(hMsgMgr->msgFreeList)) { pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgMgr-> msgFreeList); if (pMsgFrame != NULL) { pMsgFrame->msgData.msg = *pMsg; pMsgFrame->msgData.dwId = hMsgQueue->dwId; LST_PutTail(hMsgMgr->msgUsedList, (struct LST_ELEM *) pMsgFrame); hMsgMgr->uMsgsPending++; fPutMsg = true; } if (LST_IsEmpty(hMsgMgr->msgFreeList)) SYNC_ResetEvent(hMsgMgr->hSyncEvent); /* Release critical section before scheduling DPC */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); /* Schedule a DPC, to do the actual data transfer: */ IO_Schedule(hMsgMgr->hIOMgr); } else { if (hMsgQueue->fDone) status = DSP_EFAIL; else hMsgQueue->refCount++; (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); } if (DSP_SUCCEEDED(status) && !fPutMsg) { /* Wait til a free message frame is available, timeout, * or done */ hSyncs[0] = hMsgMgr->hSyncEvent; hSyncs[1] = hMsgQueue->hSyncDone; status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout, &uIndex); /* Enter critical section */ (void)SYNC_EnterCS(hMsgMgr->hSyncCS); if (hMsgQueue->fDone) { hMsgQueue->refCount--; /* Exit critical section */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); /* Signal that we're not going to access hMsgQueue * anymore, so it can be deleted. */ (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck); status = DSP_EFAIL; } else { if (DSP_SUCCEEDED(status)) { if (LST_IsEmpty(hMsgMgr->msgFreeList)) { status = DSP_EPOINTER; goto func_cont; } /* Get msg from free list */ pMsgFrame = (struct MSG_FRAME *) LST_GetHead(hMsgMgr->msgFreeList); /* Copy message into pMsg and put frame on the * used list */ if (pMsgFrame != NULL) { pMsgFrame->msgData.msg = *pMsg; pMsgFrame->msgData.dwId = hMsgQueue->dwId; LST_PutTail(hMsgMgr->msgUsedList, (struct LST_ELEM *) pMsgFrame); hMsgMgr->uMsgsPending++; /* Schedule a DPC, to do the actual * data transfer: */ IO_Schedule(hMsgMgr->hIOMgr); } } hMsgQueue->refCount--; /* Reset event if there are still frames available */ if (!LST_IsEmpty(hMsgMgr->msgFreeList)) SYNC_SetEvent(hMsgMgr->hSyncEvent); func_cont: /* Exit critical section */ (void) SYNC_LeaveCS(hMsgMgr->hSyncCS); } } func_end: return status; }
/* * ======== WMD_MSG_Get ======== * Get a message from a MSG queue. */ DSP_STATUS WMD_MSG_Get(struct MSG_QUEUE *hMsgQueue, struct DSP_MSG *pMsg, u32 uTimeout) { struct MSG_FRAME *pMsgFrame; struct MSG_MGR *hMsgMgr; bool fGotMsg = false; struct SYNC_OBJECT *hSyncs[2]; u32 uIndex; DSP_STATUS status = DSP_SOK; DBC_Require(MEM_IsValidHandle(hMsgQueue, MSGQ_SIGNATURE)); DBC_Require(pMsg != NULL); hMsgMgr = hMsgQueue->hMsgMgr; if (!hMsgQueue->msgUsedList) { status = DSP_EHANDLE; goto func_end; } /* Enter critical section */ (void)SYNC_EnterCS(hMsgMgr->hSyncCS); /* If a message is already there, get it */ if (!LST_IsEmpty(hMsgQueue->msgUsedList)) { pMsgFrame = (struct MSG_FRAME *)LST_GetHead(hMsgQueue-> msgUsedList); if (pMsgFrame != NULL) { *pMsg = pMsgFrame->msgData.msg; LST_PutTail(hMsgQueue->msgFreeList, (struct LST_ELEM *)pMsgFrame); if (LST_IsEmpty(hMsgQueue->msgUsedList)) SYNC_ResetEvent(hMsgQueue->hSyncEvent); else { NTFY_Notify(hMsgQueue->hNtfy, DSP_NODEMESSAGEREADY); SYNC_SetEvent(hMsgQueue->hSyncEvent); } fGotMsg = true; } } else { if (hMsgQueue->fDone) status = DSP_EFAIL; else hMsgQueue->refCount++; } /* Exit critical section */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); if (DSP_SUCCEEDED(status) && !fGotMsg) { /* Wait til message is available, timeout, or done. We don't * have to schedule the DPC, since the DSP will send messages * when they are available. */ hSyncs[0] = hMsgQueue->hSyncEvent; hSyncs[1] = hMsgQueue->hSyncDone; status = SYNC_WaitOnMultipleEvents(hSyncs, 2, uTimeout, &uIndex); /* Enter critical section */ (void)SYNC_EnterCS(hMsgMgr->hSyncCS); if (hMsgQueue->fDone) { hMsgQueue->refCount--; /* Exit critical section */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); /* Signal that we're not going to access hMsgQueue * anymore, so it can be deleted. */ (void)SYNC_SetEvent(hMsgQueue->hSyncDoneAck); status = DSP_EFAIL; } else { if (DSP_SUCCEEDED(status)) { DBC_Assert(!LST_IsEmpty(hMsgQueue-> msgUsedList)); /* Get msg from used list */ pMsgFrame = (struct MSG_FRAME *) LST_GetHead(hMsgQueue->msgUsedList); /* Copy message into pMsg and put frame on the * free list */ if (pMsgFrame != NULL) { *pMsg = pMsgFrame->msgData.msg; LST_PutTail(hMsgQueue->msgFreeList, (struct LST_ELEM *)pMsgFrame); } } hMsgQueue->refCount--; /* Reset the event if there are still queued messages */ if (!LST_IsEmpty(hMsgQueue->msgUsedList)) { NTFY_Notify(hMsgQueue->hNtfy, DSP_NODEMESSAGEREADY); SYNC_SetEvent(hMsgQueue->hSyncEvent); } /* Exit critical section */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); } } func_end: return status; }
/* * ======== WMD_MSG_CreateQueue ======== * Create a MSG_QUEUE for sending/receiving messages to/from a node * on the DSP. */ DSP_STATUS WMD_MSG_CreateQueue(struct MSG_MGR *hMsgMgr, OUT struct MSG_QUEUE **phMsgQueue, u32 dwId, u32 uMaxMsgs, HANDLE hArg) { u32 i; u32 uNumAllocated = 0; struct MSG_QUEUE *pMsgQ; DSP_STATUS status = DSP_SOK; DBC_Require(MEM_IsValidHandle(hMsgMgr, MSGMGR_SIGNATURE)); DBC_Require(phMsgQueue != NULL); *phMsgQueue = NULL; /* Allocate MSG_QUEUE object */ MEM_AllocObject(pMsgQ, struct MSG_QUEUE, MSGQ_SIGNATURE); if (!pMsgQ) { status = DSP_EMEMORY; goto func_end; } LST_InitElem((struct LST_ELEM *) pMsgQ); pMsgQ->uMaxMsgs = uMaxMsgs; pMsgQ->hMsgMgr = hMsgMgr; pMsgQ->hArg = hArg; /* Node handle */ pMsgQ->dwId = dwId; /* Node env (not valid yet) */ /* Queues of Message frames for messages from the DSP */ pMsgQ->msgFreeList = LST_Create(); pMsgQ->msgUsedList = LST_Create(); if (pMsgQ->msgFreeList == NULL || pMsgQ->msgUsedList == NULL) status = DSP_EMEMORY; /* Create event that will be signalled when a message from * the DSP is available. */ if (DSP_SUCCEEDED(status)) status = SYNC_OpenEvent(&pMsgQ->hSyncEvent, NULL); /* Create a notification list for message ready notification. */ if (DSP_SUCCEEDED(status)) status = NTFY_Create(&pMsgQ->hNtfy); /* Create events that will be used to synchronize cleanup * when the object is deleted. hSyncDone will be set to * unblock threads in MSG_Put() or MSG_Get(). hSyncDoneAck * will be set by the unblocked thread to signal that it * is unblocked and will no longer reference the object. */ if (DSP_SUCCEEDED(status)) status = SYNC_OpenEvent(&pMsgQ->hSyncDone, NULL); if (DSP_SUCCEEDED(status)) status = SYNC_OpenEvent(&pMsgQ->hSyncDoneAck, NULL); if (DSP_SUCCEEDED(status)) { if (!hMsgMgr->msgFreeList) { status = DSP_EHANDLE; goto func_end; } /* Enter critical section */ (void)SYNC_EnterCS(hMsgMgr->hSyncCS); /* Initialize message frames and put in appropriate queues */ for (i = 0; i < uMaxMsgs && DSP_SUCCEEDED(status); i++) { status = AddNewMsg(hMsgMgr->msgFreeList); if (DSP_SUCCEEDED(status)) { uNumAllocated++; status = AddNewMsg(pMsgQ->msgFreeList); } } if (DSP_FAILED(status)) { /* Stay inside CS to prevent others from taking any * of the newly allocated message frames. */ DeleteMsgQueue(pMsgQ, uNumAllocated); } else { LST_PutTail(hMsgMgr->queueList, (struct LST_ELEM *)pMsgQ); *phMsgQueue = pMsgQ; /* Signal that free frames are now available */ if (!LST_IsEmpty(hMsgMgr->msgFreeList)) SYNC_SetEvent(hMsgMgr->hSyncEvent); } /* Exit critical section */ (void)SYNC_LeaveCS(hMsgMgr->hSyncCS); } else { DeleteMsgQueue(pMsgQ, 0); } func_end: return status; }