summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/pc586e/pc586snd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/pc586e/pc586snd.c1300
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);
+
+}
+
+