//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsGetEventsObject -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // static DtuEvents* DtuEventsGetEventsObject( DtuDeviceData* pDvcData, DtFileObject* pFile) { Int i; DtuEvents* pDtuEvents = NULL; for (i=0; i<MAX_NUM_FILE_HANDLES; i++) { DtSpinLockAcquire(&pDvcData->m_Events[i].m_Lock); if (pDvcData->m_Events[i].m_RefCount > 0) { if (DtFileCompare(&pDvcData->m_Events[i].m_File, pFile)) { pDtuEvents = &pDvcData->m_Events[i]; // Increment refcount pDtuEvents->m_RefCount++; } } DtSpinLockRelease(&pDvcData->m_Events[i].m_Lock); if (pDtuEvents != NULL) break; } return pDtuEvents; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsUnrefEventsObject -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // static void DtuEventsUnrefEventsObject(DtuDeviceData* pDvcData, DtuEvents* pDtuEvents) { DtSpinLockAcquire(&pDtuEvents->m_Lock); if (pDtuEvents->m_RefCount > 0) pDtuEvents->m_RefCount--; DtSpinLockRelease(&pDtuEvents->m_Lock); }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsAllocEventsObject -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // static DtuEvents* DtuEventsAllocEventsObject( DtuDeviceData* pDvcData, DtFileObject* pFileHandle, UInt EventTypeMask) { Int i; DtuEvents* pDtuEvents = NULL; for (i=0; i<MAX_NUM_FILE_HANDLES; i++) { DtSpinLockAcquire(&pDvcData->m_Events[i].m_Lock); if (pDvcData->m_Events[i].m_RefCount == 0) { pDtuEvents = &pDvcData->m_Events[i]; pDtuEvents->m_RefCount = 2; // Start with 2 to prevent removal after first unref pDtuEvents->m_File = *pFileHandle; pDtuEvents->m_EventTypeMask = EventTypeMask; pDtuEvents->m_CancelInProgress = FALSE; pDtuEvents->m_NumPendingEvents = 0; memset(&pDtuEvents->m_PendingEvents, 0, sizeof(pDtuEvents->m_PendingEvents)); } DtSpinLockRelease(&pDvcData->m_Events[i].m_Lock); if (pDtuEvents != NULL) break; } return pDtuEvents; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEventsSet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // This function adds new events to the pending events. // DtStatus DtaEventsSet( DtaDeviceData* pDvcData, DtFileObject* pFile, UInt EventType, UInt Value1, UInt Value2) { DtStatus Result = DT_STATUS_OK; DtaEvents* pDtaEvents = NULL; DtDbgOut(MAX, EVENTS, "Start"); DtDbgOut(AVG, EVENTS, "EventType: %i, Value1: %i, Value2: %i", EventType, Value1, Value2); if (pFile != NULL) { // Get corresponding events object pDtaEvents = DtaEventsGetEventsObject(pDvcData, pFile); if (pDtaEvents == NULL) Result = DT_STATUS_NOT_FOUND; else { Result = DtaEventsSetEvent(pDtaEvents, EventType, Value1, Value2); #ifdef WINBUILD if (pDtaEvents->m_NumPendingEvents != 0) { // Dequeue pending events pFile = &pDtaEvents->m_File; DtaEventsDequeue(pDvcData, pFile, pDtaEvents); } #endif DtaEventsUnrefEventsObject(pDvcData, pDtaEvents); } } else { // Set event for all file handles DtSpinLockAcquire(&pDvcData->m_EventsSpinlock); pDtaEvents = pDvcData->m_pEvents; while (pDtaEvents != NULL) { // Set event Result = DtaEventsSetEvent(pDtaEvents, EventType, Value1, Value2); #ifdef WINBUILD if (pDtaEvents->m_NumPendingEvents != 0) { // Dequeue pending events pFile = &pDtaEvents->m_File; DtaEventsDequeue(pDvcData, pFile, pDtaEvents); } #endif pDtaEvents = pDtaEvents->m_pNext; } DtSpinLockRelease(&pDvcData->m_EventsSpinlock); } DtDbgOut(MAX, EVENTS, "Exit"); return Result; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsSetEvent -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // static DtStatus DtuEventsSetEvent( DtuEvents* pDtuEvents, UInt EventType, UInt Value1, UInt Value2) { DtuEvent* pDtuEvent; // Skip unregistered events if ((EventType & pDtuEvents->m_EventTypeMask) != 0) { DtSpinLockAcquire(&pDtuEvents->m_Lock); if (EventType == DTU_EVENT_TYPE_IOCONFIG) { UInt i; for (i=0; i<pDtuEvents->m_NumPendingEvents; i++) { if (pDtuEvents->m_PendingEvents[i].m_EventType==DTU_EVENT_TYPE_IOCONFIG && pDtuEvents->m_PendingEvents[i].m_EventValue1==Value1) { // Event is already pending, don't create a duplicate DtSpinLockRelease(&pDtuEvents->m_Lock); return DT_STATUS_OK; } } } // Add new events if (pDtuEvents->m_NumPendingEvents == MAX_PENDING_EVENTS) { // Remove oldest event DtDbgOut(AVG, EVENTS, "Max. number of events. Remove old event"); DtMemMove(&pDtuEvents->m_PendingEvents[0], &pDtuEvents->m_PendingEvents[1], sizeof(DtuEvent) * (MAX_PENDING_EVENTS - 1)); pDtuEvent = &pDtuEvents->m_PendingEvents[MAX_PENDING_EVENTS - 1]; } else { pDtuEvent = &pDtuEvents->m_PendingEvents[pDtuEvents->m_NumPendingEvents]; pDtuEvents->m_NumPendingEvents++; } DtDbgOut(MAX, EVENTS, "New event #%d. Type: %d, Value1: %d, Value2: %d", pDtuEvents->m_NumPendingEvents, EventType, Value1, Value2); pDtuEvent->m_EventType = EventType; pDtuEvent->m_EventValue1 = Value1; pDtuEvent->m_EventValue2 = Value2; // Trigger wait function if it was waiting DtEventSet(&pDtuEvents->m_PendingEvent); DtSpinLockRelease(&pDtuEvents->m_Lock); } return DT_STATUS_OK; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEncD7ProExclusiveAccess -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtaEnDecExclusiveAccess( DtaNonIpPort* pNonIpPort, DtFileObject* pFile, Int Cmd) { DtStatus Result = DT_STATUS_OK; DtaEnDecPort* pEnDec = &pNonIpPort->m_EnDec; DtSpinLockAcquire(&pEnDec->m_ExclAccessLock); if (Cmd == DTA_EXCLUSIVE_ACCESS_CMD_ACQUIRE) { if (!pEnDec->m_ExclAccess) { pEnDec->m_ExclAccess = TRUE; pEnDec->m_ExclAccessOwner = *pFile; } else Result = DT_STATUS_IN_USE; } else if (Cmd == DTA_EXCLUSIVE_ACCESS_CMD_RELEASE) { if (pEnDec->m_ExclAccess) { if (DtFileCompare(&pEnDec->m_ExclAccessOwner, pFile)) { pEnDec->m_ExclAccess = FALSE; } else Result = DT_STATUS_IN_USE; } } else if (Cmd == DTA_EXCLUSIVE_ACCESS_CMD_PROBE) { if (pEnDec->m_ExclAccess) Result = DT_STATUS_IN_USE; } else if (Cmd == DTA_EXCLUSIVE_ACCESS_CMD_CHECK) { if (!pNonIpPort->m_ExclAccess) Result = DT_STATUS_EXCL_ACCESS_REQD; else if (!DtFileCompare(&pEnDec->m_ExclAccessOwner, pFile)) Result = DT_STATUS_IN_USE; } else Result = DT_STATUS_NOT_SUPPORTED; DtSpinLockRelease(&pEnDec->m_ExclAccessLock); return Result; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaNonIpTxGetFlags -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // DtStatus DtaNonIpTxGetFlags(DtaNonIpPort* pNonIpPort, Int* pStatus, Int* pLatched) { // Update flags DtaNonIpTxProcessFlagsFromUser(pNonIpPort); // Update DMA pending status //if (NonIpTxIsDmaPending(pNonIpPort)) // pNonIpPort->m_Flags |= DTA_TX_DMA_PENDING; DtSpinLockAcquire(&pNonIpPort->m_FlagsSpinLock); // Return flags *pStatus = pNonIpPort->m_Flags; *pLatched = pNonIpPort->m_FlagsLatched; DtSpinLockRelease(&pNonIpPort->m_FlagsSpinLock); return DT_STATUS_OK; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEventsUnregister -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // void DtaEventsUnregister(DtaDeviceData* pDvcData, DtFileObject* pFile) { DtaEvents* pDtaEvents = NULL; DtSpinLockAcquire(&pDvcData->m_EventsSpinlock); pDtaEvents = pDvcData->m_pEvents; while (pDtaEvents != NULL) { if (DtFileCompare(&pDtaEvents->m_File, pFile)) break; pDtaEvents = pDtaEvents->m_pNext; } if (pDtaEvents == NULL) { DtSpinLockRelease(&pDvcData->m_EventsSpinlock); return; } // Remove events struct from linked list while holding the spinlock if (pDtaEvents->m_pPrev != NULL) pDtaEvents->m_pPrev->m_pNext = pDtaEvents->m_pNext; else pDvcData->m_pEvents = pDtaEvents->m_pNext; if (pDtaEvents->m_pNext != NULL) pDtaEvents->m_pNext->m_pPrev = pDtaEvents->m_pPrev; pDtaEvents->m_pPrev = NULL; pDtaEvents->m_pNext = NULL; DtSpinLockRelease(&pDvcData->m_EventsSpinlock); // Even if two threads call DtaEventsUnregister at the same time we'll only come here // once. We remove the DtaEvents object from the linked-list while holding the // spinlock, so the second thread won't find the object and return immediately. // Signal pending event (will remove object if event was pending) DtaEventsGetCancel(pDvcData, pFile); // Decrement refcount to free object as soon as it's no longer in use DtaEventsUnrefEventsObject(pDvcData, pDtaEvents); }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEventsSetEvent -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // static DtStatus DtaEventsSetEvent( DtaEvents* pDtaEvents, UInt EventType, UInt Value1, UInt Value2) { DtStatus Result = DT_STATUS_OK; DtaEvent* pDtaEvent; // Skip unregistered events if ((EventType & pDtaEvents->m_EventTypeMask) != 0) { DtSpinLockAcquire(&pDtaEvents->m_Lock); // Add new events if (pDtaEvents->m_NumPendingEvents == MAX_PENDING_EVENTS) { // Remove oldest event DtDbgOut(AVG, EVENTS, "Max. number of events. Remove old event"); DtMemMove(&pDtaEvents->m_PendingEvents[0], &pDtaEvents->m_PendingEvents[1], sizeof(DtaEvent) * (MAX_PENDING_EVENTS - 1)); pDtaEvent = &pDtaEvents->m_PendingEvents[MAX_PENDING_EVENTS - 1]; } else { pDtaEvent = &pDtaEvents->m_PendingEvents[pDtaEvents->m_NumPendingEvents]; pDtaEvents->m_NumPendingEvents++; } DtDbgOut(MAX, EVENTS, "New event #%d. Type: %d, Value1: %d, Value2: %d", pDtaEvents->m_NumPendingEvents, EventType, Value1, Value2); pDtaEvent->m_EventType = EventType; pDtaEvent->m_EventValue1 = Value1; pDtaEvent->m_EventValue2 = Value2; // Trigger wait function if it was waiting DtEventSet(&pDtaEvents->m_PendingEvent); DtSpinLockRelease(&pDtaEvents->m_Lock); } return Result; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsUnregister -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // void DtuEventsUnregister(DtuDeviceData* pDvcData, DtFileObject* pFile) { DtuEvents* pDtuEvents; // We force the Pending event to be signaled. pDtuEvents = DtuEventsGetEventsObject(pDvcData, pFile); if (pDtuEvents == NULL) return; // Decrement initial refcount to mark unused after last unreference DtSpinLockAcquire(&pDtuEvents->m_Lock); if (pDtuEvents->m_RefCount > 0) pDtuEvents->m_RefCount--; DtSpinLockRelease(&pDtuEvents->m_Lock); // Decrement refcount DtuEventsUnrefEventsObject(pDvcData, pDtuEvents); // Signal pending event (will remove object if event was pending) DtuEventsGetCancel(pDvcData, pFile); }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEnDecClose -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtaEnDecClose(DtaNonIpPort* pNonIpPort, DtFileObject* pFile) { DtaEnDecPort* pEnDec = &pNonIpPort->m_EnDec; DtSpinLockAcquire(&pEnDec->m_ExclAccessLock); if (!pEnDec->m_ExclAccess || !DtFileCompare(&pEnDec->m_ExclAccessOwner, pFile)) { DtSpinLockRelease(&pEnDec->m_ExclAccessLock); return DT_STATUS_OK; } if (pNonIpPort->m_pDvcData->m_DevInfo.m_TypeNumber == 2180 || pNonIpPort->m_pDvcData->m_DevInfo.m_TypeNumber == 2182) DtaEncD7ProUncleanDetach(pNonIpPort); pEnDec->m_ExclAccess = FALSE; DtSpinLockRelease(&pEnDec->m_ExclAccessLock); return DT_STATUS_OK; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEventsGetEventsObject -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // static DtaEvents* DtaEventsGetEventsObject( DtaDeviceData* pDvcData, DtFileObject* pFile) { DtaEvents* pDtaEvents = NULL; DtSpinLockAcquire(&pDvcData->m_EventsSpinlock); pDtaEvents = pDvcData->m_pEvents; while (pDtaEvents != NULL) { if (DtFileCompare(&pDtaEvents->m_File, pFile)) { // Increment refcount DtAtomicIncrement(&pDtaEvents->m_RefCount); break; } pDtaEvents = pDtaEvents->m_pNext; } DtSpinLockRelease(&pDvcData->m_EventsSpinlock); return pDtaEvents; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaEventsAllocEventsObject -.-.-.-.-.-.-.-.-.-.-.-.-.-.-. // static DtaEvents* DtaEventsAllocEventsObject( DtaDeviceData* pDvcData, DtFileObject* pFileHandle, UInt EventTypeMask) { DtaEvents* pDtaEvents; pDtaEvents = (DtaEvents*)DtMemAllocPool(DtPoolNonPaged, sizeof(DtaEvents), DTA_TAG); if (pDtaEvents == NULL) { DtDbgOut(ERR, EVENTS, "Out of memory allocating DtaEvents struct"); return NULL; } DtAtomicSet(&pDtaEvents->m_RefCount, 1); pDtaEvents->m_File = *pFileHandle; pDtaEvents->m_EventTypeMask = EventTypeMask; pDtaEvents->m_CancelInProgress = FALSE; pDtaEvents->m_NumPendingEvents = 0; DtEventInit(&pDtaEvents->m_PendingEvent, FALSE); DtSpinLockInit(&pDtaEvents->m_Lock); memset(&pDtaEvents->m_PendingEvents, 0, sizeof(pDtaEvents->m_PendingEvents)); // Insert at start of list DtSpinLockAcquire(&pDvcData->m_EventsSpinlock); pDtaEvents->m_pPrev = NULL; pDtaEvents->m_pNext = NULL; if (pDvcData->m_pEvents != NULL) { pDtaEvents->m_pNext = pDvcData->m_pEvents; pDtaEvents->m_pNext->m_pPrev = pDtaEvents; } pDvcData->m_pEvents = pDtaEvents; DtSpinLockRelease(&pDvcData->m_EventsSpinlock); return pDtaEvents; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaNonIpTxClearFlags -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // DtStatus DtaNonIpTxClearFlags(DtaNonIpPort* pNonIpPort, Int FlagsToClear) { DtSpinLockAcquire(&pNonIpPort->m_FlagsSpinLock); // Clear latched flags pNonIpPort->m_Flags &= ~FlagsToClear; pNonIpPort->m_FlagsLatched &= ~FlagsToClear; // Also clear flags in Transmit Status register, to avoid that flags in // m_Latched are set again in next periodic interrupt. if (!pNonIpPort->m_CapMatrix) { if ((FlagsToClear&DTA_TX_FIFO_UFL) == DTA_TX_FIFO_UFL) DtaRegTxStatClrUflInt(pNonIpPort->m_pTxRegs); if ((FlagsToClear&DTA_TX_SYNC_ERR) == DTA_TX_SYNC_ERR) DtaRegTxStatClrSyncInt(pNonIpPort->m_pTxRegs); } else { if ((FlagsToClear&DTA_TX_FIFO_UFL) == DTA_TX_FIFO_UFL) DtaRegHdStatClrTxUflErrInt(pNonIpPort->m_pTxRegs); if ((FlagsToClear&DTA_TX_SYNC_ERR) == DTA_TX_SYNC_ERR) DtaRegHdStatClrTxSyncErrInt(pNonIpPort->m_pTxRegs); } // Special case for DTA-102 if (pNonIpPort->m_pDvcData->m_DevInfo.m_TypeNumber == 102) { if ((FlagsToClear&DTA_TX_READBACK_ERR) == DTA_TX_READBACK_ERR) DtaRegTxStatClrShortInt(pNonIpPort->m_pTxRegs); } DtSpinLockRelease(&pNonIpPort->m_FlagsSpinLock); return DT_STATUS_OK; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsSet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // This function adds new events to the pending events. If the Events argument is 0, // this function does nothing. // DtStatus DtuEventsSet( DtuDeviceData* pDvcData, DtFileObject* pFile, UInt EventType, UInt Value1, UInt Value2) { DtStatus Result = DT_STATUS_OK; Int i; DtuEvents* pDtuEvents = NULL; Bool InUse; DtDbgOut(MAX, EVENTS, "Start"); DtDbgOut(AVG, EVENTS, "EventType: %i, Value1: %i, Value2: %i", EventType, Value1, Value2); if (pFile != NULL) { // Get corresponding events object pDtuEvents = DtuEventsGetEventsObject(pDvcData, pFile); if (pDtuEvents == NULL) Result = DT_STATUS_NOT_FOUND; else { Result = DtuEventsSetEvent(pDtuEvents, EventType, Value1, Value2); #ifdef WINBUILD if (pDtuEvents->m_NumPendingEvents != 0) { // Dequeue pending events DtuEventsDequeue(pDvcData, pFile); } #endif DtuEventsUnrefEventsObject(pDvcData, pDtuEvents); } } else { // Set event for all file handles for (i=0; i<MAX_NUM_FILE_HANDLES; i++) { pDtuEvents = &pDvcData->m_Events[i]; // Increment refcount InUse = FALSE; DtSpinLockAcquire(&pDtuEvents->m_Lock); if (pDtuEvents->m_RefCount > 0) { pDtuEvents->m_RefCount++; InUse = TRUE; } DtSpinLockRelease(&pDtuEvents->m_Lock); if (InUse) { // Set event Result = DtuEventsSetEvent(pDtuEvents, EventType, Value1, Value2); #ifdef WINBUILD if (pDtuEvents->m_NumPendingEvents != 0) { // Dequeue pending events pFile = &pDtuEvents->m_File; DtuEventsDequeue(pDvcData, pFile); } #endif // Decrement refcount DtuEventsUnrefEventsObject(pDvcData, pDtuEvents); } } } DtDbgOut(MAX, EVENTS, "Exit"); return Result; }
//-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtuEventsGet -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.- // // Return a pending event. This functions blocks if no events are pending. // DtStatus DtuEventsGet( DtuDeviceData* pDvcData, DtFileObject* pFile, UInt* pEventType, UInt* pValue1, UInt* pValue2, Bool Wait) { DtStatus Result = DT_STATUS_OK; DtuEvents* pDtuEvents; if (pFile==NULL || pEventType==NULL || pValue1==NULL || pValue2==NULL) return DT_STATUS_INVALID_PARAMETER; // Get corresponding events object pDtuEvents = DtuEventsGetEventsObject(pDvcData, pFile); if (pDtuEvents == NULL) Result = DT_STATUS_NOT_FOUND; if (DT_SUCCESS(Result)) { DtEventReset(&pDtuEvents->m_PendingEvent); if (Wait && pDtuEvents->m_NumPendingEvents==0 && !pDtuEvents->m_CancelInProgress) { DtDbgOut(MAX, EVENTS, "Waiting for event"); // Wait for event to be triggered DtEventWait(&pDtuEvents->m_PendingEvent, -1); } // The next request will be rejected by the IoCtl function, so we can reset // the Cancel state here. if (pDtuEvents->m_CancelInProgress) Result = DT_STATUS_CANCELLED; pDtuEvents->m_CancelInProgress = FALSE; DtSpinLockAcquire(&pDtuEvents->m_Lock); // Return pending events if (pDtuEvents->m_NumPendingEvents != 0) { *pEventType = pDtuEvents->m_PendingEvents[0].m_EventType; *pValue1 = pDtuEvents->m_PendingEvents[0].m_EventValue1; *pValue2 = pDtuEvents->m_PendingEvents[0].m_EventValue2; DtDbgOut(MAX, EVENTS, "Event #%d. Type: %d, Value1: %d, Value2: %d", pDtuEvents->m_NumPendingEvents, *pEventType, *pValue1, *pValue2); pDtuEvents->m_NumPendingEvents--; if (pDtuEvents->m_NumPendingEvents != 0) { // Remove the old event DtMemMove(&pDtuEvents->m_PendingEvents[0], &pDtuEvents->m_PendingEvents[1], sizeof(DtuEvent) * pDtuEvents->m_NumPendingEvents); } } else { *pEventType = 0; *pValue1 = 0; *pValue2 = 0; if (Result == DT_STATUS_OK) Result = DT_STATUS_REQUEUE; // No pending events DtDbgOut(MAX, EVENTS, "Event #%d. No event", pDtuEvents->m_NumPendingEvents); } DtSpinLockRelease(&pDtuEvents->m_Lock); // Decrement refcount DtuEventsUnrefEventsObject(pDvcData, pDtuEvents); } return Result; }
//.-.-.-.-.-.-.-.-.-.-.-.-.-.- DtaNonIpTxProcessFlagsFromUser -.-.-.-.-.-.-.-.-.-.-.-.-.-. // void DtaNonIpTxProcessFlagsFromUser(DtaNonIpPort* pNonIpPort) { DtSpinLockAcquire(&pNonIpPort->m_FlagsSpinLock); DtaNonIpTxProcessFlags(pNonIpPort); DtSpinLockRelease(&pNonIpPort->m_FlagsSpinLock); }