diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/pc586e/pc586snd.c | 1300 |
1 files changed, 1300 insertions, 0 deletions
diff --git a/private/ntos/ndis/pc586e/pc586snd.c b/private/ntos/ndis/pc586e/pc586snd.c new file mode 100644 index 000000000..f8fb2f002 --- /dev/null +++ b/private/ntos/ndis/pc586e/pc586snd.c @@ -0,0 +1,1300 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + pc586snd.c + +Abstract: + + This file contains the code for putting a packet through the + staged allocation for transmission. + + This is a process of + + 1) Calculating the what would need to be done to the + packet so that the packet can be transmitted on the hardware. + + 2) Potentially allocating adapter buffers and copying user data + to those buffers so that the packet data is transmitted under + the hardware constraints. + + 3) Allocating enough hardware ring entries so that the packet + can be transmitted. + + 4) Relinquish thos ring entries to the hardware. + + NOTE: ZZZ There is a potential priority inversion problem when + allocating the packet. For nt it looks like we need to raise + the irql to dpc when we start the allocation. + +Author: + + Anthony V. Ercolano (Tonye) 12-Sept-1990 + +Environment: + + Kernel Mode - Or whatever is the equivalent on OS/2 and DOS. + +Revision History: + + +--*/ + +#include <ntos.h> +#include <ndis.h> +#include <filter.h> +#include <pc586hrd.h> +#include <pc586sft.h> + + + + +// +// ZZZ This macro implementation is peculiar to NT. It will poke the +// pc586 hardware into noticing that there is a packet available +// for transmit. +// +// Note that there is the assumption that the register address +// port (RAP) is already set to zero. +// +#define PROD_TRANSMIT(A) \ + PC586_WRITE_RDP( \ + A->RDP, \ + PC586_CSR0_TRANSMIT_DEMAND | PC586_CSR0_INTERRUPT_ENABLE \ + ); + + +static +BOOLEAN +PacketShouldBeSent( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ); + +static +VOID +SetupAllocate( + IN PPC586_ADAPTER Adapter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE RequestHandle, + IN PNDIS_PACKET Packet + ); + +static +VOID +StagedAllocation( + IN PPC586_ADAPTER Adapter + ); + +static +BOOLEAN +AcquireTransmitRingEntries( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet, + OUT PUINT RingIndex + ); + +static +VOID +AssignPacketToRings( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet, + IN UINT RingIndex + ); + +static +VOID +MovePacketToStage2( + IN PPC586_ADAPTER Adapter + ); + +static +VOID +MovePacketToStage3( + IN PPC586_ADAPTER Adapter + ); + +static +VOID +RemovePacketFromStage3( + IN PPC586_ADAPTER Adapter + ); + +static +VOID +RelinquishPacket( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet, + ); + +static +VOID +CalculatePacketConstraints( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + +static +BOOLEAN +ConstrainPacket( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ); + + +extern +NDIS_STATUS +Pc586Send( + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE RequestHandle, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + The Pc586Send request instructs a MAC to transmit a packet through + the adapter onto the medium. + +Arguments: + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. In reality, it is a pointer to PC586_OPEN. + + RequestHandle - A value supplied by the NDIS interface that the MAC + must use when completing this request with the NdisCompleteRequest + service, if the MAC completes this request asynchronously. + + Packet - A pointer to a descriptor for the packet that is to be + transmitted. + +Return Value: + + The function value is the status of the operation. + + +--*/ + +{ + + // + // Holds the status that should be returned to the caller. + // + NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING; + + // + // Pointer to the adapter. + // + PPC586_ADAPTER Adapter; + + Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle); + NdisAcquireSpinLock(&Adapter->Lock); + Adapter->References++; + + if (!Adapter->ResetInProgress) { + + PPC586_OPEN Open; + + Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle); + + if (!Open->BindingShuttingDown) { + + UINT TotalPacketSize; + + // + // Increment the references on the open while we are + // accessing it in the interface. + // + + Open->References++; + + NdisReleaseSpinLock(&Adapter->Lock); + + // + // It is reasonable to do a quick check and fail if the packet + // is larger than the maximum an ethernet can handle. + // + + NdisQueryPacket( + Packet, + NULL, + NULL, + NULL, + &TotalPacketSize + ); + + if ((!TotalPacketSize) || + (TotalPacketSize > PC586_LARGE_BUFFER_SIZE)) { + + StatusToReturn = NDIS_INSUFFICIENT_RESOURCES; + NdisAcquireSpinLock(&Adapter->Lock); + + } else { + + // + // NOTE NOTE NOTE !!!!!! + // + // There is an assumption in the code that no pointer + // (which are really handles) to an ndis packet will have + // its low bit set. (Always have even byte alignment.) + // + + ASSERT(!((UINT)Packet & 1)); + + // + // Check to see if the packet should even make it out to + // the media. The primary reason this shouldn't *actually* + // be sent is if the destination is equal to the source + // address. + // + // If it doesn't need to be placed on the wire then we can + // simply put it onto the loopback queue. + // + + if (PacketShouldBeSent( + MacBindingHandle, + Packet + )) { + + // + // The packet needs to be placed out on the wire. + // + + SetupAllocate( + Adapter, + MacBindingHandle, + RequestHandle, + Packet + ); + + // + // Only try to push it through the stage queues + // if somebody else isn't already doing it and + // there is some hope of moving some packets + // ahead. + // + + NdisAcquireSpinLock(&Adapter->Lock); + while ((!(Adapter->AlreadyProcessingStage4 || + Adapter->AlreadyProcessingStage3 || + Adapter->AlreadyProcessingStage2) + ) && + ((Adapter->FirstStage3Packet && + Adapter->Stage4Open) || + (Adapter->FirstStage2Packet && + Adapter->Stage3Open) || + (Adapter->FirstStage1Packet && + Adapter->Stage2Open) + ) + ) { + + Pc586StagedAllocation(Adapter); + + } + + } else { + + PPC586_RESERVED Reserved; + + Reserved = PPC586_RESERVED_FROM_PACKET(Packet); + Reserved->MacBindingHandle = MacBindingHandle; + Reserved->RequestHandle = RequestHandle; + + NdisAcquireSpinLock(&Adapter->Lock); + + Pc586PutPacketOnLoopBack( + Adapter, + Packet, + TRUE + ); + + } + + } + + // + // The interface is no longer referencing the open. + // + + Open->References--; + + } else { + + StatusToReturn = NDIS_CLOSING; + + } + + } else { + + StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS; + + } + + PC586_DO_DEFERRED(Adapter); + return StatusToReturn; +} + +static +BOOLEAN +PacketShouldBeSent( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + Determines whether the packet should go out on the wire at all. + The way it does this is to see if the destination address is + equal to the source address. + +Arguments: + + MacBindingHandle - Is a pointer to the open binding. + + Packet - Packet whose source and destination addresses are tested. + +Return Value: + + Returns FALSE if the source is equal to the destination. + + +--*/ + +{ + + // + // Holds the source address from the packet. + // + CHAR Source[MAC_LENGTH_OF_ADDRESS]; + + // + // Holds the destination address from the packet. + // + CHAR Destination[MAC_LENGTH_OF_ADDRESS]; + + // + // variable to hold the length of the source address. + // + UINT AddressLength; + + // + // Will hold the result of the comparasion of the two MAC_NETWORD_ADDRESSes. + // + INT Result; + + Pc586CopyFromPacketToBuffer( + Packet, + 0, + MAC_LENGTH_OF_ADDRESS, + Destination, + &AddressLength + ); + ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS); + + + Pc586CopyFromPacketToBuffer( + Packet, + MAC_LENGTH_OF_ADDRESS, + MAC_LENGTH_OF_ADDRESS, + Source, + &AddressLength + ); + ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS); + + MAC_COMPARE_NETWORK_ADDRESSES( + Source, + Destination, + &Result + ); + + // + // If the result is 0 then the two addresses are equal and the + // packet shouldn't go out on the wire. + // + + return ((!Result)?(FALSE):(TRUE)); + +} + +static +VOID +SetupAllocate( + IN PPC586_ADAPTER Adapter, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE RequestHandle, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + This sets up the MAC reserved portion of the packet so that + later allocation routines can determine what is left to be + done in the allocation cycle. + +Arguments: + + Adapter - The adapter that this packet is coming through. + + MacBindingHandle - Points to the open binding structure. + + RequestHandle - Protocol supplied value. It is saved so that when + the send finnaly completes it can be used to indicate to the protocol. + + Packet - The packet that is to be transmitted. + +Return Value: + + None. + +--*/ + +{ + + // + // Points to the MAC reserved portion of this packet. This + // interpretation of the reserved section is only valid during + // the allocation phase of the packet. + // + PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet); + + + ASSERT(sizeof(PC586_RESERVED) <= + sizeof(Packet->MacReserved)); + + Reserved->STAGE.ClearStage = 0; + Reserved->MacBindingHandle = MacBindingHandle; + Reserved->RequestHandle = RequestHandle; + + // + // Determine if and how much adapter space would need to be allocated + // to meet hardware constraints. + // + + CalculatePacketConstraints( + Adapter, + Packet + ); + + NdisAcquireSpinLock(&Adapter->Lock); + + // + // Put on the stage 1 queue. + // + + if (!Adapter->LastStage1Packet) { + + Adapter->FirstStage1Packet = Packet; + + } else { + + PPC586_RESERVED_FROM_PACKET(Adapter->LastStage1Packet)->Next = Packet; + + } + + Adapter->LastStage1Packet = Packet; + + Reserved->Next = NULL; + + // + // Increment the reference on the open since it + // will be leaving this packet around on the transmit + // queues. + // + + PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References++; + + NdisReleaseSpinLock(&Adapter->Lock); + +} + +extern +VOID +Pc586StagedAllocation( + IN PPC586_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + This routine attempts to take a packet through a stage of allocation. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + None. + +--*/ + +{ + + // + // For each stage, we check to see that it is open, + // that somebody else isn't already processing, + // and that there is some work from the previous + // stage to do. + // + + if (Adapter->Stage2Open && + !Adapter->AlreadyProcessingStage2 && + Adapter->FirstStage1Packet) { + + // + // Holds whether the packet has been constrained + // to the hardware requirements. + // + BOOLEAN SuitableForHardware; + + PNDIS_PACKET FirstPacket = Adapter->FirstStage1Packet; + + Adapter->AlreadyProcessingStage2 = TRUE; + NdisReleaseSpinLock(&Adapter->Lock); + + SuitableForHardware = ConstrainPacket( + Adapter, + FirstPacket + ); + + NdisAcquireSpinLock(&Adapter->Lock); + if (SuitableForHardware) { + + MovePacketToStage2(Adapter); + Adapter->Stage2Open = FALSE; + } + + Adapter->AlreadyProcessingStage2 = FALSE; + + } + if (Adapter->Stage3Open && + !Adapter->AlreadyProcessingStage3 && + Adapter->FirstStage2Packet) { + + + + + + + + PNDIS_PACKET FirstPacket = Adapter->FirstStage2Packet; + + Adapter->AlreadyProcessingStage3 = TRUE; + + NdisReleaseSpinLock(&Adapter->Lock); + + // + // We look to see if there are enough ring entries. + // If there aren't then stage 3 will close. + // + // AcquireTransmitRingEntries will hold a spin lock + // for a short time. + // + +// the Acquire/Assign procs below may be used later for 586 command chaining + +// if (AcquireTransmitRingEntries( +// Adapter, +// FirstPacket, +// &RingIndex +// )) { + + // + // We have the number of buffers that we need. + // We assign all of the buffers to the ring entries. + // + +// AssignPacketToRings( +// Adapter, +// FirstPacket, +// RingIndex +// ); + + // + // We need exclusive access to the tranmit ring so + // that we can move this packet on to the next stage. + // + + + NdisAcquireSpinLock(&Adapter->Lock); + + MovePacketToStage3(Adapter); + + +// } else { +// +// Adapter->Stage3Open = FALSE; +// +// } + + Adapter->AlreadyProcessingStage3 = FALSE; + + } + if (Adapter->Stage4Open && + !Adapter->AlreadyProcessingStage4 && + Adapter->FirstStage3Packet) { + + // + // Holds a pointer to packet at the head of the + // stage 3. + // + PNDIS_PACKET Packet = Adapter->FirstStage3Packet; + + // + // We have a packet to work with. + // + // Take the packet off of the transmit work queue. + // + + RemovePacketFromStage3(Adapter); + + Adapter->AlreadyProcessingStage4 = TRUE; + + NdisReleaseSpinLock(&Adapter->Lock); + + RelinquishPacket( + Adapter, + Packet + ); + + NdisAcquireSpinLock(&Adapter->Lock); + + Adapter->AlreadyProcessingStage4 = FALSE; + + } + +} + +static +BOOLEAN +ConstrainPacket( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + Given a packet and if necessary attempt to acquire adapter + buffer resources so that the packet meets pc586 hardware + contraints. + +Arguments: + + Adapter - The adapter the packet is coming through. + + Packet - The packet whose buffers are to be constrained. + The packet reserved section is filled with information + detailing how the packet needs to be adjusted. + +Return Value: + + Returns TRUE if the packet is suitable for the hardware. + +--*/ + +{ + + // + // Pointer to the reserved section of the packet to be contrained. + // + PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet); + + + if (Reserved->STAGE.STAGE1.MinimumBufferRequirements) { + + // + // Will point into the virtual address space addressed + // by the adapter buffer if one was successfully allocated. + // + PCHAR CurrentDestination; + + // + // used to clear padding bytes in short packets + // + PUSHORT Clearing; + + // + // Will hold the total amount of data copied to the + // adapter buffer. + // + UINT TotalDataMoved = 0; + + + // + // Will point to the current source buffer. + // + PNDIS_BUFFER SourceBuffer; + + // + // Points to the virtual address of the source buffers data. + // + PUCHAR SourceData; + + // + // Will point to the number of bytes of data in the source + // buffer. + // + UINT SourceLength; + + // + // Simple iteration variable. + // + INT i; + + // + // the number of ndis buffers in an ndis packet + // + UINT BufferCount; + + // the 586 can only be touched on 16-bit boundries + + PUSHORT ShortAddr1, ShortAddr2; + + WaitScb(Adapter); + + if ( (Adapter->Cb->CmdStatus & CSBUSY) || + !(Adapter->Cb->CmdStatus & CSCMPLT) ) return FALSE; + + // + // Fill in the adapter buffer with the data from the users + // buffers. + // + // FIRST FILL IN THE 586 COMMAND BLOCK + + + NdisQueryPacket( + Packet, + NULL, + &BufferCount, + &SourceBuffer, + NULL + ); + + NdisQueryBuffer( + SourceBuffer, + NULL, + &(PVOID)SourceData, + &SourceLength + ); + + if (SourceLength < 14) { + DbgPrint("pc586 ConstrainPacket(): can't handle fragmented xmt buffers\n"); + SourceLength = 14; // ??? + } + Adapter->Cb->CmdStatus = 0; + Adapter->Cb->CmdCmd = CSEL | CSCMDXMIT | CSINT; + Adapter->Cb->CmdNxtOfst = OFFSETCU; // only one Cb, points to self + + Adapter->Cb->PRMTR.PrmXmit.XmtTbdOfst = OFFSETTBD; + + ShortAddr2 = (PUSHORT)(Adapter->Cb->PRMTR.PrmXmit.XmtDest); + ShortAddr1 = (PUSHORT)SourceData; + + *ShortAddr2++ = *ShortAddr1++; + *ShortAddr2++ = *ShortAddr1++; + *ShortAddr2++ = *ShortAddr1++; + + SourceData+=12; // skip over dest and source addresses + SourceLength-=12; + + ShortAddr1 = (PUSHORT)SourceData; + + Adapter->Cb->PRMTR.PrmXmit.XmtLength = *ShortAddr1; + + SourceData+=2; // skip over length field + SourceLength-=2; + + // SECOND FILL IN XMT BUFFER DESCRIPTOR + + Adapter->Tbd->TbdNxtOfst = 0xffff; + Adapter->Tbd->TbdBuff = OFFSETTBUF; + Adapter->Tbd->TbdBuffBase = 0; + + + // THIRD FILL IN XMT DATA + + + // 64 is minimum packet length, incl 6 source, 6 dest addr, 2 len + if (SourceLength < 64 - 14) { + Clearing = (PUSHORT)(Adapter->CommandBuffer); + for (i = 0; i <= 64 - 14; i +=2) + *Clearing++ = 0; + } + + CurrentDestination = (PCHAR)(Adapter->CommandBuffer); + + for ( + i = Reserved->STAGE.STAGE1.NdisBuffersToMove; + i; + i-- + ) { + + + Pc586MoveToAdapter( + (PVOID)CurrentDestination, + (PVOID)SourceData, + SourceLength + ); + + CurrentDestination = (PCHAR)(CurrentDestination + SourceLength); + + TotalDataMoved += SourceLength; + + if (i > 1) { + + NdisGetNextBuffer( + SourceBuffer, + &SourceBuffer + ); + + if (SourceBuffer == NULL) { + DbgPrint("PC586 ConstrainPacket(): NULL NDIS BUFFER\n"); + break; + } + + NdisQueryBuffer( + SourceBuffer, + NULL, + &(PVOID)SourceData, + &SourceLength + ); + + } + + } + if (TotalDataMoved < 64 - 14 ) TotalDataMoved = 64 - 14; //required by 802.3 + Adapter->Tbd->TbdCount = (USHORT)TotalDataMoved | (USHORT)CSEOF; + + // Reserved->STAGE.STAGE2.UsedPc586Buffer = TRUE; might be used later + Reserved->STAGE.ClearStage = 0; + Adapter->OwningPacket = Packet; + + } + + return TRUE; +} + +static +VOID +CalculatePacketConstraints( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet + ) + +/*++ + +Routine Description: + + Given a packet calculate how the packet will have to be + adjusted to meet with hardware constraints. + +Arguments: + + Adapter - The adapter the packet is coming through. + + Packet - The packet whose buffers are to be reallocated. + The packet reserved section is filled with information + detailing how the packet needs to be adjusted. + +Return Value: + + None. + +--*/ + +{ + + // + // ZZZ This is not a portable routine. The MDLs that make + // up the physical address are not available on OS/2 and + // DOS. + // + + + // + // A basic principle here is that the reallocation of some or + // all of the user buffers to adapter buffers will only allocate + // a single adapter buffer. + // + + // + // Points to the reserved portion of the packet. + // + PPC586_RESERVED Reserved = PPC586_RESERVED_FROM_PACKET(Packet); + + // + // The number of ndis buffers in the packet. + // + UINT NdisBufferCount; + + // + // The number of physical buffers in the entire packet. + // + UINT PhysicalBufferCount; + + // + // Points to the current ndis buffer being walked. + // + PNDIS_BUFFER CurrentBuffer; + + // + // Points to the mdl for the current ndis buffer. + // + NDIS_PHYSICAL_ADDRESS PointerToMdl; + + // + // The virtual address of the current ndis buffer. + // + PVOID VirtualAddress; + + // + // The length in bytes of the current ndis buffer. + // + UINT CurrentVirtualLength; + + // + // The total amount of data contained within the ndis packet. + // + UINT TotalVirtualLength; + + // + // Pointer into an array of physical pages numbers for the mdl. + // + PULONG PhysicalAddressElement; + + // + // An actual physical address. + // + PHYSICAL_ADDRESS PhysicalAddress; + + // + // The amount of memory used in the current physical + // page for the buffer. + // + UINT LengthOfPhysicalBuffer; + + // + // Holds the number of Ndis buffers that we have queried. + // + UINT NdisBuffersExamined; + + // + // The total amount of virtual memory in bytes contained in all of the + // ndis buffers examined. + // + UINT VirtualMemoryPassed; + + + // + // Get the first buffer. + // + + NdisQueryPacket( + Packet, + &PhysicalBufferCount, + &NdisBufferCount, + &CurrentBuffer, + &TotalVirtualLength + ); + + NdisQueryBuffer( + CurrentBuffer, + &PointerToMdl, + &VirtualAddress, + &CurrentVirtualLength + ); + +// +// Certain hardware implementation (Decstation) use a dual ported +// memory to communicate with the hardware. This is reasonable since +// it reduces bus contention. When using the dual ported memory, all +// send data must be moved to buffers allocated from the dual ported +// memory. +// +// #ifdef PC586_USE_HARDWARE_MEMORY + + VirtualMemoryPassed = TotalVirtualLength; + NdisBuffersExamined = NdisBufferCount; + +// #else // PC586_USE_HARDWARE_MEMORY + +// +// In the interests of keeping silo underflow from occuring +// we might want to disable data chaining. In this case the +// only time we don't copy to the adapters buffers is if there +// is only one physical buffer in the packet and it is greater +// than the minimum single buffer length. + +// #endif // PC586_USE_HARDDWARE_MEMORY + + Reserved->STAGE.STAGE1.MinimumBufferRequirements = 3; + + Reserved->STAGE.STAGE1.NdisBuffersToMove = NdisBuffersExamined; + +} + + +static +VOID +MovePacketToStage2( + IN PPC586_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Move a packet from the stage 1 allocation to stage 2 allocation. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_PACKET PacketToMove = Adapter->FirstStage1Packet; + + // + // First remove it from the stage 1 queue; + // + + Adapter->FirstStage1Packet = + PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next; + + if (!Adapter->FirstStage1Packet) { + + Adapter->LastStage1Packet = NULL; + + } + + // + // Now put it on the stage 2 queue. + // + + if (!Adapter->FirstStage2Packet) { + + Adapter->FirstStage2Packet = PacketToMove; + + } else { + + PPC586_RESERVED_FROM_PACKET(Adapter->LastStage2Packet)->Next = + PacketToMove; + + + } + + Adapter->LastStage2Packet = PacketToMove; + PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL; +} + +static +VOID +MovePacketToStage3( + IN PPC586_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Move a packet from the stage 2 allocation to stage 3 allocation. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_PACKET PacketToMove = Adapter->FirstStage2Packet; + + // + // First remove it from the stage 2 queue. + // + + Adapter->FirstStage2Packet = + PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next; + + if (!Adapter->FirstStage2Packet) { + + Adapter->LastStage2Packet = NULL; + + } + + // + // Now put it on the stage 3 queue. + // + + if (!Adapter->FirstStage3Packet) { + + Adapter->FirstStage3Packet = PacketToMove; + + } else { + + PPC586_RESERVED_FROM_PACKET(Adapter->LastStage3Packet)->Next = + PacketToMove; + + + } + + Adapter->LastStage3Packet = PacketToMove; + PPC586_RESERVED_FROM_PACKET(PacketToMove)->Next = NULL; + +} + +static +VOID +RemovePacketFromStage3( + IN PPC586_ADAPTER Adapter + ) + +/*++ + +Routine Description: + + Removes a the packet from the from of the stage 3 allocation + list. + +Arguments: + + Adapter - The adapter that the packets are coming through. + +Return Value: + + None. + +--*/ + +{ + + PNDIS_PACKET PacketToRemove = Adapter->FirstStage3Packet; + + // + // Holds the destination address of the packet. + // + CHAR Address[MAC_LENGTH_OF_ADDRESS]; + + // + // Holds the length of data we got from getting the + // address from the packet. + // + UINT AddressLength; + + + // + // First remove it from stage 3. + // + + Adapter->FirstStage3Packet = + PPC586_RESERVED_FROM_PACKET(PacketToRemove)->Next; + + if (!Adapter->FirstStage3Packet) { + + Adapter->LastStage3Packet = NULL; + + } + + // + // Do a quick check to see if the packet has a high likelyhood + // of needing to loopback. (NOTE: This means that if the packet + // must be loopbacked then this function will return true. If + // the packet doesn't need to be loopbacked then the function + // will probably return false.) + // + + Pc586CopyFromPacketToBuffer( + PacketToRemove, + 0, + MAC_LENGTH_OF_ADDRESS, + Address, + &AddressLength + ); + ASSERT(AddressLength == MAC_LENGTH_OF_ADDRESS); + + if (MacShouldAddressLoopBack( + Adapter->FilterDB, + Address + )) { + + Pc586PutPacketOnLoopBack( + Adapter, + PacketToRemove, + FALSE + ); + + } else { + + Pc586PutPacketOnFinishTrans( + Adapter, + PacketToRemove + ); + + } + + return; + +} + +static +VOID +RelinquishPacket( + IN PPC586_ADAPTER Adapter, + IN PNDIS_PACKET Packet, + ) + +/*++ + +Routine Description: + + Relinquish the ring entries owned by the packet to the chip. + We also update the first uncommitted ring pointer. + +Arguments: + + Adapter - The adapter that points to the ring entry structures. + + Packet - The packet contains the ring index of the first ring + entry for the packet. + + +Return Value: + + None. + +--*/ + +{ + // FOURTH MAKE 586 DO A TRANSMIT + + NdisAcquireSpinLock(&Adapter->Lock); + WaitScb(Adapter); + + Adapter->Scb->ScbCmd = SCBCUCSTRT; + ChanAttn(Adapter); + + NdisReleaseSpinLock(&Adapter->Lock); + +} + + |