/* * ======== WMD_CHNL_Close ======== * Purpose: * Ensures all pending I/O on this channel is cancelled, discards all * queued I/O completion notifications, then frees the resources allocated * for this channel, and makes the corresponding logical channel id * available for subsequent use. */ DSP_STATUS WMD_CHNL_Close(struct CHNL_OBJECT *hChnl) { DSP_STATUS status; struct CHNL_OBJECT *pChnl = (struct CHNL_OBJECT *)hChnl; /* Check args: */ if (!MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) { status = DSP_EHANDLE; goto func_cont; } { /* Cancel IO: this ensures no further IO requests or * notifications.*/ status = WMD_CHNL_CancelIO(hChnl); } func_cont: if (DSP_SUCCEEDED(status)) { /* Assert I/O on this channel is now cancelled: Protects * from IO_DPC. */ DBC_Assert((pChnl->dwState & CHNL_STATECANCEL)); /* Invalidate channel object: Protects from * CHNL_GetIOCompletion(). */ pChnl->dwSignature = 0x0000; /* Free the slot in the channel manager: */ pChnl->pChnlMgr->apChannel[pChnl->uId] = NULL; pChnl->pChnlMgr->cOpenChannels -= 1; if (pChnl->hNtfy) { NTFY_Delete(pChnl->hNtfy); pChnl->hNtfy = NULL; } /* Reset channel event: (NOTE: hUserEvent freed in user * context.). */ if (pChnl->hSyncEvent) { SYNC_ResetEvent(pChnl->hSyncEvent); SYNC_CloseEvent(pChnl->hSyncEvent); pChnl->hSyncEvent = NULL; } /* Free I/O request and I/O completion queues: */ if (pChnl->pIOCompletions) { FreeChirpList(pChnl->pIOCompletions); pChnl->pIOCompletions = NULL; pChnl->cIOCs = 0; } if (pChnl->pIORequests) { FreeChirpList(pChnl->pIORequests); pChnl->pIORequests = NULL; pChnl->cIOReqs = 0; } if (pChnl->pFreeList) { FreeChirpList(pChnl->pFreeList); pChnl->pFreeList = NULL; } /* Release channel object. */ MEM_FreeObject(pChnl); pChnl = NULL; } DBC_Ensure(DSP_FAILED(status) || !MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)); return status; }
/* * ======== CreateChirpList ======== * Purpose: * Initialize a queue of channel I/O Request/Completion packets. * Parameters: * uChirps: Number of Chirps to allocate. * Returns: * Pointer to queue of IRPs, or NULL. * Requires: * Ensures: */ static struct LST_LIST *CreateChirpList(u32 uChirps) { struct LST_LIST *pChirpList; struct CHNL_IRP *pChirp; u32 i; pChirpList = MEM_Calloc(sizeof(struct LST_LIST), MEM_NONPAGED); if (pChirpList) { INIT_LIST_HEAD(&pChirpList->head); /* Make N chirps and place on queue. */ for (i = 0; (i < uChirps) && ((pChirp = MakeNewChirp()) != NULL); i++) { LST_PutTail(pChirpList, (struct list_head *)pChirp); } /* If we couldn't allocate all chirps, free those allocated: */ if (i != uChirps) { FreeChirpList(pChirpList); pChirpList = NULL; } } return pChirpList; }
/* * ======== CreateChirpList ======== * Purpose: * Initialize a queue of channel I/O Request/Completion packets. * Parameters: * uChirps: Number of Chirps to allocate. * Returns: * Pointer to queue of IRPs, or NULL. * Requires: * Ensures: */ static struct LST_LIST *CreateChirpList(u32 uChirps) { struct LST_LIST *pChirpList; struct CHNL_IRP *pChirp; u32 i; pChirpList = LST_Create(); if (pChirpList) { /* Make N chirps and place on queue. */ for (i = 0; (i < uChirps) && ((pChirp = MakeNewChirp()) != NULL); i++) { LST_PutTail(pChirpList, (struct LST_ELEM *)pChirp); } /* If we couldn't allocate all chirps, free those allocated: */ if (i != uChirps) { FreeChirpList(pChirpList); pChirpList = NULL; } } return pChirpList; }
/* * ======== WMD_CHNL_Open ======== * Open a new half-duplex channel to the DSP board. */ DSP_STATUS WMD_CHNL_Open(OUT struct CHNL_OBJECT **phChnl, struct CHNL_MGR *hChnlMgr, short int uMode, u32 uChnlId, CONST IN struct CHNL_ATTRS *pAttrs) { DSP_STATUS status = DSP_SOK; struct CHNL_MGR *pChnlMgr = hChnlMgr; struct CHNL_OBJECT *pChnl = NULL; struct SYNC_ATTRS *pSyncAttrs = NULL; struct SYNC_OBJECT *hSyncEvent = NULL; /* Ensure DBC requirements: */ DBC_Require(phChnl != NULL); DBC_Require(pAttrs != NULL); DBC_Require(hChnlMgr != NULL); *phChnl = NULL; /* Validate Args: */ if (pAttrs->uIOReqs == 0) { status = DSP_EINVALIDARG; } else { if (!MEM_IsValidHandle(hChnlMgr, CHNL_MGRSIGNATURE)) { status = DSP_EHANDLE; } else { if (uChnlId != CHNL_PICKFREE) { if (uChnlId >= pChnlMgr->cChannels) status = CHNL_E_BADCHANID; else if (pChnlMgr->apChannel[uChnlId] != NULL) status = CHNL_E_CHANBUSY; } else { /* Check for free channel */ status = SearchFreeChannel(pChnlMgr, &uChnlId); } } } if (DSP_FAILED(status)) goto func_end; DBC_Assert(uChnlId < pChnlMgr->cChannels); /* Create channel object: */ MEM_AllocObject(pChnl, struct CHNL_OBJECT, 0x0000); if (!pChnl) { status = DSP_EMEMORY; goto func_end; } /* Protect queues from IO_DPC: */ pChnl->dwState = CHNL_STATECANCEL; /* Allocate initial IOR and IOC queues: */ pChnl->pFreeList = CreateChirpList(pAttrs->uIOReqs); pChnl->pIORequests = CreateChirpList(0); pChnl->pIOCompletions = CreateChirpList(0); pChnl->cChirps = pAttrs->uIOReqs; pChnl->cIOCs = 0; pChnl->cIOReqs = 0; status = SYNC_OpenEvent(&hSyncEvent, pSyncAttrs); if (DSP_SUCCEEDED(status)) status = NTFY_Create(&pChnl->hNtfy); if (DSP_SUCCEEDED(status)) { if (pChnl->pIOCompletions && pChnl->pIORequests && pChnl->pFreeList) { /* Initialize CHNL object fields: */ pChnl->pChnlMgr = pChnlMgr; pChnl->uId = uChnlId; pChnl->uMode = uMode; pChnl->hUserEvent = hSyncEvent; /* for Linux */ pChnl->hSyncEvent = hSyncEvent; /* Get the process handle */ pChnl->hProcess = current->tgid; pChnl->pCBArg = 0; pChnl->cBytesMoved = 0; /* Default to proc-copy */ pChnl->uChnlType = CHNL_PCPY; } else { status = DSP_EMEMORY; } } if (DSP_FAILED(status)) { /* Free memory */ if (pChnl->pIOCompletions) { FreeChirpList(pChnl->pIOCompletions); pChnl->pIOCompletions = NULL; pChnl->cIOCs = 0; } if (pChnl->pIORequests) { FreeChirpList(pChnl->pIORequests); pChnl->pIORequests = NULL; } if (pChnl->pFreeList) { FreeChirpList(pChnl->pFreeList); pChnl->pFreeList = NULL; } if (hSyncEvent) { SYNC_CloseEvent(hSyncEvent); hSyncEvent = NULL; } if (pChnl->hNtfy) { NTFY_Delete(pChnl->hNtfy); pChnl->hNtfy = NULL; } MEM_FreeObject(pChnl); } else { /* Insert channel object in channel manager: */ pChnlMgr->apChannel[pChnl->uId] = pChnl; SYNC_EnterCS(pChnlMgr->hCSObj); pChnlMgr->cOpenChannels++; SYNC_LeaveCS(pChnlMgr->hCSObj); /* Return result... */ pChnl->dwSignature = CHNL_SIGNATURE; pChnl->dwState = CHNL_STATEREADY; *phChnl = pChnl; } func_end: DBC_Ensure((DSP_SUCCEEDED(status) && MEM_IsValidHandle(pChnl, CHNL_SIGNATURE)) || (*phChnl == NULL)); return status; }