//********************************************************************** //********************************************************************** // // File Name: SUPPORT.C // // Program Name: NetFlex NDIS 3.0 Miniport Driver // // Companion Files: None // // Function: This module contains the NetFlex Miniport Driver // interface routines called by the Wrapper and the // configuration manager. // // (c) Compaq Computer Corporation, 1992,1993,1994 // // This file is licensed by Compaq Computer Corporation to Microsoft // Corporation pursuant to the letter of August 20, 1992 from // Gary Stimac to Mark Baber. // // History: // // 04/15/94 Robert Van Cleve - Converted from NDIS Mac Driver // //********************************************************************** //********************************************************************** //------------------------------------- // Include all general companion files //------------------------------------- #if (DBG || DBGPRINT) #include #include #endif #include #include "tmsstrct.h" #include "macstrct.h" #include "adapter.h" #include "protos.h" #if (DBG || DBGPRINT) ULONG DebugLevel=1; #endif //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexInitializeAcb // // Description: This routine initializes the given ACB. This // routine allocates memory for certain fields // pointed to by the ACB. // // Input: acb - Pointer to acb to fill in. // parms - Settable mac driver parms. // // Output: Returns NDIS_STATUS_SUCCESS for a successful // completion. Otherwise, an error code is // returned. // // Calls: NdisAllocateMemory,NdisZeroMemory,NdisMoveMemory // NdisMAllocateSharedMemory,SWAPL,CTRL_ADDR // // Called By: NetFlexInitialize // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NDIS_STATUS NetFlexInitializeAcb(PACB acb) { USHORT i; PRCV CurrentReceiveEntry; PXMIT CurrentXmitEntry; PVOID start, next, current; ULONG next_phys, current_phys, temp; PETH_OBJS ethobjs; NDIS_STATUS Status; PBUFFER_DESCRIPTOR OurBuf; ULONG LowPart; PUCHAR CurrentReceiveBuffer; PUCHAR CurrentMergeBuffer; PNETFLEX_PARMS parms = acb->acb_parms; ULONG Alignment, FrameSizeCacheAligned; DebugPrint(1,("NF(%d): NetFlexInitializeAcb entered.\n",acb->anum)); // // Initialize pointers and counters // acb->InterruptsDisabled = FALSE; // interrupts are enabled after a reset. acb->ResetState = 0; // // Set up rest of general oid variables. // acb->acb_smallbufsz = parms->utd_smallbufsz; acb->acb_maxmaps = parms->utd_maxtrans * MAX_BUFS_PER_XMIT; acb->acb_gen_objs.max_frame_size = parms->utd_maxframesz; acb->acb_lastringstate = NdisRingStateClosed; acb->acb_curmap = 0; // // Get the max frame size, cache align it and a save it for later. // Alignment = NdisGetCacheFillSize(); if ( Alignment < sizeof(ULONG) ) { Alignment = sizeof(ULONG); } FrameSizeCacheAligned = (parms->utd_maxframesz + Alignment - 1) & ~(Alignment - 1); // // Allocate the map registers // if (NdisMAllocateMapRegisters( acb->acb_handle, 0, TRUE, acb->acb_maxmaps, acb->acb_gen_objs.max_frame_size ) != NDIS_STATUS_SUCCESS) { return(NDIS_STATUS_RESOURCES); } // // Get the OID structures set up. The list of oids is determined // by the network type of the adapter. Also set up any network type // specific information. // if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3) { // ETHERNET // // Load up the oid pointers and lengths // acb->acb_gbl_oid_list = (PNDIS_OID)NetFlexGlobalOIDs_Eth; acb->acb_gbl_oid_list_size = NetFlexGlobalOIDs_Eth_size; acb->acb_spec_oid_list = (PNDIS_OID)NetFlexNetworkOIDs_Eth; acb->acb_spec_oid_list_size = NetFlexNetworkOIDs_Eth_size; // // Allocate and Zero out the Memory for Ethernet specific objects // NdisAllocateMemory( (PVOID *)&(acb->acb_spec_objs), (UINT) (sizeof (ETH_OBJS)), (UINT) 0, NetFlexHighestAddress); if (acb->acb_spec_objs == NULL) { return(NDIS_STATUS_RESOURCES); } NdisZeroMemory( acb->acb_spec_objs, sizeof (ETH_OBJS) ); // // Allocate and Zero out Memory for the Multicast table. // ethobjs = (PETH_OBJS)(acb->acb_spec_objs); ethobjs->MaxMulticast = parms->utd_maxmulticast; NdisAllocateMemory( (PVOID *)ðobjs->MulticastEntries, (UINT) (ethobjs->MaxMulticast * NET_ADDR_SIZE), (UINT) 0, NetFlexHighestAddress); if (ethobjs->MulticastEntries == NULL) { return(NDIS_STATUS_RESOURCES); } NdisZeroMemory(ethobjs->MulticastEntries, ethobjs->MaxMulticast * NET_ADDR_SIZE); ethobjs->NumberOfEntries = 0; // // Allocate Memory for sending multicast requests to the adapter. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)(sizeof(MULTI_BLOCK) * 2), FALSE, (PVOID *)(&(acb->acb_multiblk_virtptr)), &acb->acb_multiblk_physptr); if (acb->acb_multiblk_virtptr == NULL) { return(NDIS_STATUS_RESOURCES); } } else { // TOKEN RING // // Load up the oid pointers and lengths // acb->acb_gbl_oid_list = (PNDIS_OID)NetFlexGlobalOIDs_Tr; acb->acb_gbl_oid_list_size = NetFlexGlobalOIDs_Tr_size; acb->acb_spec_oid_list = (PNDIS_OID)NetFlexNetworkOIDs_Tr; acb->acb_spec_oid_list_size = NetFlexNetworkOIDs_Tr_size; // // Allocate and Zero out Memory for Token Ring specific objects // NdisAllocateMemory( (PVOID *)&(acb->acb_spec_objs), (UINT) (sizeof (TR_OBJS)), (UINT) 0, NetFlexHighestAddress); if (acb->acb_spec_objs == NULL) { return(NDIS_STATUS_RESOURCES); } NdisZeroMemory( acb->acb_spec_objs, sizeof (TR_OBJS) ); } // // Allocate the SCB for this adapter. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)SIZE_SCB, FALSE, (PVOID *)(&(acb->acb_scb_virtptr)), &acb->acb_scb_physptr); if (acb->acb_scb_virtptr == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating SCB failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } // // Allocate the SSB for this adapter. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)SIZE_SSB, FALSE, (PVOID *)(&(acb->acb_ssb_virtptr)), &acb->acb_ssb_physptr); if (acb->acb_ssb_virtptr == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating SSB failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } acb->acb_maxinternalbufs = parms->utd_maxinternalbufs; acb->acb_numsmallbufs = parms->utd_numsmallbufs; // // Allocate Flush Buffer Pool for our InteralBuffers and the ReceiveBuffers // NdisAllocateBufferPool( &Status, (PVOID*)&acb->FlushBufferPoolHandle, acb->acb_gen_objs.max_frame_size * ( parms->utd_maxinternalbufs + acb->acb_maxrcvs + acb->acb_maxinternalbufs)); if (Status != NDIS_STATUS_SUCCESS) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating flush buffer pool failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } // // Now allocate our internal buffers, and their flush buffers... // NdisAllocateMemory( (PVOID *) &acb->OurBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs, (UINT) 0, NetFlexHighestAddress); // // Zero the memory of all the descriptors so that we can // know which buffers weren't allocated incase we can't allocate // them all. // NdisZeroMemory( acb->OurBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs ); // // Allocate each of the buffers and fill in the // buffer descriptor. // OurBuf = acb->OurBuffersVirtPtr; NdisMAllocateSharedMemory( acb->acb_handle, FrameSizeCacheAligned * acb->acb_maxinternalbufs, TRUE, &acb->MergeBufferPoolVirt, &acb->MergeBufferPoolPhys); if ( acb->MergeBufferPoolVirt != NULL ) { acb->MergeBuffersAreContiguous = TRUE; CurrentMergeBuffer = acb->MergeBufferPoolVirt; LowPart = NdisGetPhysicalAddressLow(acb->MergeBufferPoolPhys); // // If the high part is non-zero then this adapter is hosed anyway since // its a 32-bit busmaster device. // ASSERT( NdisGetPhysicalAddressHigh(acb->MergeBufferPoolPhys) == 0 ); } else { acb->MergeBuffersAreContiguous = FALSE; acb->MergeBufferPoolVirt = NULL; CurrentMergeBuffer = NULL; } for (i = 0; i < acb->acb_maxinternalbufs; i++ ) { // // Allocate a buffer // if ( acb->MergeBuffersAreContiguous ) { OurBuf->VirtualBuffer = CurrentMergeBuffer; NdisSetPhysicalAddressLow(OurBuf->PhysicalBuffer, LowPart); NdisSetPhysicalAddressHigh(OurBuf->PhysicalBuffer, 0); CurrentMergeBuffer += FrameSizeCacheAligned; LowPart += FrameSizeCacheAligned; } else { NdisMAllocateSharedMemory( acb->acb_handle, parms->utd_maxframesz, TRUE, &OurBuf->VirtualBuffer, &OurBuf->PhysicalBuffer); if ( OurBuf->VirtualBuffer == NULL ) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual merge buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } } // // Build flush buffers // NdisAllocateBuffer( &Status, &OurBuf->FlushBuffer, acb->FlushBufferPoolHandle, OurBuf->VirtualBuffer, acb->acb_gen_objs.max_frame_size ); if (Status != NDIS_STATUS_SUCCESS) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } // // Insert this buffer into the queue // OurBuf->Next = (OurBuf + 1); OurBuf->BufferSize = acb->acb_gen_objs.max_frame_size; OurBuf = OurBuf->Next; } // // Make sure that the last buffer correctly terminates the free list. // (OurBuf - 1)->Next = NULL; acb->OurBuffersListHead = acb->OurBuffersVirtPtr; // // Now allocate our internal buffers, and their flush buffers... // NdisAllocateMemory( (PVOID *) &acb->SmallBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * parms->utd_numsmallbufs, (UINT) 0, NetFlexHighestAddress); // // Zero the memory of all the descriptors so that we can // know which buffers weren't allocated incase we can't allocate // them all. // NdisZeroMemory( acb->SmallBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * parms->utd_numsmallbufs); // // Allocate each of the buffers and fill in the // buffer descriptor. // OurBuf = acb->SmallBuffersVirtPtr; NdisMAllocateSharedMemory( acb->acb_handle, acb->acb_smallbufsz * parms->utd_numsmallbufs, TRUE, &acb->SmallBufferPoolVirt, &acb->SmallBufferPoolPhys); if ( acb->SmallBufferPoolVirt != NULL ) { acb->SmallBuffersAreContiguous = TRUE; CurrentMergeBuffer = acb->SmallBufferPoolVirt; LowPart = NdisGetPhysicalAddressLow(acb->SmallBufferPoolPhys); // // If the high part is non-zero then this adapter is hosed anyway since // its a 32-bit busmaster device. // ASSERT( NdisGetPhysicalAddressHigh(acb->SmallBufferPoolPhys) == 0 ); } else { acb->SmallBuffersAreContiguous = FALSE; acb->SmallBufferPoolVirt = NULL; CurrentMergeBuffer = NULL; } for (i = 0; i < parms->utd_numsmallbufs; i++ ) { // // Allocate a small buffer // if ( acb->SmallBuffersAreContiguous ) { OurBuf->VirtualBuffer = CurrentMergeBuffer; NdisSetPhysicalAddressLow(OurBuf->PhysicalBuffer, LowPart); NdisSetPhysicalAddressHigh(OurBuf->PhysicalBuffer, 0); CurrentMergeBuffer += acb->acb_smallbufsz; LowPart += acb->acb_smallbufsz; } else { NdisMAllocateSharedMemory( acb->acb_handle, acb->acb_smallbufsz, TRUE, &OurBuf->VirtualBuffer, &OurBuf->PhysicalBuffer ); if ( OurBuf->VirtualBuffer == NULL ) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual merge buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } } // // Build flush buffers // NdisAllocateBuffer( &Status, &OurBuf->FlushBuffer, acb->FlushBufferPoolHandle, OurBuf->VirtualBuffer, acb->acb_smallbufsz ); if (Status != NDIS_STATUS_SUCCESS) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } // // Insert this buffer into the queue // OurBuf->Next = (OurBuf + 1); OurBuf->BufferSize = acb->acb_smallbufsz; OurBuf = OurBuf->Next; } // // Make sure that the last buffer correctly terminates the free list. // (OurBuf - 1)->Next = NULL; acb->SmallBuffersListHead = acb->SmallBuffersVirtPtr; // // Now, Allocate the transmit lists // acb->acb_maxtrans = parms->utd_maxtrans * (USHORT)MAX_LISTS_PER_XMIT; NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)(SIZE_XMIT * acb->acb_maxtrans), FALSE, (PVOID *)&acb->acb_xmit_virtptr, &acb->acb_xmit_physptr); if (acb->acb_xmit_virtptr == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating transmit list failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } // // Initialize the transmit lists and link them together. // acb->acb_xmit_head = acb->acb_xmit_virtptr; current_phys = NdisGetPhysicalAddressLow(acb->acb_xmit_physptr); for (i = 0, CurrentXmitEntry = acb->acb_xmit_virtptr; i < acb->acb_maxtrans; i++, CurrentXmitEntry++ ) { NdisSetPhysicalAddressHigh(CurrentXmitEntry->XMIT_Phys, 0); NdisSetPhysicalAddressLow( CurrentXmitEntry->XMIT_Phys, current_phys); CurrentXmitEntry->XMIT_MyMoto = SWAPL(CTRL_ADDR((LONG)current_phys)); CurrentXmitEntry->XMIT_CSTAT = 0; #ifdef XMIT_INTS CurrentXmitEntry->XMIT_Number = i; #endif next_phys = current_phys + SIZE_XMIT; // // Make the forward pointer odd. // CurrentXmitEntry->XMIT_FwdPtr = SWAPL(CTRL_ADDR((LONG)next_phys)); CurrentXmitEntry->XMIT_Next = (CurrentXmitEntry + 1); CurrentXmitEntry->XMIT_OurBufferPtr = NULL; current_phys = next_phys; } // // Make sure the last entry is properly set to the begining... // (CurrentXmitEntry - 1)->XMIT_Next = acb->acb_xmit_virtptr; (CurrentXmitEntry - 1)->XMIT_FwdPtr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_xmit_physptr))); acb->acb_avail_xmit = parms->utd_maxtrans; // // Now, Allocate the Receive lists. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)(sizeof(RCV) * parms->utd_maxrcvs), FALSE, (PVOID *) &acb->acb_rcv_virtptr, &acb->acb_rcv_physptr); if (acb->acb_rcv_virtptr == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating receive list failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } // // Point the head to the first one... // acb->acb_rcv_head = acb->acb_rcv_virtptr; // // Clear the receive lists // NdisZeroMemory( acb->acb_rcv_virtptr, sizeof(RCV) * parms->utd_maxrcvs ); // // Initialize the receive lists and link them together. // acb->acb_maxrcvs = parms->utd_maxrcvs; current_phys = NdisGetPhysicalAddressLow(acb->acb_rcv_physptr); CurrentReceiveEntry = acb->acb_rcv_virtptr; // // Create the receive buffer pool. // NdisMAllocateSharedMemory( acb->acb_handle, FrameSizeCacheAligned * parms->utd_maxrcvs, TRUE, &acb->ReceiveBufferPoolVirt, &acb->ReceiveBufferPoolPhys ); if ( acb->ReceiveBufferPoolVirt != NULL ) { acb->RecvBuffersAreContiguous = TRUE; CurrentReceiveBuffer = acb->ReceiveBufferPoolVirt; LowPart = NdisGetPhysicalAddressLow(acb->ReceiveBufferPoolPhys); // // If the high part is non-zero then this adapter is hosed anyway since // its a 32-bit busmaster device. // ASSERT( NdisGetPhysicalAddressHigh(acb->ReceiveBufferPoolPhys) == 0 ); } else { acb->RecvBuffersAreContiguous = FALSE; acb->ReceiveBufferPoolVirt = NULL; CurrentReceiveBuffer = NULL; } for ( i = 0; i < parms->utd_maxrcvs; ++i, ++CurrentReceiveEntry ) { // // Allocate the actual receive frame buffers. // if ( acb->RecvBuffersAreContiguous ) { CurrentReceiveEntry->RCV_Buf = CurrentReceiveBuffer; NdisSetPhysicalAddressLow(CurrentReceiveEntry->RCV_BufPhys, LowPart); NdisSetPhysicalAddressHigh(CurrentReceiveEntry->RCV_BufPhys, 0); CurrentReceiveBuffer += FrameSizeCacheAligned; LowPart += FrameSizeCacheAligned; } else { NdisMAllocateSharedMemory( acb->acb_handle, parms->utd_maxframesz, TRUE, &CurrentReceiveEntry->RCV_Buf, &CurrentReceiveEntry->RCV_BufPhys ); if ( CurrentReceiveEntry->RCV_Buf == NULL ) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating individual receive buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } } // // Build flush buffers // NdisAllocateBuffer( &Status, &CurrentReceiveEntry->RCV_FlushBuffer, acb->FlushBufferPoolHandle, CurrentReceiveEntry->RCV_Buf, acb->acb_gen_objs.max_frame_size); if (Status != NDIS_STATUS_SUCCESS) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating FLUSH receive buffer failed.\n",acb->anum)); return NDIS_STATUS_RESOURCES; } // // Initialize receive buffers // NdisFlushBuffer(CurrentReceiveEntry->RCV_FlushBuffer, FALSE); CurrentReceiveEntry->RCV_Number = i; CurrentReceiveEntry->RCV_CSTAT = ((i % acb->RcvIntRatio) == 0) ? RCSTAT_GO_INT : RCSTAT_GO; CurrentReceiveEntry->RCV_Dsize = (SHORT) SWAPS((USHORT)(acb->acb_gen_objs.max_frame_size)); CurrentReceiveEntry->RCV_Dsize &= DATA_LAST; temp = NdisGetPhysicalAddressLow(CurrentReceiveEntry->RCV_BufPhys); temp = SWAPL(temp); CurrentReceiveEntry->RCV_DptrHi = (USHORT)temp; CurrentReceiveEntry->RCV_DptrLo = (USHORT)(temp >> 16); NdisSetPhysicalAddressHigh(CurrentReceiveEntry->RCV_Phys, 0); NdisSetPhysicalAddressLow( CurrentReceiveEntry->RCV_Phys, current_phys); next_phys = current_phys + SIZE_RCV; CurrentReceiveEntry->RCV_FwdPtr = SWAPL(CTRL_ADDR(next_phys)); CurrentReceiveEntry->RCV_MyMoto = SWAPL(CTRL_ADDR(current_phys)); CurrentReceiveEntry->RCV_Next = (CurrentReceiveEntry + 1); current_phys = next_phys; } // // Make sure the last entry is properly set to the begining... // (CurrentReceiveEntry - 1)->RCV_Next = acb->acb_rcv_virtptr; (CurrentReceiveEntry - 1)->RCV_FwdPtr = SWAPL(CTRL_ADDR(NdisGetPhysicalAddressLow(acb->acb_rcv_physptr))); // // Allocate and initialize the OPEN parameter block. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)SIZE_OPEN, FALSE, (PVOID *)(&(acb->acb_opnblk_virtptr)), &acb->acb_opnblk_physptr ); if (acb->acb_opnblk_virtptr == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating OPEN block failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } NdisMoveMemory(acb->acb_opnblk_virtptr, &(parms->utd_open), SIZE_OPEN); // // Convert the product ID pointer in the Open parameter block // into a big endian type address. // acb->acb_opnblk_virtptr->OPEN_ProdIdPtr = (CHAR *) (SWAPL((LONG) acb->acb_opnblk_virtptr->OPEN_ProdIdPtr)); acb->acb_openoptions = parms->utd_open.OPEN_Options; // // Initialize the intialization block. // NdisMoveMemory(&acb->acb_initblk, &init_mask, SIZE_INIT); // // Allocate Memory to hold the Read Statistics Log information. // NdisMAllocateSharedMemory( acb->acb_handle, (ULONG)(sizeof(RSL)), FALSE, (PVOID *)(&(acb->acb_logbuf_virtptr)), &acb->acb_logbuf_physptr ); if (acb->acb_logbuf_virtptr == NULL) { return(NDIS_STATUS_RESOURCES); } // // Allocate Memory for internal SCB requests. // NdisAllocateMemory( (PVOID *)&(start), (UINT) (SCBREQSIZE * parms->utd_maxinternalreqs), (UINT) NDIS_MEMORY_CONTIGUOUS, NetFlexHighestAddress); if (start == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating internal SCB request failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } // // Initialize the SCB requests and place them on the free queue. // acb->acb_maxreqs = parms->utd_maxinternalreqs; current = start; for (i = 0; i < parms->utd_maxinternalreqs; i++) { next = (PVOID)( ((PUCHAR)(current)) + SCBREQSIZE); ((PSCBREQ) current)->req_next = next; if (i < (USHORT)(parms->utd_maxinternalreqs-1)) { current = next; } } ((PSCBREQ)current)->req_next = (PSCBREQ) NULL; acb->acb_scbreq_ptr = (PSCBREQ)start; acb->acb_scbreq_free = (PSCBREQ)start; // // Allocate Memory for the internal MAC requests. // NdisAllocateMemory( (PVOID *)&(start), (UINT) (MACREQSIZE * parms->utd_maxinternalreqs), (UINT) NDIS_MEMORY_CONTIGUOUS, NetFlexHighestAddress); if (start == NULL) { DebugPrint(1,("NF(%d): NetFlexInitializeAcb: Allocating internal MAC request failed.\n",acb->anum)); return(NDIS_STATUS_RESOURCES); } // // Initialize the internal MAC requests and place them // on the free queue. // current = start; for (i = 0; i < parms->utd_maxinternalreqs; i++) { next = (PVOID)( ((PUCHAR)(current)) + MACREQSIZE); ((PMACREQ) current)->req_next = next; if (i < (USHORT)(parms->utd_maxinternalreqs-1)) { current = next; } } ((PMACREQ)current)->req_next = (PMACREQ) NULL; acb->acb_macreq_ptr = (PMACREQ)start; acb->acb_macreq_free = (PMACREQ)start; DebugPrint(1,("NF(%d): NetFlexInitializeAcb completed successfully!\n",acb->anum)); return(NDIS_STATUS_SUCCESS); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexDeallocateAcb // // Description: This routine deallocates the acb resources. // // Input: acb - Our Driver Context for this adapter or head. // // Output: None. // // Called By: NetFlexInitialize, // NetFlexDeregisterAdapter // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexDeallocateAcb( PACB acb ) { PETH_OBJS ethobjs; PRCV CurrentReceiveEntry; PNETFLEX_PARMS parms = acb->acb_parms; USHORT i; PBUFFER_DESCRIPTOR OurBuf; ULONG Alignment, FrameSizeCacheAligned; // // Get the max frame size, cache align it and a save it for later. // Alignment = NdisGetCacheFillSize(); if ( Alignment < sizeof(ULONG) ) { Alignment = sizeof(ULONG); } FrameSizeCacheAligned = (parms->utd_maxframesz + Alignment - 1) & ~(Alignment - 1); // // If we have allocated memory for the network specific information, // release this memory now. // if (acb->acb_spec_objs) { if (acb->acb_gen_objs.media_type_in_use == NdisMedium802_3) { // ETHERNET ethobjs = (PETH_OBJS)(acb->acb_spec_objs); // // If we have allocated the multicast table entries, free // the memory. // if (ethobjs->MulticastEntries) { NdisFreeMemory( (PVOID)(ethobjs->MulticastEntries), (UINT) (ethobjs->MaxMulticast * NET_ADDR_SIZE), (UINT) 0); } // // Deallocate Memory for Ethernet specific objects // NdisFreeMemory((PVOID)(acb->acb_spec_objs), (UINT) (sizeof (ETH_OBJS)), (UINT) 0); } else { // Token Ring // // Deallocate Memory for Token Ring specific objects // NdisFreeMemory( (PVOID)(acb->acb_spec_objs), (UINT) (sizeof (TR_OBJS)), (UINT) 0); } } // // If we have allocated memory for the multicast request to the // adapter, free the memory. // if (acb->acb_multiblk_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)(sizeof(MULTI_BLOCK) * 2), FALSE, (PVOID)(acb->acb_multiblk_virtptr), acb->acb_multiblk_physptr); } // // If we have allocated memory for the scb, free the memory. // if (acb->acb_scb_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)SIZE_SCB, FALSE, (PVOID)(acb->acb_scb_virtptr), acb->acb_scb_physptr); } // // If we have allocated memory for the ssb, free the memory. // if (acb->acb_ssb_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)SIZE_SSB, FALSE, (PVOID)(acb->acb_ssb_virtptr), acb->acb_ssb_physptr); } // // Free merge buffer pool. // if (acb->MergeBufferPoolVirt) { OurBuf = acb->OurBuffersVirtPtr; // // Free flush buffers // for (i = 0; i < acb->acb_maxinternalbufs; ++i, ++OurBuf) { if (OurBuf->FlushBuffer) { NdisFreeBuffer(OurBuf->FlushBuffer); if ( !acb->MergeBuffersAreContiguous ) { NdisMFreeSharedMemory( acb->acb_handle, parms->utd_maxframesz, TRUE, OurBuf->VirtualBuffer, OurBuf->PhysicalBuffer ); } } } // // Free the pool itself. // if ( acb->MergeBuffersAreContiguous ) { NdisMFreeSharedMemory( acb->acb_handle, FrameSizeCacheAligned * acb->acb_maxinternalbufs, TRUE, acb->MergeBufferPoolVirt, acb->MergeBufferPoolPhys ); } } // // Free our own transmit buffers. // if (acb->OurBuffersVirtPtr) { // // Free OurBuffers // NdisFreeMemory( acb->OurBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * acb->acb_maxinternalbufs, 0 ); } // // Free Small Merge buffer pool. // if (acb->SmallBufferPoolVirt) { OurBuf = acb->SmallBuffersVirtPtr; // // Free flush buffers // for (i = 0; i < acb->acb_numsmallbufs; ++i, ++OurBuf) { if (OurBuf->FlushBuffer) { NdisFreeBuffer(OurBuf->FlushBuffer); if ( !acb->SmallBuffersAreContiguous ) { NdisMFreeSharedMemory( acb->acb_handle, acb->acb_smallbufsz, TRUE, OurBuf->VirtualBuffer, OurBuf->PhysicalBuffer); } } } // // Free the pool itself. // if ( acb->SmallBuffersAreContiguous ) { NdisMFreeSharedMemory( acb->acb_handle, acb->acb_smallbufsz * acb->acb_numsmallbufs, TRUE, acb->SmallBufferPoolVirt, acb->SmallBufferPoolPhys); } } // // Free our Small transmit buffers. // if (acb->SmallBuffersVirtPtr) { // // Free Small Buffers // NdisFreeMemory( acb->SmallBuffersVirtPtr, sizeof(BUFFER_DESCRIPTOR) * acb->acb_numsmallbufs, 0 ); } // // If we have allocated memory for the transmit lists, free it. // if (acb->acb_xmit_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)(SIZE_XMIT * acb->acb_maxtrans), FALSE, (PVOID)(acb->acb_xmit_virtptr), acb->acb_xmit_physptr ); } // // If we have allocated memory for the receive lists, free it. // if ( acb->acb_rcv_virtptr ) { // // If we allocated the receive buffer pool, free it. // CurrentReceiveEntry = acb->acb_rcv_virtptr; for (i = 0; i < parms->utd_maxrcvs; ++i, ++CurrentReceiveEntry) { // // Free flush buffers // if ( CurrentReceiveEntry->RCV_FlushBuffer ) { NdisFreeBuffer(CurrentReceiveEntry->RCV_FlushBuffer); } // // Free individual buffer, if allocated. // if ((!acb->RecvBuffersAreContiguous) && (CurrentReceiveEntry->RCV_Buf)) { NdisMFreeSharedMemory( acb->acb_handle, parms->utd_maxframesz, TRUE, CurrentReceiveEntry->RCV_Buf, CurrentReceiveEntry->RCV_BufPhys ); } } // // Free the pool itself, if it was allocated contiguously. // if ( acb->RecvBuffersAreContiguous && acb->ReceiveBufferPoolVirt) { NdisMFreeSharedMemory( acb->acb_handle, FrameSizeCacheAligned * parms->utd_maxrcvs, TRUE, acb->ReceiveBufferPoolVirt, acb->ReceiveBufferPoolPhys ); } // // Now Free the RCV Lists // NdisMFreeSharedMemory( acb->acb_handle, (ULONG)(SIZE_RCV * parms->utd_maxrcvs), FALSE, (PVOID)acb->acb_rcv_virtptr, acb->acb_rcv_physptr); } // // Free the Flush Pool // if (acb->FlushBufferPoolHandle) { // Free the buffer pool // NdisFreeBufferPool(acb->FlushBufferPoolHandle); } // // If we have allocated memory for the open block, free it. // if (acb->acb_opnblk_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)SIZE_OPEN, FALSE, (PVOID)(acb->acb_opnblk_virtptr), acb->acb_opnblk_physptr); } // // If we have allocated memory for the Read Statistics Log, free it. // if (acb->acb_logbuf_virtptr) { NdisMFreeSharedMemory( acb->acb_handle, (ULONG)(sizeof(RSL)), FALSE, (PVOID)(acb->acb_logbuf_virtptr), acb->acb_logbuf_physptr); } // // If we have allocated memory for the internal SCB requests, // free it. // if (acb->acb_scbreq_ptr) { NdisFreeMemory( (PVOID)acb->acb_scbreq_ptr, (UINT) (SCBREQSIZE * acb->acb_maxreqs), (UINT) NDIS_MEMORY_CONTIGUOUS); } // // If we have allocated memory for the internal MAC requests, // free it. // if (acb->acb_macreq_ptr) { NdisFreeMemory( (PVOID)acb->acb_macreq_ptr, (UINT) (MACREQSIZE * acb->acb_maxreqs), (UINT) NDIS_MEMORY_CONTIGUOUS); } // // Free map registers // NdisMFreeMapRegisters(acb->acb_handle); // // Deregister IO mappings // if (acb->acb_dualport) { BOOLEAN OtherHeadStillActive = FALSE; PACB tmp_acb = macgbls.mac_adapters; while (tmp_acb) { if ((tmp_acb->acb_baseaddr == acb->acb_baseaddr) && (tmp_acb->acb_portnumber != acb->acb_portnumber)) { OtherHeadStillActive = TRUE; break; } else { tmp_acb = tmp_acb->acb_next; } } if (!OtherHeadStillActive) { // Remove ports for both heads // // free ports z000 - -z02f // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr, NUM_DUALHEAD_CFG_PORTS, (PVOID) acb->MasterBasePorts ); // free ports zc80 - zc87 // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr + CFG_PORT_OFFSET, NUM_CFG_PORTS, (PVOID)acb->ConfigPorts ); // free ports zc63 - zc67 // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr + EXTCFG_PORT_OFFSET, NUM_EXTCFG_PORTS, (PVOID)acb->ExtConfigPorts ); } } else { // free ports z000 - z01f // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr, NUM_BASE_PORTS, (PVOID) acb->BasePorts ); // free ports zc80 - zc87 // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr + CFG_PORT_OFFSET, NUM_CFG_PORTS, (PVOID)acb->ConfigPorts ); // free ports zc63 - zc67 // NdisMDeregisterIoPortRange( acb->acb_handle, acb->acb_baseaddr + EXTCFG_PORT_OFFSET, NUM_EXTCFG_PORTS, (PVOID)acb->ExtConfigPorts ); } // // Free the Memory for the adapter's acb. // if (acb->acb_parms != NULL) { NdisFreeMemory( (PVOID) acb->acb_parms, (UINT) sizeof(PNETFLEX_PARMS), (UINT) 0); } if (acb != NULL) { NdisFreeMemory( (PVOID)acb, (UINT) (sizeof (ACB)),(UINT) 0); } // // Indicate New Number of Adapters // macgbls.mac_numadpts--; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexSendNextSCB // // Description: // This routine either sends a TMS_TRANSMIT SCB // command to the adapter or sends a command on // the SCBReq active queue. // // Input: // acb - Our Driver Context for this adapter or head. // // Output: // None // // Called By: // NetFlexSCBClear, // NetFlexQueueSCB, // NetFlexTransmitStatus // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexSendNextSCB( PACB acb ) { USHORT sifint_reg; PSCBREQ req; PMACREQ macreq; PMULTI_BLOCK tempmulti; // // If there is a Transmit command waiting, issue it. Otherwise, // issue the first SCBReq on the SCBReq active queue. // if (acb->acb_xmit_whead) { // Load up the real SCB with a Transmit command // DebugPrint(2,("!S!")); acb->acb_scb_virtptr->SCB_Cmd = TMS_TRANSMIT; acb->acb_scb_virtptr->SCB_Ptr = acb->acb_xmit_whead->XMIT_MyMoto; // // If the transmit lists on the waiting queue are ready to // transmit, put them on the active queue. // if ((acb->acb_xmit_whead->XMIT_CSTAT & XCSTAT_GO) != 0) { acb->acb_xmit_ahead = acb->acb_xmit_whead; acb->acb_xmit_atail = acb->acb_xmit_wtail; } acb->acb_xmit_whead = 0; acb->acb_xmit_wtail = 0; } // // If there is a Receive command waiting, issue it. // else if (acb->acb_rcv_whead) { // Load up the real SCB with a receive command // acb->acb_scb_virtptr->SCB_Cmd = TMS_RECEIVE; acb->acb_scb_virtptr->SCB_Ptr = acb->acb_rcv_whead->RCV_MyMoto; acb->acb_rcv_head = acb->acb_rcv_whead; acb->acb_rcv_whead = 0; } // // Otherwise, if there is a SCB request waiting, issue it. // else if (acb->acb_scbreq_next) { // First, let's skip over any dummy SCB commands // req = acb->acb_scbreq_next; // // Fill in the real SCB with the first SCBReq on the SCBReq active // queue. // acb->acb_scbreq_next = acb->acb_scbreq_next->req_next; acb->acb_scb_virtptr->SCB_Cmd = req->req_scb.SCB_Cmd; // // If this is a Multicast request, we have to fill in a Multicast // buffer. // if (req->req_scb.SCB_Cmd == TMS_MULTICAST) { acb->acb_scb_virtptr->SCB_Ptr = SWAPL(CTRL_ADDR((ULONG)(NdisGetPhysicalAddressLow(acb->acb_multiblk_physptr) + (acb->acb_multi_index * sizeof(MULTI_BLOCK)))) ); tempmulti = (PMULTI_BLOCK)((ULONG)(acb->acb_multiblk_virtptr) + (acb->acb_multi_index * sizeof(MULTI_BLOCK))); acb->acb_multi_index = acb->acb_multi_index ^ (SHORT)1; tempmulti->MB_Option = req->req_multi.MB_Option; tempmulti->MB_Addr_Hi = req->req_multi.MB_Addr_Hi; tempmulti->MB_Addr_Med = req->req_multi.MB_Addr_Med; tempmulti->MB_Addr_Lo = req->req_multi.MB_Addr_Lo; } else { acb->acb_scb_virtptr->SCB_Ptr = req->req_scb.SCB_Ptr; } } else { // Nothing to do // return; } sifint_reg = SIFINT_CMD; // // If there are other requests to send and we are not waiting for // an SCB clear interrupt, tell the adapter we want an SCB clear int. // if ((!acb->acb_scbclearout) && ((acb->acb_scbreq_next) || (acb->acb_rcv_whead)) ) { sifint_reg |= SIFINT_SCBREQST; acb->acb_scbclearout = TRUE; } // // Send the SCB to the adapter. // NdisRawWritePortUshort(acb->SifIntPort, (USHORT) sifint_reg); } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexQueueSCB // // Description: // This routine places the given SCBReq onto the // active SCBreq queue. // // Input: // acb - Our Driver Context for this adapter or head. // scbreq - Ptr to the SCBReq to execute // // Output: // None // // Called By: // NetFlexQueryInformation // NetFlexSetInformation, // NetFlexDeleteMulticast, // NetFlexAddMulticast // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexQueueSCB( PACB acb, PSCBREQ scbreq ) { // // Place the scbreq on the SCBReq active queue. // NetFlexEnqueue_TwoPtrQ_Tail( (PVOID *)&(acb->acb_scbreq_head), (PVOID *)&(acb->acb_scbreq_tail), (PVOID)scbreq ); // // If there are no requests waiting for the SCB to clear, // point the request waiting queue to this SCBReq. // if (!acb->acb_scbreq_next) acb->acb_scbreq_next = scbreq; // // If the SCB is clear, send a SCB command off now. // Otherwise, if we are not currently waiting for an SCB clear // interrupt, signal the adapter to send us a SCB clear interrupt // when it is done with the SCB. // if (acb->acb_scb_virtptr->SCB_Cmd == 0) { NetFlexSendNextSCB(acb); } else if (!acb->acb_scbclearout) { acb->acb_scbclearout = TRUE; NdisRawWritePortUshort(acb->SifIntPort, (USHORT)SIFINT_SCBREQST); } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexGetBIA // // Description: // This routine gets the Burned In Address of the adapter. // // Input: // acb - Acb pointer // // Output: // NDIS_STATUS_SUCCESS if successful // // Called By: // NetFlexBoardInitandReg // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexGetBIA( PACB acb ) { USHORT value; SHORT i; NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) 0x0a00); NdisRawReadPortUshort( acb->SifDataPort, (PUSHORT) &value); NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) value); for (i = 0; i < 3; i++) { NdisRawReadPortUshort( acb->SifDIncPort, (PUSHORT) &value); // // Copy the value into the permanent and current station addresses // acb->acb_gen_objs.perm_staddr[i*2] = (UCHAR)(SWAPS(value)); acb->acb_gen_objs.perm_staddr[(i*2)+1] = (UCHAR)(value); } // // Figure out whether the current station address will be the bia or // an address set up in the configuration file. // if ( (acb->acb_opnblk_virtptr->OPEN_NodeAddr[0] == 0) && (acb->acb_opnblk_virtptr->OPEN_NodeAddr[1] == 0) && (acb->acb_opnblk_virtptr->OPEN_NodeAddr[2] == 0) && (acb->acb_opnblk_virtptr->OPEN_NodeAddr[3] == 0) && (acb->acb_opnblk_virtptr->OPEN_NodeAddr[4] == 0) && (acb->acb_opnblk_virtptr->OPEN_NodeAddr[5] == 0) ) { NdisMoveMemory(acb->acb_gen_objs.current_staddr, acb->acb_gen_objs.perm_staddr, NET_ADDR_SIZE); } else { NdisMoveMemory(acb->acb_gen_objs.current_staddr, acb->acb_opnblk_virtptr->OPEN_NodeAddr, NET_ADDR_SIZE); } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexGetUpstreamAddrPtr // // Description: This routine saves the address of where to // get the upstream address after opening. // // Input: // acb - Our Driver Context for this adapter or head. // // Output: // NDIS_STATUS_SUCCESS if successful // // Called By: // NetFlexAdapterReset // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexGetUpstreamAddrPtr( PACB acb ) { USHORT value; NdisRawWritePortUshort( acb->SifAddrPort, (USHORT) 0x0a06); // RVC: what is this value for? NdisRawReadPortUshort( acb->SifDataPort, (PUSHORT) &value); // // Save the address of where to get the UNA for later requests // acb->acb_upstreamaddrptr = value; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexAsciiToHex // // Description: // This routine takes an ascii string an converts // it into hex digits storing them in an array provided. // // Input: // src - source string. // dst - destiniation string // dst_length - length of dst // // Output: // NDIS_STATUS_SUCCESS if the string was converted successfully. // // Called By: // NetFlexReadConfigurationParameters // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NDIS_STATUS NetFlexAsciiToHex( PNDIS_STRING src, PUCHAR dst, USHORT dst_length ) { ULONG i; UCHAR num; // // If the string is too short, return an error. // if (src->Length < (USHORT)(dst_length*2)) return(NDIS_STATUS_FAILURE); // // Begin to convert. // for (i = 0; i < dst_length; i++) { // // Get first digit of the byte // num = (UCHAR)(src->Buffer[i*2]); if ( (num >= '0') && (num <= '9') ) *dst = (UCHAR)(num - '0') * 0x10; else if ( (num >= 'a') && (num <= 'f') ) *dst = (UCHAR)(num - 'a' + 10) * 0x10; else if ( (num >= 'A') && (num <= 'F') ) *dst = (UCHAR)(num - 'A' + 10) * 0x10; else return(NDIS_STATUS_FAILURE); // // Get second digit of the byte // num = (UCHAR)(src->Buffer[(i*2)+1]); if ( (num >= '0') && (num <= '9') ) *dst += (UCHAR)(num - '0'); else if ( (num >= 'a') && (num <= 'f') ) *dst += (UCHAR)(num - 'a' + 10); else if ( (num >= 'A') && (num <= 'F') ) *dst += (UCHAR)(num - 'A' + 10); else return(NDIS_STATUS_FAILURE); dst++; } return NDIS_STATUS_SUCCESS; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexFindEntry // // Description: // This routine finds the given entry in a queue given to it. // // Input: // head - Ptr to the head of the queue. // entry - Ptr to the entry to find. // // Output: // back - Ptr to the address of the entry in front of the // entry given. // Returns TRUE if found and FALSE if not. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ BOOLEAN NetFlexFindEntry( PVOID head, PVOID *back, PVOID entry ) { PVOID current; current = *back = head; while (current) { if (current == entry) return(TRUE); *back = current; current = (PVOID)( ( (PNETFLEX_ENTRY)(current) )->next ); } return FALSE; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexDequeue_OnePtrQ // // Description: This routine finds the given entry and removes // it from the queueu given. // // Input: head - Ptr to the head of the queue. // entry - Ptr to the entry to remove. // // Output: None. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexDequeue_OnePtrQ( PVOID *head, PVOID entry ) { PNETFLEX_ENTRY back; if (NetFlexFindEntry(*head, (PVOID *) &back, entry)) { if (entry == *head) *head = (PVOID)( ( (PNETFLEX_ENTRY)(entry) )->next ); else back->next = ( (PNETFLEX_ENTRY)(entry) )->next; } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexEnqueue_OnePtrQ_Head // // Description: // This routine places the entry given on the front of the // queue given. // // Input: // head - Ptr to the ptr of the head of the queue. // entry - Pointer to the entry to add // // Output: None // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexEnqueue_OnePtrQ_Head( PVOID *head, PVOID entry ) { ((PNETFLEX_ENTRY)(entry))->next = *head; *head = entry; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexDequeue_OnePtrQ_Head // // Description: // This routine dequeues a the first entry of the given queue // // Input: // head - Ptr to the ptr of the head of the queue. // // Output: // entry - Ptr to the ptr of the dequeued entry. // // Returns NDIS_STATUS_SUCCESS if an entry is freed. // Otherwise, NDIS_STATUS_RESOURCES. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NDIS_STATUS NetFlexDequeue_OnePtrQ_Head( PVOID *head, PVOID *entry ) { // // Is there a free entry? If not, return an error. // if (!(*head)) { *entry = NULL; return NDIS_STATUS_RESOURCES; } // // Dequeue the free entry from the queue. // *entry = *head; *head = ( (PNETFLEX_ENTRY)(*head))->next; ((PNETFLEX_ENTRY)(*entry))->next = NULL; return NDIS_STATUS_SUCCESS; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexEnqueue_TwoPtrQ_Tail // // Description: // This routine places an entry on the tail of // a queue with a head and tail pointer. // // Input: // head - Ptr to address of the head of the queue. // tail - Ptr to the address of the tail of the queue. // entry - Ptr to the entry to enqueue // // Output: // Status. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NDIS_STATUS NetFlexEnqueue_TwoPtrQ_Tail( PVOID *head, PVOID *tail, PVOID entry) { // // Place the entry on tail of the queue. // ((PNETFLEX_ENTRY)(entry))->next = NULL; if (*tail) ((PNETFLEX_ENTRY)(*tail))->next = entry; else *head = entry; *tail = entry; return NDIS_STATUS_SUCCESS; } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexDequeue_TwoPtrQ // // Description: // This routine finds the given entry and removes it from // the queue. Queue has a head and tail pointer. // // Input: // head - Ptr to address of the head of the queue. // tail - Ptr to the address of the tail of the queue. // entry - Ptr to the entry to enqueue // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID NetFlexDequeue_TwoPtrQ( PVOID *head, PVOID *tail, PVOID entry ) { PVOID back; if (NetFlexFindEntry(*head, &back, entry)) { if (entry == *head) { if ( (*head = ((PNETFLEX_ENTRY)entry)->next) == NULL) *tail = NULL; } else { ((PNETFLEX_ENTRY)back)->next = ((PNETFLEX_ENTRY)entry)->next; if (*tail == entry) *tail = back; } } } //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: NetFlexDequeue_TwoPtrQ_Head // // Description: // This routine dequeues a the first entry of the given queue // // Input: // head - Ptr to the ptr of the head of the queue. // tail - Ptr to the address of the tail of the queue. // // Output: // entry - Ptr to the ptr of the dequeued entry. // // Status - NDIS_STATUS_SUCCESS if an entry is freed. // Otherwise, NDIS_STATUS_RESOURCES. // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ NDIS_STATUS NetFlexDequeue_TwoPtrQ_Head( PVOID *head, PVOID *tail, PVOID *entry ) { // // Is there a free entry? If not, return an error. // if (!(*head)) { *entry = NULL; return(NDIS_STATUS_RESOURCES); } // // Dequeue the free entry from the queue. // *entry = *head; *head = ((PNETFLEX_ENTRY)(*head))->next; if (*head == NULL) *tail = NULL; ((PNETFLEX_ENTRY)(*entry))->next = NULL; return NDIS_STATUS_SUCCESS; } #if (DBG || DBGPRINT) //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // Routine Name: _DebugPrint // // Description: // Level sensitive debug print. It is called through // a the DebugPrint macro which compares the current // DebugLevel to that specified. If the level indicated // is less than or equal, the message is displayed. // // Input: // Variable PrintF style Message to display // // Output: // Displays Message on Debug Screen // //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ VOID _DebugPrint(PCHAR DebugMessage, ... ) { char buffer[256]; va_list ap; va_start(ap, DebugMessage); vsprintf(buffer, DebugMessage, ap); DbgPrint(buffer); va_end(ap); } // end _DebugPrint() #endif /* DBG */