/* * ======== DSP_Deinit ======== * Frees the resources allocated for bridge. */ bool DSP_Deinit(u32 deviceContext) { bool retVal = true; u32 deviceNode; struct MGR_OBJECT *mgrObject = NULL; GT_0trace(curTrace, GT_ENTER, "Entering DSP_Deinit \r\n"); while ((deviceNode = DRV_GetFirstDevExtension()) != 0) { (void)DEV_RemoveDevice((struct CFG_DEVNODE *)deviceNode); (void)DRV_ReleaseResources((u32)deviceNode, (struct DRV_OBJECT *)deviceContext); } (void) DRV_Destroy((struct DRV_OBJECT *) deviceContext); /* Get the Manager Object from Registry * MGR Destroy will unload the DCD dll */ if (DSP_SUCCEEDED(CFG_GetObject((u32 *)&mgrObject, REG_MGR_OBJECT))) (void)MGR_Destroy(mgrObject); WCD_Exit(); return retVal; }
/* * ======== STRM_FreeBuffer ======== * Purpose: * Frees the buffers allocated for a stream. */ DSP_STATUS STRM_FreeBuffer(struct STRM_OBJECT *hStrm, u8 **apBuffer, u32 uNumBufs) { DSP_STATUS status = DSP_SOK; u32 i = 0; #ifndef RES_CLEANUP_DISABLE DSP_STATUS res_status = DSP_SOK; u32 hProcess; HANDLE pCtxt = NULL; HANDLE hDrvObject; HANDLE hSTRMRes = NULL; #endif DBC_Require(cRefs > 0); DBC_Require(apBuffer != NULL); GT_3trace(STRM_debugMask, GT_ENTER, "STRM_FreeBuffer: hStrm: 0x%x\t" "apBuffer: 0x%x\tuNumBufs: 0x%x\n", hStrm, apBuffer, uNumBufs); if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) status = DSP_EHANDLE; if (DSP_SUCCEEDED(status)) { for (i = 0; i < uNumBufs; i++) { DBC_Assert(hStrm->hXlator != NULL); status = CMM_XlatorFreeBuf(hStrm->hXlator, apBuffer[i]); if (DSP_FAILED(status)) { GT_0trace(STRM_debugMask, GT_7CLASS, "STRM_FreeBuffer: DSP_FAILED" " to free shared memory.\n"); break; } apBuffer[i] = NULL; } } #ifndef RES_CLEANUP_DISABLE /* Update the node and stream resource status */ /* Return PID instead of process handle */ hProcess = current->pid; res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_SUCCEEDED(res_status)) { DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, &pCtxt, NULL, 0); if (pCtxt != NULL) { if (DRV_GetSTRMResElement(hStrm, hSTRMRes, pCtxt) != DSP_ENOTFOUND) { DRV_ProcUpdateSTRMRes(uNumBufs-i, hSTRMRes, pCtxt); } } } #endif return status; }
static int __devexit omap34xx_bridge_remove(struct platform_device *pdev) { dev_t devno; bool ret; DSP_STATUS dsp_status = DSP_SOK; HANDLE hDrvObject = NULL; dsp_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_FAILED(dsp_status)) goto func_cont; #ifdef CONFIG_BRIDGE_DVFS if (clk_notifier_unregister(clk_handle, &iva_clk_notifier)) pr_err("%s: clk_notifier_unregister failed for iva2_ck\n", __func__); #endif /* #ifdef CONFIG_BRIDGE_DVFS */ if (driverContext) { /* Put the DSP in reset state */ ret = DSP_Deinit(driverContext); driverContext = 0; DBC_Assert(ret == true); } #ifdef CONFIG_BRIDGE_DVFS clk_put(clk_handle); clk_handle = NULL; #endif func_cont: #ifdef CONFIG_PM /* The suspend wait queue should not have anything waiting on it since remove won't be called while the file is open */ DBC_Assert(!waitqueue_active(&bridge_suspend_data.suspend_wq)); #endif MEM_ExtPhysPoolRelease(); SERVICES_Exit(); GT_exit(); /* Remove driver sysfs entries */ bridge_destroy_sysfs(); devno = MKDEV(driver_major, 0); cdev_del(&bridge_cdev); unregister_chrdev_region(devno, 1); if (bridge_class) { /* remove the device from sysfs */ device_destroy(bridge_class, MKDEV(driver_major, 0)); class_destroy(bridge_class); } return 0; }
/* * ======== STRM_Open ======== * Purpose: * Open a stream for sending/receiving data buffers to/from a task or * XDAIS socket node on the DSP. */ DSP_STATUS STRM_Open(struct NODE_OBJECT *hNode, u32 uDir, u32 uIndex, IN struct STRM_ATTR *pAttr, OUT struct STRM_OBJECT **phStrm) { struct STRM_MGR *hStrmMgr; struct WMD_DRV_INTERFACE *pIntfFxns; u32 ulChnlId; struct STRM_OBJECT *pStrm = NULL; CHNL_MODE uMode; struct CHNL_ATTRS chnlAttrs; DSP_STATUS status = DSP_SOK; struct CMM_OBJECT *hCmmMgr = NULL; /* Shared memory manager hndl */ #ifndef RES_CLEANUP_DISABLE DSP_STATUS res_status = DSP_SOK; u32 hProcess; HANDLE pCtxt = NULL; HANDLE hDrvObject; HANDLE hSTRMRes; #endif DBC_Require(cRefs > 0); DBC_Require(phStrm != NULL); DBC_Require(pAttr != NULL); GT_5trace(STRM_debugMask, GT_ENTER, "STRM_Open: hNode: 0x%x\tuDir: 0x%x\t" "uIndex: 0x%x\tpAttr: 0x%x\tphStrm: 0x%x\n", hNode, uDir, uIndex, pAttr, phStrm); *phStrm = NULL; if (uDir != DSP_TONODE && uDir != DSP_FROMNODE) { status = DSP_EDIRECTION; } else { /* Get the channel id from the node (set in NODE_Connect()) */ status = NODE_GetChannelId(hNode, uDir, uIndex, &ulChnlId); } if (DSP_SUCCEEDED(status)) status = NODE_GetStrmMgr(hNode, &hStrmMgr); if (DSP_SUCCEEDED(status)) { MEM_AllocObject(pStrm, struct STRM_OBJECT, STRM_SIGNATURE); if (pStrm == NULL) { status = DSP_EMEMORY; GT_0trace(STRM_debugMask, GT_6CLASS, "STRM_Open: MEM_AllocObject() failed!\n "); } else { pStrm->hStrmMgr = hStrmMgr; pStrm->uDir = uDir; pStrm->strmState = STREAM_IDLE; pStrm->hUserEvent = pAttr->hUserEvent; if (pAttr->pStreamAttrIn != NULL) { pStrm->uTimeout = pAttr->pStreamAttrIn-> uTimeout; pStrm->uNumBufs = pAttr->pStreamAttrIn-> uNumBufs; pStrm->lMode = pAttr->pStreamAttrIn->lMode; pStrm->uSegment = pAttr->pStreamAttrIn-> uSegment; pStrm->uAlignment = pAttr->pStreamAttrIn-> uAlignment; pStrm->uDMAChnlId = pAttr->pStreamAttrIn-> uDMAChnlId; pStrm->uDMAPriority = pAttr->pStreamAttrIn-> uDMAPriority; chnlAttrs.uIOReqs = pAttr->pStreamAttrIn-> uNumBufs; } else { pStrm->uTimeout = DEFAULTTIMEOUT; pStrm->uNumBufs = DEFAULTNUMBUFS; pStrm->lMode = STRMMODE_PROCCOPY; pStrm->uSegment = 0; /* local memory */ pStrm->uAlignment = 0; pStrm->uDMAChnlId = 0; pStrm->uDMAPriority = 0; chnlAttrs.uIOReqs = DEFAULTNUMBUFS; } chnlAttrs.hReserved1 = NULL; /* DMA chnl flush timeout */ chnlAttrs.hReserved2 = pStrm->uTimeout; chnlAttrs.hEvent = NULL; if (pAttr->hUserEvent != NULL) chnlAttrs.hEvent = pAttr->hUserEvent; } } if (DSP_FAILED(status)) goto func_cont; if ((pAttr->pVirtBase == NULL) || !(pAttr->ulVirtSize > 0)) goto func_cont; DBC_Assert(pStrm->lMode != STRMMODE_LDMA); /* no System DMA */ /* Get the shared mem mgr for this streams dev object */ status = DEV_GetCmmMgr(hStrmMgr->hDev, &hCmmMgr); if (DSP_FAILED(status)) { GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Open: Failed to get " "CMM Mgr handle: 0x%x\n", status); } else { /*Allocate a SM addr translator for this strm.*/ status = CMM_XlatorCreate(&pStrm->hXlator, hCmmMgr, NULL); if (DSP_FAILED(status)) { GT_1trace(STRM_debugMask, GT_6CLASS, "STRM_Open: Failed to " "create SM translator: 0x%x\n", status); } else { DBC_Assert(pStrm->uSegment > 0); /* Set translators Virt Addr attributes */ status = CMM_XlatorInfo(pStrm->hXlator, (u8 **)&pAttr->pVirtBase, pAttr->ulVirtSize, pStrm->uSegment, true); if (status != DSP_SOK) { GT_0trace(STRM_debugMask, GT_6CLASS, "STRM_Open: ERROR: " "in setting CMM_XlatorInfo.\n"); } } } func_cont: if (DSP_SUCCEEDED(status)) { /* Open channel */ uMode = (uDir == DSP_TONODE) ? CHNL_MODETODSP : CHNL_MODEFROMDSP; pIntfFxns = hStrmMgr->pIntfFxns; status = (*pIntfFxns->pfnChnlOpen) (&(pStrm->hChnl), hStrmMgr->hChnlMgr, uMode, ulChnlId, &chnlAttrs); if (DSP_FAILED(status)) { /* * over-ride non-returnable status codes so we return * something documented */ if (status != DSP_EMEMORY && status != DSP_EINVALIDARG && status != DSP_EFAIL) { /* * We got a status that's not return-able. * Assert that we got something we were * expecting (DSP_EHANDLE isn't acceptable, * hStrmMgr->hChnlMgr better be valid or we * assert here), and then return DSP_EFAIL. */ DBC_Assert(status == CHNL_E_OUTOFSTREAMS || status == CHNL_E_BADCHANID || status == CHNL_E_CHANBUSY || status == CHNL_E_NOIORPS); status = DSP_EFAIL; } GT_2trace(STRM_debugMask, GT_6CLASS, "STRM_Open: Channel open failed, " "chnl id = %d, status = 0x%x\n", ulChnlId, status); } } if (DSP_SUCCEEDED(status)) *phStrm = pStrm; else (void)DeleteStrm(pStrm); #ifndef RES_CLEANUP_DISABLE /* Return PID instead of process handle */ hProcess = current->pid; res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_SUCCEEDED(res_status)) { DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, &pCtxt, hNode, 0); if (pCtxt != NULL) DRV_ProcInsertSTRMResElement(*phStrm, &hSTRMRes, pCtxt); } #endif /* ensure we return a documented error code */ DBC_Ensure((DSP_SUCCEEDED(status) && MEM_IsValidHandle((*phStrm), STRM_SIGNATURE)) || (*phStrm == NULL && (status == DSP_EHANDLE || status == DSP_EDIRECTION || status == DSP_EVALUE || status == DSP_EFAIL))); return status; }
/* * ======== STRM_Close ======== * Purpose: * Close a stream opened with STRM_Open(). */ DSP_STATUS STRM_Close(struct STRM_OBJECT *hStrm) { struct WMD_DRV_INTERFACE *pIntfFxns; struct CHNL_INFO chnlInfo; DSP_STATUS status = DSP_SOK; #ifndef RES_CLEANUP_DISABLE u32 hProcess; HANDLE pCtxt = NULL; HANDLE hDrvObject; HANDLE hSTRMRes; DSP_STATUS res_status = DSP_SOK; #endif DBC_Require(cRefs > 0); GT_1trace(STRM_debugMask, GT_ENTER, "STRM_Close: hStrm: 0x%x\n", hStrm); if (!MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { status = DSP_EHANDLE; } else { /* Have all buffers been reclaimed? If not, return * DSP_EPENDING */ pIntfFxns = hStrm->hStrmMgr->pIntfFxns; status = (*pIntfFxns->pfnChnlGetInfo) (hStrm->hChnl, &chnlInfo); DBC_Assert(DSP_SUCCEEDED(status)); if (chnlInfo.cIOCs > 0 || chnlInfo.cIOReqs > 0) { status = DSP_EPENDING; } else { status = DeleteStrm(hStrm); if (DSP_FAILED(status)) { /* we already validated the handle. */ DBC_Assert(status != DSP_EHANDLE); /* make sure we return a documented result */ status = DSP_EFAIL; } } } #ifndef RES_CLEANUP_DISABLE if (DSP_FAILED(status)) goto func_end; /* Update the node and stream resource status */ /* Return PID instead of process handle */ hProcess = current->pid; res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_FAILED(res_status)) goto func_end; DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, &pCtxt, NULL, 0); if (pCtxt != NULL) { if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) != DSP_ENOTFOUND) { DRV_ProcRemoveSTRMResElement(hSTRMRes, pCtxt); } } func_end: #endif DBC_Ensure(status == DSP_SOK || status == DSP_EHANDLE || status == DSP_EPENDING || status == DSP_EFAIL); return status; }
/* * ======== STRM_AllocateBuffer ======== * Purpose: * Allocates buffers for a stream. */ DSP_STATUS STRM_AllocateBuffer(struct STRM_OBJECT *hStrm, u32 uSize, OUT u8 **apBuffer, u32 uNumBufs) { DSP_STATUS status = DSP_SOK; u32 uAllocated = 0; u32 i; #ifndef RES_CLEANUP_DISABLE DSP_STATUS res_status = DSP_SOK; u32 hProcess; HANDLE pCtxt = NULL; HANDLE hDrvObject; HANDLE hSTRMRes; #endif DBC_Require(cRefs > 0); DBC_Require(apBuffer != NULL); GT_4trace(STRM_debugMask, GT_ENTER, "STRM_AllocateBuffer: hStrm: 0x%x\t" "uSize: 0x%x\tapBuffer: 0x%x\tuNumBufs: 0x%x\n", hStrm, uSize, apBuffer, uNumBufs); if (MEM_IsValidHandle(hStrm, STRM_SIGNATURE)) { /* * Allocate from segment specified at time of stream open. */ if (uSize == 0) status = DSP_ESIZE; } if (DSP_FAILED(status)) { status = DSP_EHANDLE; goto func_end; } for (i = 0; i < uNumBufs; i++) { DBC_Assert(hStrm->hXlator != NULL); (void)CMM_XlatorAllocBuf(hStrm->hXlator, &apBuffer[i], uSize); if (apBuffer[i] == NULL) { GT_0trace(STRM_debugMask, GT_7CLASS, "STRM_AllocateBuffer: " "DSP_FAILED to alloc shared memory.\n"); status = DSP_EMEMORY; uAllocated = i; break; } } if (DSP_FAILED(status)) STRM_FreeBuffer(hStrm, apBuffer, uAllocated); #ifndef RES_CLEANUP_DISABLE if (DSP_FAILED(status)) goto func_end; /* Return PID instead of process handle */ hProcess = current->pid; res_status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_FAILED(res_status)) goto func_end; DRV_GetProcContext(hProcess, (struct DRV_OBJECT *)hDrvObject, &pCtxt, NULL, 0); if (pCtxt != NULL) { if (DRV_GetSTRMResElement(hStrm, &hSTRMRes, pCtxt) != DSP_ENOTFOUND) { DRV_ProcUpdateSTRMRes(uNumBufs, hSTRMRes, pCtxt); } } #endif func_end: return status; }
/* * ======== MGR_EnumProcessorInfo ======== * Enumerate and get configuration information about available * DSP processors. */ DSP_STATUS MGR_EnumProcessorInfo(u32 uProcessor, OUT struct DSP_PROCESSORINFO *pProcessorInfo, u32 uProcessorInfoSize, OUT u32 *puNumProcs) { DSP_STATUS status = DSP_SOK; DSP_STATUS status1 = DSP_SOK; DSP_STATUS status2 = DSP_SOK; struct DSP_UUID uTempUuid; u32 uTempIndex = 0; u32 uProcIndex = 0; struct DCD_GENERICOBJ GenObj; struct MGR_OBJECT *pMgrObject = NULL; struct MGR_PROCESSOREXTINFO *pExtInfo; struct DEV_OBJECT *hDevObject; struct DRV_OBJECT *hDrvObject; s32 devType; struct CFG_DEVNODE *devNode; struct CFG_DSPRES chipResources; bool procDetect = false; DBC_Require(pProcessorInfo != NULL); DBC_Require(puNumProcs != NULL); DBC_Require(uProcessorInfoSize >= sizeof(struct DSP_PROCESSORINFO)); DBC_Require(cRefs > 0); GT_4trace(MGR_DebugMask, GT_ENTER, "Entered Manager_EnumProcessorInfo, " "args:\n\tuProcessor: 0x%x\n\tpProcessorInfo: 0x%x\n\t" "uProcessorInfoSize: 0x%x\tpuNumProcs: 0x%x\n", uProcessor, pProcessorInfo, uProcessorInfoSize, puNumProcs); *puNumProcs = 0; status = CFG_GetObject((u32 *)&hDrvObject, REG_DRV_OBJECT); if (DSP_SUCCEEDED(status)) { status = DRV_GetDevObject(uProcessor, hDrvObject, &hDevObject); if (DSP_SUCCEEDED(status)) { status = DEV_GetDevType(hDevObject, (u32 *) &devType); status = DEV_GetDevNode(hDevObject, &devNode); if (devType == DSP_UNIT) { status = CFG_GetDSPResources(devNode, &chipResources); } else { status = DSP_EFAIL; GT_1trace(MGR_DebugMask, GT_7CLASS, "Unsupported dev type gotten" "from device object %d\n", devType); } if (DSP_SUCCEEDED(status)) { pProcessorInfo->uProcessorType = chipResources.uChipType; } } } if (DSP_FAILED(status)) goto func_end; /* Get The Manager Object from the Registry */ if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject, REG_MGR_OBJECT))) { GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumProcessorInfo: " "Failed To Get MGR Object from Registry\r\n"); goto func_end; } DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE)); /* Forever loop till we hit no more items in the * Enumeration. We will exit the loop other than DSP_SOK; */ while (status1 == DSP_SOK) { status1 = DCD_EnumerateObject(uTempIndex++, DSP_DCDPROCESSORTYPE, &uTempUuid); if (status1 != DSP_SOK) break; uProcIndex++; /* Get the Object properties to find the Device/Processor * Type */ if (procDetect != false) continue; status2 = DCD_GetObjectDef(pMgrObject->hDcdMgr, (struct DSP_UUID *)&uTempUuid, DSP_DCDPROCESSORTYPE, &GenObj); if (DSP_SUCCEEDED(status2)) { /* Get the Obj def */ if (uProcessorInfoSize < sizeof(struct MGR_PROCESSOREXTINFO)) { *pProcessorInfo = GenObj.objData.procObj; } else { /* extended info */ pExtInfo = (struct MGR_PROCESSOREXTINFO *) pProcessorInfo; *pExtInfo = GenObj.objData.extProcObj; } GT_1trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumProcessorInfo: Got" " Proctype from DCD %x \r\n", pProcessorInfo->uProcessorType); /* See if we got the needed processor */ if (devType == DSP_UNIT) { if (pProcessorInfo->uProcessorType == DSPPROCTYPE_C64) procDetect = true; } else if (devType == IVA_UNIT) { if (pProcessorInfo->uProcessorType == IVAPROCTYPE_ARM7) procDetect = true; } /* User applciatiuons aonly check for chip type, so * this clumsy overwrite */ pProcessorInfo->uProcessorType = chipResources.uChipType; } else { GT_1trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumProcessorInfo: " "Failed to Get DCD Processor Info %x \r\n", status2); status = DSP_EFAIL; } } *puNumProcs = uProcIndex; if (procDetect == false) { GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumProcessorInfo: Failed" " to get Proc info from DCD , so use CFG registry\n"); pProcessorInfo->uProcessorType = chipResources.uChipType; } func_end: return status; }
/* * ======== MGR_EnumNodeInfo ======== * Enumerate and get configuration information about nodes configured * in the node database. */ DSP_STATUS MGR_EnumNodeInfo(u32 uNode, OUT struct DSP_NDBPROPS *pNDBProps, u32 uNDBPropsSize, OUT u32 *puNumNodes) { DSP_STATUS status = DSP_SOK; DSP_STATUS status1 = DSP_SOK; struct DSP_UUID Uuid, uTempUuid; u32 uTempIndex = 0; u32 uNodeIndex = 0; struct DCD_GENERICOBJ GenObj; struct MGR_OBJECT *pMgrObject = NULL; DBC_Require(pNDBProps != NULL); DBC_Require(puNumNodes != NULL); DBC_Require(uNDBPropsSize >= sizeof(struct DSP_NDBPROPS)); DBC_Require(cRefs > 0); GT_4trace(MGR_DebugMask, GT_ENTER, "Entered Manager_EnumNodeInfo, " "args:\n\t uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:" "0x%x\tpuNumNodes: 0x%x\n", uNode, pNDBProps, uNDBPropsSize, puNumNodes); *puNumNodes = 0; /* Get The Manager Object from the Registry */ if (DSP_FAILED(CFG_GetObject((u32 *)&pMgrObject, REG_MGR_OBJECT))) { GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo:Failed To Get" " MGR Object from Registry\r\n"); goto func_cont; } DBC_Assert(MEM_IsValidHandle(pMgrObject, SIGNATURE)); /* Forever loop till we hit failed or no more items in the * Enumeration. We will exit the loop other than DSP_SOK; */ while (status == DSP_SOK) { status = DCD_EnumerateObject(uTempIndex++, DSP_DCDNODETYPE, &uTempUuid); if (status == DSP_SOK) { uNodeIndex++; if (uNode == (uNodeIndex - 1)) Uuid = uTempUuid; } } if (DSP_SUCCEEDED(status)) { if (uNode > (uNodeIndex - 1)) { status = DSP_EINVALIDARG; GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo: uNode" " is Invalid \r\n"); } else { status1 = DCD_GetObjectDef(pMgrObject->hDcdMgr, (struct DSP_UUID *)&Uuid, DSP_DCDNODETYPE, &GenObj); if (DSP_SUCCEEDED(status1)) { /* Get the Obj def */ *pNDBProps = GenObj.objData.nodeObj.ndbProps; *puNumNodes = uNodeIndex; status = DSP_SOK; } else { GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo: " "Failed to Get Node Info \r\n"); status = DSP_EFAIL; } } } else { /* This could be changed during enum, EFAIL ... */ GT_0trace(MGR_DebugMask, GT_7CLASS, "Manager_EnumNodeInfo: " "Enumeration failure\r\n"); status = DSP_EFAIL; } func_cont: GT_4trace(MGR_DebugMask, GT_ENTER, "Exiting Manager_EnumNodeInfo, args:\n\t" "uNode: 0x%x\n\tpNDBProps: 0x%x\n\tuNDBPropsSize:" " 0x%x\tuNumNodes: 0x%x\n", uNode, pNDBProps, uNDBPropsSize, *puNumNodes); DBC_Ensure((DSP_SUCCEEDED(status) && *puNumNodes > 0) || (DSP_FAILED(status) && *puNumNodes == 0)); return status; }