summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/sonic
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/ndis/sonic')
-rw-r--r--private/ntos/ndis/sonic/alloc.c1137
-rw-r--r--private/ntos/ndis/sonic/i386/sonicdet.h68
-rw-r--r--private/ntos/ndis/sonic/interrup.c1694
-rw-r--r--private/ntos/ndis/sonic/makefile6
-rw-r--r--private/ntos/ndis/sonic/mips/sonicdet.h89
-rw-r--r--private/ntos/ndis/sonic/request.c890
-rw-r--r--private/ntos/ndis/sonic/send.c1305
-rw-r--r--private/ntos/ndis/sonic/sonic.c2800
-rw-r--r--private/ntos/ndis/sonic/sonic.rc39
-rw-r--r--private/ntos/ndis/sonic/sonichrd.h791
-rw-r--r--private/ntos/ndis/sonic/sonicsft.h1039
-rw-r--r--private/ntos/ndis/sonic/sources61
-rw-r--r--private/ntos/ndis/sonic/transfer.c247
13 files changed, 10166 insertions, 0 deletions
diff --git a/private/ntos/ndis/sonic/alloc.c b/private/ntos/ndis/sonic/alloc.c
new file mode 100644
index 000000000..354461735
--- /dev/null
+++ b/private/ntos/ndis/sonic/alloc.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ alloc.c
+
+Abstract:
+
+ This file contains the code for allocating and freeing adapter
+ resources for the National Semiconductor SONIC Ethernet controller.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+STATIC
+PNDIS_BUFFER
+AllocateFlushBuffer(
+ IN PSONIC_ADAPTER Adapter,
+ IN PVOID VirtualAddress,
+ IN ULONG Length
+ );
+
+
+#pragma NDIS_INIT_FUNCTION(AllocateFlushBuffer)
+
+STATIC
+PNDIS_BUFFER
+AllocateFlushBuffer(
+ IN PSONIC_ADAPTER Adapter,
+ IN PVOID VirtualAddress,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates an NDIS_BUFFER for the specified address and length.
+ This function is intended to create NDIS_BUFFERs for flushing.
+
+Arguments:
+
+ Adapter - The adapter the buffer is for. It must have a
+ FlushBufferPoolHandle that points to a valid buffer pool.
+
+ VirtualAddress - A pointer to the buffer to describe.
+
+ Length - The length of the buffer.
+
+Return Value:
+
+ The NDIS_BUFFER if one was allocated.
+ NULL if an NDIS_BUFFER could not be allocated.
+
+--*/
+
+{
+ PNDIS_BUFFER ReturnBuffer;
+ NDIS_STATUS Status;
+
+ NdisAllocateBuffer(
+ &Status,
+ &ReturnBuffer,
+ Adapter->FlushBufferPoolHandle,
+ VirtualAddress,
+ Length
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not allocate flush buffer, %x\n", Status);
+#endif
+ ReturnBuffer = (PNDIS_BUFFER)NULL;
+ }
+
+
+ return ReturnBuffer;
+}
+
+
+#pragma NDIS_INIT_FUNCTION(AllocateAdapterMemory)
+
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to allocate memory for.
+
+Return Value:
+
+ Returns FALSE if some memory needed for the adapter could not
+ be allocated. It does NOT call DeleteAdapterMemory in this
+ case.
+
+--*/
+
+{
+
+ //
+ // Pointer to a transmit ring entry. Used while initializing
+ // the TDA.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor;
+
+ //
+ // Pointer to a receive buffer. Used while allocated the
+ // RBAs.
+ //
+ PVOID * CurrentReceiveBuffer;
+
+ //
+ // Pointer to a receive descriptor. Used while initialing
+ // the RDA.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor;
+
+ //
+ // Used for determining physical addresses.
+ //
+ SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr;
+
+ //
+ // Used for NDIS allocation routines that return an NDIS_PHYSICAL_ADDRESS
+ //
+ NDIS_PHYSICAL_ADDRESS NdisPhysicalAdr;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+ //
+ // Used to flush buffers that only need to be flushed once.
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // The size of the buffer pool needed.
+ //
+ UINT PoolBuffersNeeded;
+
+ //
+ // Holds the result of calls to SONIC_ALLOC_MEMORY
+ //
+ NDIS_STATUS AllocStatus;
+
+
+
+ //
+ // We need some NDIS_BUFFERs to describe memory that we
+ // allocate (generally either to flush the buffer, or
+ // because we need its physical address). To do this
+ // we need a buffer pool, so we have to determine how
+ // many buffers we need.
+ //
+ PoolBuffersNeeded =
+ 1 + // for CamDescriptorArea
+ 1 + // for ReceiveResourceArea
+ 1 + // for BlankBuffer
+ Adapter->NumberOfReceiveBuffers + // for flushing cached receive buffers.
+ SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS ;
+
+ NdisAllocateBufferPool(
+ &AllocStatus,
+ &Adapter->FlushBufferPoolHandle,
+ PoolBuffersNeeded
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not allocate flush buffer pool\n");
+#endif
+ return FALSE;
+
+ }
+
+
+
+ //
+ // Allocate the transmit ring descriptors.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_TRANSMIT_DESCRIPTOR)*
+ Adapter->NumberOfTransmitDescriptors,
+ FALSE, // non-cached
+ (PVOID *)&Adapter->TransmitDescriptorArea,
+ &Adapter->TransmitDescriptorAreaPhysical
+ );
+
+ if (Adapter->TransmitDescriptorArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: TransmitDescriptorArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->TransmitDescriptorAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: TransmitDescriptorArea memory too high\n");
+#endif
+ return FALSE;
+ }
+
+
+
+ //
+ // Clean the above memory
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->TransmitDescriptorArea,
+ (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors)
+ );
+
+
+ //
+ // We have the transmit ring descriptors. Initialize the Link
+ // fields.
+ //
+
+ for (
+ i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea;
+ i < Adapter->NumberOfTransmitDescriptors;
+ i++,CurrentTransmitDescriptor++
+ ) {
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr;
+
+ } else {
+
+ (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Allocate the ring to packet structure.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->DescriptorToPacket,
+ sizeof(SONIC_DESCRIPTOR_TO_PACKET)
+ *Adapter->NumberOfTransmitDescriptors
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+
+ //
+ // We have to do this now. The PrevLinkPointer field is used
+ // to point to where the Link field of the previous transmit
+ // descriptor is; it is normally set when the previous
+ // transmit descriptor is filled. For the very first packet
+ // transmitted there will have been no previous transmit
+ // descriptor, so we fill it in ourselves. We use the
+ // Link field of the last transmit descriptor (the actual
+ // location used doesn't really matter, as long as it is
+ // a valid address).
+ //
+
+ Adapter->DescriptorToPacket->PrevLinkPointer =
+ &(Adapter->TransmitDescriptorArea[
+ Adapter->NumberOfTransmitDescriptors-1].Link);
+
+
+ //
+ // Allocate the receive resource area and the
+ // CAM descriptor area. These are allocated together
+ // since they must have the same high 16 bits in
+ // their addresses.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) +
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA),
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->ReceiveResourceArea,
+ &Adapter->ReceiveResourceAreaPhysical
+ );
+
+ if (Adapter->ReceiveResourceArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveResourceArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->ReceiveResourceAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveResourceArea memory too high\n");
+#endif
+ return FALSE;
+
+ }
+
+
+ //
+ // The CAM Descriptor Area is immediately after the RRA.
+ //
+
+ Adapter->CamDescriptorArea = (PSONIC_CAM_DESCRIPTOR_AREA)
+ (Adapter->ReceiveResourceArea + Adapter->NumberOfReceiveBuffers);
+
+ Adapter->CamDescriptorAreaPhysical =
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical) +
+ ((PUCHAR)Adapter->CamDescriptorArea -
+ (PUCHAR)Adapter->ReceiveResourceArea);
+
+
+ //
+ // Allocate the NDIS_BUFFER to flush the CAM Descriptor Area.
+ //
+ Adapter->CamDescriptorAreaFlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ Adapter->CamDescriptorArea,
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA)
+ );
+
+ if (!Adapter->CamDescriptorAreaFlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_ZERO_MEMORY(
+ Adapter->CamDescriptorArea,
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA)
+ );
+
+ SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer);
+
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Cam Descriptor Area: %lx physical: %lx\n",
+ Adapter->CamDescriptorArea,
+ Adapter->CamDescriptorAreaPhysical);
+ }
+#endif
+
+ //
+ // Allocate the array to hold pointers to the RBAs.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->ReceiveBufferArea,
+ sizeof(PVOID) * Adapter->NumberOfReceiveBuffers
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+ }
+
+ //
+ // Allocate the array to hold pointers to the receive ndis
+ // (flush) buffers.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->ReceiveNdisBufferArea,
+ sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+
+ return FALSE;
+ }
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Receive Buffer Area: %lx\n",
+ (ULONG)Adapter->ReceiveBufferArea);
+ }
+#endif
+
+
+ //
+ // We have the receive buffer pointers. Allocate the buffer
+ // for each entry and zero them.
+ //
+ // For each receive buffer, the Physical address and length
+ // will be in Adapter->ReceiveResourceArea[i], while the
+ // virtual address will be in Adapter->ReceiveBufferArea[i].
+ //
+
+ for (
+ i = 0, CurrentReceiveBuffer = Adapter->ReceiveBufferArea;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++,CurrentReceiveBuffer++
+ ) {
+
+ //
+ // Allocate the next [cached] receive buffer.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE, // CACHED!
+ CurrentReceiveBuffer,
+ &NdisPhysicalAdr
+ );
+
+ //
+ // Did the allocation fail?
+ //
+
+ if ( *CurrentReceiveBuffer == NULL ) {
+
+ return FALSE;
+ }
+
+ if ( NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+
+ return FALSE;
+ }
+
+ //
+ // Zero the [cached] receive buffer.
+ //
+
+ SONIC_ZERO_MEMORY(
+ *CurrentReceiveBuffer,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+
+
+ //
+ // Allocate an NDIS_BUFFER for this receive buffer.
+ //
+
+ Adapter->ReceiveNdisBufferArea[i] = AllocateFlushBuffer(
+ Adapter,
+ *CurrentReceiveBuffer,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+
+ if ( Adapter->ReceiveNdisBufferArea[i] == NULL ) {
+
+ return FALSE;
+
+ }
+
+ SONIC_SET_RECEIVE_RESOURCE_ADDRESS(
+ &Adapter->ReceiveResourceArea[i],
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr)
+ );
+
+ SONIC_SET_RECEIVE_RESOURCE_LENGTH(
+ &Adapter->ReceiveResourceArea[i],
+ SONIC_SIZE_OF_RECEIVE_BUFFERS
+ );
+ }
+
+
+ //
+ // The Receive Resource Area is set up, we can flush
+ // it now since it does not change.
+ //
+
+ FlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ (PVOID)Adapter->ReceiveResourceArea,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers)
+ );
+
+ if (!FlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_FLUSH_WRITE_BUFFER(FlushBuffer);
+
+ NdisFreeBuffer(FlushBuffer);
+
+ //
+ // Allocate memory to hold the receive descriptor pointers.
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) * Adapter->NumberOfReceiveDescriptors,
+ FALSE, // NON-CACHED!
+ (PVOID *)&Adapter->ReceiveDescriptorArea,
+ &Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+
+ if (Adapter->ReceiveDescriptorArea == NULL) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveDescriptorArea memory invalid\n");
+#endif
+ return FALSE;
+
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->ReceiveDescriptorAreaPhysical) != 0) {
+
+#if DBG
+ DbgPrint("SONIC: ReceiveDescriptorArea memory too high\n");
+#endif
+ return FALSE;
+
+ }
+
+
+
+ //
+ // Clean the above memory
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->ReceiveDescriptorArea,
+ (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors)
+ );
+
+
+ //
+ // Now set up the Link fields in the receive descriptors.
+ //
+
+ for (
+ i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea;
+ i < Adapter->NumberOfReceiveDescriptors;
+ i++,CurrentReceiveDescriptor++
+ ) {
+
+ //
+ // belongs to SONIC.
+ //
+
+ CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC;
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_RECEIVE_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1].Link =
+ SonicPhysicalAdr | SONIC_END_OF_LIST;
+
+ } else {
+
+ Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Allocate the array of buffer descriptors.
+ //
+
+ SONIC_ALLOC_MEMORY(
+ &AllocStatus,
+ &Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+ if (AllocStatus != NDIS_STATUS_SUCCESS) {
+ return FALSE;
+ }
+
+ //
+ // Zero the memory of all the descriptors so that we can
+ // know which buffers wern't allocated incase we can't allocate
+ // them all.
+ //
+ SONIC_ZERO_MEMORY(
+ Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+
+ //
+ // Allocate space for the small sonic buffers and fill in the
+ // buffer descriptors.
+ //
+
+ Adapter->SonicBufferListHeads[0] = -1;
+ Adapter->SonicBufferListHeads[1] = 0;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS,
+ TRUE, // CACHED!
+ &Adapter->SmallSonicBuffers,
+ &NdisPhysicalAdr
+ );
+
+ if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+
+ return FALSE;
+ }
+
+ if ( Adapter->SmallSonicBuffers == NULL ) {
+
+ return FALSE;
+ }
+
+ for (
+ i = 0;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS;
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID)
+ ((PUCHAR)Adapter->SmallSonicBuffers +
+ (i * SONIC_SMALL_BUFFER_SIZE));
+
+ NdisSetPhysicalAddressHigh(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ 0);
+
+ NdisSetPhysicalAddressLow(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr) +
+ (i * SONIC_SMALL_BUFFER_SIZE));
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_SMALL_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+ //
+ // Do the medium buffers now.
+ //
+
+ Adapter->SonicBufferListHeads[2] = i;
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS,
+ TRUE, // CACHED!
+ &Adapter->MediumSonicBuffers,
+ &NdisPhysicalAdr
+ );
+
+
+ if (Adapter->MediumSonicBuffers == NULL) {
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(NdisPhysicalAdr) != 0) {
+ return FALSE;
+ }
+
+
+
+ for (
+ ;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS + SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].VirtualSonicBuffer = (PVOID)
+ ((PUCHAR)Adapter->MediumSonicBuffers +
+ ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE));
+
+ NdisSetPhysicalAddressHigh(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ 0);
+
+ NdisSetPhysicalAddressLow(
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer,
+ NdisGetPhysicalAddressLow(NdisPhysicalAdr) +
+ ((i - SONIC_NUMBER_OF_SMALL_BUFFERS) * SONIC_MEDIUM_BUFFER_SIZE));
+
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_MEDIUM_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+ //
+ // Now do the large buffers; note that they have one
+ // Physical address per buffer.
+ //
+
+ Adapter->SonicBufferListHeads[3] = i;
+
+ for (
+ ;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++
+ ) {
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_LARGE_BUFFER_SIZE,
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ &Adapter->SonicBuffers[i].PhysicalSonicBuffer
+ );
+
+ if (Adapter->SonicBuffers[i].VirtualSonicBuffer == NULL) {
+
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->SonicBuffers[i].PhysicalSonicBuffer) != 0) {
+ return FALSE;
+ }
+
+ Adapter->SonicBuffers[i].FlushBuffer =
+ AllocateFlushBuffer(
+ Adapter,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ SONIC_LARGE_BUFFER_SIZE
+ );
+
+ if (!Adapter->SonicBuffers[i].FlushBuffer) {
+ return FALSE;
+ }
+
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ //
+ // Make sure that the last buffer correctly terminates the free list.
+ //
+
+ Adapter->SonicBuffers[i-1].Next = -1;
+
+
+ //
+ // Allocate the BlankBuffer
+ //
+
+ NdisMAllocateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE,
+ TRUE, // CACHED!
+ (PVOID *)&Adapter->BlankBuffer,
+ &Adapter->BlankBufferAddress
+ );
+
+ if (Adapter->BlankBuffer == NULL) {
+ return FALSE;
+ }
+
+ if (NdisGetPhysicalAddressHigh(Adapter->BlankBufferAddress) != 0) {
+ return FALSE;
+ }
+
+ for (i=0; i < SONIC_SMALL_BUFFER_SIZE; i++) {
+
+ Adapter->BlankBuffer[i] = ' ';
+
+ }
+
+
+ //
+ // Flush the blank buffer now, it never changes.
+ //
+
+ FlushBuffer = AllocateFlushBuffer(
+ Adapter,
+ Adapter->BlankBuffer,
+ SONIC_SMALL_BUFFER_SIZE
+ );
+
+ if (!FlushBuffer) {
+ return FALSE;
+ }
+
+ SONIC_FLUSH_WRITE_BUFFER(FlushBuffer);
+
+ //
+ // We are done with the FlushBuffer.
+ //
+
+ NdisFreeBuffer(FlushBuffer);
+
+
+ return TRUE;
+
+}
+
+
+extern
+VOID
+DeleteAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates memory for:
+
+ - Transmit ring entries
+
+ - Receive ring entries
+
+ - Receive buffers
+
+ - Adapter buffers for use if user transmit buffers don't meet hardware
+ contraints
+
+ - Structures to map transmit ring entries back to the packets.
+
+Arguments:
+
+ Adapter - The adapter to deallocate memory for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (Adapter->TransmitDescriptorArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_TRANSMIT_DESCRIPTOR)*
+ Adapter->NumberOfTransmitDescriptors,
+ FALSE,
+ Adapter->TransmitDescriptorArea,
+ Adapter->TransmitDescriptorAreaPhysical
+ );
+
+ }
+
+ if (Adapter->CamDescriptorAreaFlushBuffer) {
+
+ NdisFreeBuffer(Adapter->CamDescriptorAreaFlushBuffer);
+
+ }
+
+ if (Adapter->ReceiveBufferArea) {
+
+ UINT i;
+ NDIS_PHYSICAL_ADDRESS PhysicalAddr;
+
+ for (
+ i = 0;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++
+ ) {
+
+ //
+ // Free the receive flush buffer.
+ //
+
+ if ( Adapter->ReceiveNdisBufferArea[i] != NULL ) {
+
+ NdisFreeBuffer(Adapter->ReceiveNdisBufferArea[i]);
+
+ }
+
+ //
+ // Free the receive buffer.
+ //
+
+ if ( Adapter->ReceiveBufferArea[i] != NULL ) {
+
+ NdisSetPhysicalAddressHigh(PhysicalAddr, 0);
+
+ NdisSetPhysicalAddressLow(
+ PhysicalAddr,
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i]));
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ TRUE, //... CACHED!
+ Adapter->ReceiveBufferArea[i],
+ PhysicalAddr
+ );
+ }
+ }
+
+ SONIC_FREE_MEMORY(
+ Adapter->ReceiveBufferArea,
+ sizeof(PVOID) * Adapter->NumberOfReceiveBuffers
+ );
+
+ SONIC_FREE_MEMORY(
+ Adapter->ReceiveNdisBufferArea,
+ sizeof(PNDIS_BUFFER) * Adapter->NumberOfReceiveBuffers
+ );
+ }
+
+ if (Adapter->ReceiveResourceArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ (sizeof(SONIC_RECEIVE_RESOURCE)*Adapter->NumberOfReceiveBuffers) +
+ sizeof(SONIC_CAM_DESCRIPTOR_AREA),
+ TRUE,
+ Adapter->ReceiveResourceArea,
+ Adapter->ReceiveResourceAreaPhysical
+ );
+
+ }
+
+ if (Adapter->ReceiveDescriptorArea) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) *
+ Adapter->NumberOfReceiveDescriptors,
+ FALSE,
+ Adapter->ReceiveDescriptorArea,
+ Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+ }
+
+ if (Adapter->DescriptorToPacket) {
+
+ SONIC_FREE_MEMORY(Adapter->DescriptorToPacket,
+ sizeof(SONIC_DESCRIPTOR_TO_PACKET)
+ *Adapter->NumberOfTransmitDescriptors);
+
+ }
+
+
+ if (Adapter->SmallSonicBuffers) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE * SONIC_NUMBER_OF_SMALL_BUFFERS,
+ TRUE,
+ Adapter->SmallSonicBuffers,
+ Adapter->SonicBuffers[0].PhysicalSonicBuffer
+ );
+
+ }
+
+ if (Adapter->MediumSonicBuffers) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_MEDIUM_BUFFER_SIZE * SONIC_NUMBER_OF_MEDIUM_BUFFERS,
+ TRUE,
+ Adapter->MediumSonicBuffers,
+ Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS].PhysicalSonicBuffer
+ );
+
+ }
+
+ if (Adapter->SonicBuffers) {
+
+ UINT i;
+
+ //
+ // First free the large buffers.
+ //
+
+ for (
+ i = SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++) {
+
+ if (Adapter->SonicBuffers[i].VirtualSonicBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_LARGE_BUFFER_SIZE,
+ TRUE,
+ Adapter->SonicBuffers[i].VirtualSonicBuffer,
+ Adapter->SonicBuffers[i].PhysicalSonicBuffer
+ );
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Now free the flush buffers.
+ //
+
+ for (
+ i = 0;
+ i < SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS;
+ i++) {
+
+ if (Adapter->SonicBuffers[i].FlushBuffer) {
+ NdisFreeBuffer(Adapter->SonicBuffers[i].FlushBuffer);
+ }
+
+ }
+
+ SONIC_FREE_MEMORY(Adapter->SonicBuffers,
+ sizeof(SONIC_BUFFER_DESCRIPTOR)*
+ (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS)
+ );
+
+ }
+
+
+ if (Adapter->BlankBuffer) {
+
+ NdisMFreeSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SMALL_BUFFER_SIZE,
+ TRUE,
+ Adapter->BlankBuffer,
+ Adapter->BlankBufferAddress
+ );
+
+ }
+
+
+ if (Adapter->FlushBufferPoolHandle) {
+
+ NdisFreeBufferPool(Adapter->FlushBufferPoolHandle);
+
+ }
+
+}
diff --git a/private/ntos/ndis/sonic/i386/sonicdet.h b/private/ntos/ndis/sonic/i386/sonicdet.h
new file mode 100644
index 000000000..e318ed667
--- /dev/null
+++ b/private/ntos/ndis/sonic/i386/sonicdet.h
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicdet.h
+
+Abstract:
+
+ This file has processor-specific definitions.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 5-Nov-1991
+
+Environment:
+
+ This driver is expected at the equivalent of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+
+//
+// Handy macros to read out of sonic ports.
+//
+// Because the use of PortShift makes the code more complicated,
+// we make some assumptions about when it is needed. On x86, we
+// only support the EISA card; on MIPS, we only support the
+// internal version unless MIPS_EISA_SONIC is defined.
+//
+// We define two constants, SONIC_EISA and SONIC_INTERNAL, if
+// that particular adapter type is supported by this driver.
+// This is to prevent unneeded code from being compiled in.
+//
+
+
+//
+// x86, only the EISA card is supported, the registers are always 16 bits.
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 2), (PUSHORT)(_Value))
+
+
+#define SONIC_EISA
+#undef SONIC_INTERNAL
+#undef MIPS_EISA_SONIC // just in case it is defined
+
+
+//
+// The default adapter type is EISA
+//
+
+#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_EISA
diff --git a/private/ntos/ndis/sonic/interrup.c b/private/ntos/ndis/sonic/interrup.c
new file mode 100644
index 000000000..f3034f80e
--- /dev/null
+++ b/private/ntos/ndis/sonic/interrup.c
@@ -0,0 +1,1694 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ interrup.c
+
+Abstract:
+
+ This is a part of the driver for the National Semiconductor SONIC
+ Ethernet controller. It contains the interrupt-handling routines.
+ This driver conforms to the NDIS 3.0 miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 16-Jan-1991
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+#define REMOVE_EOL_AND_ACK(A,L) \
+{ \
+ PSONIC_ADAPTER _A = A; \
+ SONIC_REMOVE_END_OF_LIST(L); \
+ if ((_A)->ReceiveDescriptorsExhausted) { \
+ SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \
+ SONIC_INT_RECEIVE_DESCRIPTORS \
+ ); \
+ (_A)->ReceiveDescriptorsExhausted = FALSE; \
+ } \
+}
+
+#define WRITE_RWP_AND_ACK(A,RWP) \
+{ \
+ PSONIC_ADAPTER _A = A; \
+ SONIC_WRITE_PORT((_A), SONIC_RESOURCE_WRITE, (RWP)); \
+ if ((_A)->ReceiveBuffersExhausted) { \
+ SONIC_WRITE_PORT((_A), SONIC_INTERRUPT_STATUS, \
+ SONIC_INT_RECEIVE_BUFFERS \
+ ); \
+ (_A)->ReceiveBuffersExhausted = FALSE; \
+ } \
+}
+
+
+VOID
+SonicDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to turn off all interrupts from the adapter.
+
+Arguments:
+
+ Context - A pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ 0
+ );
+
+}
+
+VOID
+SonicEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to turn on all interrupts from the adapter.
+
+Arguments:
+
+ Context - A pointer to the adapter block
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ SONIC_INT_DEFAULT_VALUE
+ );
+
+}
+
+
+
+
+
+STATIC
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+VOID
+ProcessInterrupt(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+extern
+VOID
+SonicInterruptService(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Interrupt service routine for the sonic. This routine only gets
+ called during initial initialization of the adapter.
+
+Arguments:
+
+ InterruptRecognized - Boolean value which returns TRUE if the
+ ISR recognizes the interrupt as coming from this adapter.
+
+ QueueDpc - TRUE if a DPC should be queued.
+
+ Context - Really a pointer to the adapter.
+
+Return Value:
+
+ Returns true if the card ISR is non-zero.
+
+--*/
+
+{
+
+ //
+ // Will hold the value from the ISR.
+ //
+ USHORT LocalIsrValue;
+
+ //
+ // Holds the pointer to the adapter.
+ //
+ PSONIC_ADAPTER Adapter = Context;
+
+
+ SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &LocalIsrValue);
+
+ if (LocalIsrValue != 0x0000) {
+
+#if DBG
+ if (SonicDbg) {
+ if (LocalIsrValue & (
+ SONIC_INT_BUS_RETRY |
+ SONIC_INT_LOAD_CAM_DONE |
+ SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_TRANSMIT_ERROR |
+ SONIC_INT_RECEIVE_DESCRIPTORS |
+ SONIC_INT_RECEIVE_BUFFERS |
+ SONIC_INT_RECEIVE_OVERFLOW |
+ SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER
+ )) {
+ DbgPrint("ISR %x\n", LocalIsrValue);
+ }
+ }
+#endif
+
+ //
+ // Check for exhausted receive descriptors.
+ //
+
+ if ( LocalIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) {
+
+ Adapter->ReceiveDescriptorsExhausted = TRUE;
+
+ LocalIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS;
+ }
+
+ //
+ // Check for exhausted receive buffers.
+ //
+
+ if ( LocalIsrValue & SONIC_INT_RECEIVE_BUFFERS ) {
+
+ Adapter->ReceiveBuffersExhausted = TRUE;
+
+ LocalIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS;
+ }
+
+ //
+ // It's our interrupt. Clear only those bits that we got
+ // in this read of ISR.
+ //
+
+ *InterruptRecognized = TRUE;
+
+ SONIC_WRITE_PORT(
+ Adapter,
+ SONIC_INTERRUPT_STATUS,
+ (USHORT)(LocalIsrValue)
+ );
+
+ //
+ // If we got a LOAD_CAM_DONE interrupt, it may be
+ // because our first initialization is complete.
+ // We check this here because on some systems the
+ // DeferredProcessing call might not interrupt
+ // the initialization process.
+ //
+
+ if (LocalIsrValue & SONIC_INT_LOAD_CAM_DONE) {
+
+ if (Adapter->FirstInitialization) {
+
+ Adapter->FirstInitialization = FALSE;
+
+#if DBG
+ {
+ USHORT PortValue;
+
+ SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &PortValue);
+ if (SonicDbg) {
+ DbgPrint("SONIC Initialized: Revision %d\n", PortValue);
+ }
+ }
+#endif
+
+ }
+ }
+
+ //
+ // No deferred processing is needed.
+ //
+ *QueueDpc = FALSE;
+
+ return;
+
+ } else {
+
+ *InterruptRecognized = FALSE;
+ *QueueDpc = FALSE;
+ return;
+
+ }
+
+}
+
+VOID
+SonicHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This DPR routine is queued by the wrapper after every interrupt
+ and also by other routines within the driver that notice that
+ some deferred processing needs to be done. It's main
+ job is to call the interrupt processing code.
+
+Arguments:
+
+ MiniportAdapterContext - Really a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // A pointer to the adapter object.
+ //
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext;
+
+ //
+ // Holds a value of the Interrupt Status register.
+ //
+ USHORT Isr;
+ USHORT ThisIsrValue;
+
+ //
+ // TRUE if the main loop did something.
+ //
+ BOOLEAN DidSomething = TRUE;
+
+ //
+ // TRUE if ReceiveComplete needs to be indicated.
+ //
+ BOOLEAN IndicateReceiveComplete = FALSE;
+
+ //
+ // Grab any simulated interrupts
+ //
+ Isr = Adapter->SimulatedIsr;
+ Adapter->SimulatedIsr = 0;
+
+ //
+ // Loop until there are no more processing sources.
+ //
+
+#if DBG
+ if (SonicDbg) {
+
+ DbgPrint("In Dpr\n");
+ }
+#endif
+
+ //
+ // If the hardware has failed, do nothing until the reset completes
+ //
+ if (Adapter->HardwareFailure) {
+
+ return;
+
+ }
+
+ while (DidSomething) {
+
+ //
+ // Set this FALSE now, so if nothing happens we
+ // will exit.
+ //
+
+ DidSomething = FALSE;
+
+ //
+ // Read in all outstanding interrupt reasons.
+ //
+
+ SONIC_READ_PORT(Adapter, SONIC_INTERRUPT_STATUS, &ThisIsrValue);
+
+ //
+ // Check for exhausted receive descriptors.
+ //
+
+ if ( ThisIsrValue & SONIC_INT_RECEIVE_DESCRIPTORS ) {
+
+ Adapter->ReceiveDescriptorsExhausted = TRUE;
+
+ ThisIsrValue &= ~SONIC_INT_RECEIVE_DESCRIPTORS;
+ }
+
+ //
+ // Check for exhausted receive buffers.
+ //
+
+ if ( ThisIsrValue & SONIC_INT_RECEIVE_BUFFERS ) {
+
+ Adapter->ReceiveBuffersExhausted = TRUE;
+
+ ThisIsrValue &= ~SONIC_INT_RECEIVE_BUFFERS;
+ }
+
+ //
+ // Acknowledge these interrupts
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, ThisIsrValue);
+
+ //
+ // Save these bits.
+ //
+ Isr |= ThisIsrValue;
+
+ //
+ // Check for receive interrupts.
+ //
+
+ if (Isr & SONIC_INT_PACKET_RECEIVED) {
+
+ DidSomething = TRUE;
+
+ } else {
+
+ goto DoneProcessingReceives;
+
+ }
+
+ //
+ // After we process any
+ // other interrupt source we always come back to the top
+ // of the loop to check if any more receive packets have
+ // come in. This is to lessen the probability that we
+ // drop a receive.
+ //
+ // ProcessReceiveInterrupts may exit early if it has
+ // processed too many receives in a row. In this case
+ // it returns FALSE, we don't clear the PACKET_RECEIVED
+ // bit, and we will loop through here again.
+ //
+
+ if (ProcessReceiveInterrupts(Adapter)) {
+ Isr &= ~SONIC_INT_PACKET_RECEIVED;
+ }
+
+ //
+ // If the hardware failed, then exit
+ //
+ if (Adapter->HardwareFailure) {
+ return;
+ }
+
+ IndicateReceiveComplete = TRUE;
+
+ //
+ // We set ProcessingReceiveInterrupt to FALSE here so
+ // that we can issue new receive indications while
+ // the rest of the loop is proceeding.
+ //
+
+DoneProcessingReceives:;
+
+ //
+ // Check the interrupt source and other reasons
+ // for processing. If there are no reasons to
+ // process then exit this loop.
+ //
+
+ if ((Isr & (SONIC_INT_LOAD_CAM_DONE |
+ SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR |
+ SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER))) {
+
+ DidSomething = TRUE;
+
+ } else {
+
+ goto DoneProcessingGeneral;
+
+ }
+
+ //
+ // Check for a Load CAM completing.
+ //
+ // This can happen due to a change in the CAM, due to
+ // initialization (in which case we won't save the bit
+ // and will not come through this code), or a reset
+ // (in which case ResetInProgress will be TRUE).
+ //
+
+ //
+ // Check for non-packet related happenings.
+ //
+
+ if (Isr & SONIC_INT_LOAD_CAM_DONE) {
+
+ Isr &= ~SONIC_INT_LOAD_CAM_DONE;
+
+ if (Adapter->ResetInProgress) {
+
+ //
+ // This initialization is from a reset.
+ //
+
+ Adapter->ResetInProgress = FALSE;
+
+ //
+ // Restart the chip.
+ //
+
+ SonicStartChip(Adapter);
+
+ //
+ // Complete the reset.
+ //
+
+ NdisMResetComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS,
+ TRUE
+ );
+
+ } else { // ResetInProgress FALSE
+
+ NdisMSetInformationComplete(
+ Adapter->MiniportAdapterHandle,
+ NDIS_STATUS_SUCCESS);
+
+ }
+
+ }
+
+ //
+ // Now process any remaining interrupts.
+ //
+
+ if (Isr & (SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER)) {
+
+ //
+ // If any of the counters overflowed, then we update
+ // the counter by adding one to the high sixteen bits
+ // and reading the register for the low sixteen bits.
+ //
+
+ if (Isr & SONIC_INT_CRC_TALLY_ROLLOVER) {
+
+ USHORT CrcError;
+ SONIC_READ_PORT(Adapter, SONIC_CRC_ERROR, &CrcError);
+
+ Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] =
+ (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) +
+ 0x10000 +
+ CrcError;
+
+ }
+
+ if (Isr & SONIC_INT_FAE_TALLY_ROLLOVER) {
+
+ USHORT FaError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError);
+
+ Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] =
+ (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) +
+ 0x10000 +
+ FaError;
+
+ }
+
+ if (Isr & SONIC_INT_MP_TALLY_ROLLOVER) {
+
+ USHORT MissedPacket;
+ SONIC_READ_PORT(Adapter, SONIC_MISSED_PACKET, &MissedPacket);
+
+ Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] =
+ (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) +
+ 0x10000 +
+ MissedPacket;
+
+ }
+
+ Isr &= ~(SONIC_INT_CRC_TALLY_ROLLOVER |
+ SONIC_INT_FAE_TALLY_ROLLOVER |
+ SONIC_INT_MP_TALLY_ROLLOVER);
+
+ }
+
+ //
+ // Process the transmit interrupts if there are any.
+ //
+
+ if (Isr & (SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR)) {
+
+ {
+
+ if (!ProcessTransmitInterrupts(Adapter)) {
+
+ //
+ // Process interrupts returns false if it
+ // finds no more work to do. If this so we
+ // turn off the transmitter interrupt source.
+ //
+
+ Isr &= ~ (SONIC_INT_PROG_INTERRUPT |
+ SONIC_INT_PACKET_TRANSMITTED |
+ SONIC_INT_TRANSMIT_ERROR);
+
+ }
+
+ }
+
+ }
+
+
+DoneProcessingGeneral:;
+
+ }
+
+ if (IndicateReceiveComplete) {
+
+ //
+ // We have indicated at least one packet, we now
+ // need to signal that the receives are complete.
+ //
+
+ NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+
+ }
+
+}
+
+#define SONIC_RECEIVE_LIMIT 10
+
+
+STATIC
+BOOLEAN
+ProcessReceiveInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished receiving.
+
+Arguments:
+
+ Adapter - The adapter to indicate to.
+
+Return Value:
+
+ FALSE if we exit because we have indicated SONIC_RECEIVE_LIMIT
+ packets, TRUE if there are no more packets.
+
+--*/
+
+{
+
+ //
+ // We don't get here unless there was a receive. Loop through
+ // the receive descriptors starting at the last known descriptor
+ // owned by the hardware that begins a packet.
+ //
+ // Examine each receive ring descriptor for errors.
+ //
+ // We keep an array whose elements are indexed by the ring
+ // index of the receive descriptors. The arrays elements are
+ // the virtual addresses of the buffers pointed to by
+ // each ring descriptor.
+ //
+ // When we have the entire packet (and error processing doesn't
+ // prevent us from indicating it), we give the routine that
+ // processes the packet through the filter, the buffers virtual
+ // address (which is always the lookahead size) and as the
+ // MAC context the index to the first and last ring descriptors
+ // comprising the packet.
+ //
+
+
+ //
+ // Pointer to the receive descriptor being examined.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR CurrentDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->CurrentReceiveDescriptorIndex];
+
+ //
+ // Index of the RBA that the next packet should
+ // come out of.
+ //
+ UINT CurrentRbaIndex = Adapter->CurrentReceiveBufferIndex;
+
+ //
+ // Virtual address of the start of that RBA.
+ //
+ PVOID CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex];
+
+ //
+ // Physical address of the start of that RBA.
+ //
+ SONIC_PHYSICAL_ADDRESS CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]);
+
+ //
+ // The size of the packet.
+ //
+ UINT PacketSize;
+
+ //
+ // The amount of data received in the RBA (will be PacketSize +
+ // 4 for the CRC).
+
+ USHORT ByteCount;
+
+ //
+ // The amount of lookahead data to indicate.
+ //
+ UINT LookAheadSize;
+
+ //
+ // The offset of the start of the packet in its receive buffer.
+ //
+ UINT PacketOffsetInRba;
+
+ //
+ // The Physical address of the packet.
+ //
+ SONIC_PHYSICAL_ADDRESS PacketPhysical;
+
+ //
+ // A pointer to the link field at the end of the receive
+ // descriptor before the one we are processing.
+ //
+ PSONIC_PHYSICAL_ADDRESS PrevLinkFieldAddr;
+
+ //
+ // The virtual address of the packet.
+ //
+ PVOID PacketVa;
+
+ //
+ // The status of the packet.
+ //
+ USHORT ReceiveStatus;
+
+ //
+ // Is the descriptor in use by the sonic.
+ //
+ USHORT InUse;
+
+ //
+ // Used tempoerarily to determine PacketPhysical.
+ //
+ USHORT PacketAddress;
+
+ //
+ // How many packets we have indicated this time.
+ //
+ UINT PacketsIndicated = 0;
+
+ //
+ // Used with update shared memory.
+ //
+
+ NDIS_PHYSICAL_ADDRESS TempAddress;
+
+#if DBG
+ //
+ // For debugging, save the previous receive descriptor.
+ //
+ static SONIC_RECEIVE_DESCRIPTOR PreviousDescriptor;
+#endif
+
+
+ do {
+
+ //
+ // Ensure that the system memory copy of the
+ // receive descriptor is up-to-date.
+ //
+
+ NdisMUpdateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ sizeof(SONIC_RECEIVE_DESCRIPTOR) *
+ Adapter->NumberOfReceiveDescriptors,
+ Adapter->ReceiveDescriptorArea,
+ Adapter->ReceiveDescriptorAreaPhysical
+ );
+
+
+ //
+ // Check to see whether we own the packet. If
+ // we don't then simply return to the caller.
+ //
+
+ NdisReadRegisterUshort(&CurrentDescriptor->InUse, &InUse);
+
+ if (InUse != SONIC_OWNED_BY_SYSTEM) {
+
+ return TRUE;
+ }
+
+ //
+ // Figure out the virtual address of the packet.
+ //
+
+ NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->LowPacketAddress,
+ (PUSHORT)&PacketAddress);
+ PacketPhysical = PacketAddress;
+ NdisReadRegisterUshort((PUSHORT)&CurrentDescriptor->HighPacketAddress,
+ (PUSHORT)&PacketAddress);
+ PacketPhysical += PacketAddress << 16;
+
+ if ((PacketPhysical < CurrentRbaPhysical) ||
+ (PacketPhysical > (CurrentRbaPhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS)) ) {
+
+ //
+ // Something is wrong, the packet is not in the
+ // receive buffer that we expect it in.
+ //
+
+ SONIC_PHYSICAL_ADDRESS ResourcePhysical;
+ PSONIC_RECEIVE_RESOURCE CurrentReceiveResource;
+ UINT i;
+
+ if (Adapter->WrongRbaErrorLogCount++ < 5) {
+
+ //
+ // Log an error the first five times this happens.
+ //
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 6,
+ processReceiveInterrupts,
+ SONIC_ERRMSG_WRONG_RBA,
+ (ULONG)CurrentRbaPhysical,
+ (ULONG)PacketPhysical,
+ (ULONG)CurrentDescriptor,
+ (ULONG)Adapter->ReceiveDescriptorArea
+ );
+
+#if DBG
+ DbgPrint("SONIC: RBA at %lx [%lx], Packet at %lx\n", CurrentRbaPhysical, CurrentRbaVa, PacketPhysical);
+
+ DbgPrint("descriptor %lx, start %lx, prev %lx\n",
+ (ULONG)CurrentDescriptor,
+ (ULONG)Adapter->ReceiveDescriptorArea,
+ &PreviousDescriptor);
+#endif
+ }
+
+ //
+ // Attempt to recover by advancing the relevant pointers
+ // to where the SONIC thinks the packet is. First we need
+ // to find the receive buffer that matches the indicated
+ // physical address.
+ //
+
+ for (
+ i = 0, CurrentReceiveResource = Adapter->ReceiveResourceArea;
+ i < Adapter->NumberOfReceiveBuffers;
+ i++,CurrentReceiveResource++
+ ) {
+
+ ResourcePhysical = SONIC_GET_RECEIVE_RESOURCE_ADDRESS(CurrentReceiveResource);
+ if ((PacketPhysical >= ResourcePhysical) &&
+ (PacketPhysical <
+ (ResourcePhysical + SONIC_SIZE_OF_RECEIVE_BUFFERS))) {
+
+ //
+ // We found the receive resource.
+ //
+ break;
+
+ }
+
+ }
+
+ if (i == Adapter->NumberOfReceiveBuffers) {
+
+ //
+ // Quit now, there is a failure by the chip, and we
+ // cannot find the receive.
+ //
+
+ Adapter->HardwareFailure = TRUE;
+
+ return FALSE;
+ }
+
+ //
+ // Update our pointers.
+ //
+
+ Adapter->CurrentReceiveBufferIndex = i;
+
+ CurrentRbaIndex = i;
+
+ CurrentRbaVa = Adapter->ReceiveBufferArea[i];
+
+ CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[i]);
+
+ //
+ // Flush the receive buffer.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[i],
+ FALSE
+ );
+
+ //
+ // Ensure that we release buffers before this one
+ // back to the sonic.
+ //
+
+ WRITE_RWP_AND_ACK(
+ Adapter,
+ (USHORT)(CurrentRbaPhysical & 0xffff)
+ );
+
+ }
+
+
+ PacketOffsetInRba = PacketPhysical - CurrentRbaPhysical;
+
+
+ //
+ // Check that the packet was received correctly...note that
+ // we always compute PacketOffsetInRba and ByteCount,
+ // which are needed to skip the packet even if we do not
+ // indicate it.
+ //
+
+ NdisReadRegisterUshort(&CurrentDescriptor->ReceiveStatus, &ReceiveStatus);
+
+ NdisReadRegisterUshort(&CurrentDescriptor->ByteCount, &ByteCount);
+
+ if (!(ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK)) {
+
+#if DBG
+ if (SonicDbg) {
+
+ DbgPrint("SONIC: Skipping %lx\n", ReceiveStatus);
+ }
+#endif
+
+ goto SkipIndication;
+
+ }
+
+ //
+ // Prepare to indicate the packet.
+ //
+
+ PacketSize = ByteCount - 4;
+
+ if ( PacketSize > 1514 ) {
+
+#if DBG
+ DbgPrint("SONIC: Skipping packet, length %d\n", PacketSize);
+#endif
+
+ goto SkipIndication;
+ }
+
+
+ if (PacketSize < SONIC_INDICATE_MAXIMUM) {
+
+ LookAheadSize = PacketSize;
+
+ } else {
+
+ LookAheadSize = SONIC_INDICATE_MAXIMUM;
+
+ }
+
+ PacketVa = (PUCHAR) CurrentRbaVa + PacketOffsetInRba;
+
+ //
+ // Ensure that the system memory version of this RBA is up-to-date.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[CurrentRbaIndex],
+ FALSE
+ );
+
+ NdisSetPhysicalAddressLow(
+ TempAddress,
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex])
+ );
+
+ NdisSetPhysicalAddressHigh(TempAddress, 0);
+
+ NdisMUpdateSharedMemory(
+ Adapter->MiniportAdapterHandle,
+ SONIC_SIZE_OF_RECEIVE_BUFFERS,
+ Adapter->ReceiveBufferArea[CurrentRbaIndex],
+ TempAddress
+ );
+
+ //
+ // Indicate the packet to the protocol.
+ //
+
+ if ( PacketSize < 14 ) {
+
+ //
+ // Must have at least the destination address
+ //
+
+ if (PacketSize >= ETH_LENGTH_OF_ADDRESS) {
+
+ //
+ // Runt packet
+ //
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context
+ PacketVa, // header buffer
+ PacketSize, // header buffer size
+ NULL, // lookahead buffer
+ 0, // lookahead buffer size
+ 0 // packet size
+ );
+
+ }
+
+ } else {
+
+ NdisMEthIndicateReceive(
+ Adapter->MiniportAdapterHandle,
+ (NDIS_HANDLE)((PUCHAR)PacketVa + 14), // context
+ PacketVa, // header buffer
+ 14, // header buffer size
+ (PUCHAR)PacketVa + 14, // lookahead buffer
+ LookAheadSize - 14, // lookahead buffer size
+ PacketSize - 14 // packet size
+ );
+
+ }
+
+SkipIndication:;
+
+#if DBG
+ SONIC_MOVE_MEMORY (&PreviousDescriptor, CurrentDescriptor, sizeof(SONIC_RECEIVE_DESCRIPTOR));
+#endif
+
+ //
+ // Give the packet back to the hardware.
+ //
+
+ NdisWriteRegisterUlong(&CurrentDescriptor->InUse, SONIC_OWNED_BY_SONIC);
+
+ //
+ // And re-set the EOL fields correctly.
+ //
+
+ SONIC_SET_END_OF_LIST(
+ &(CurrentDescriptor->Link)
+ );
+
+ if (CurrentDescriptor == Adapter->ReceiveDescriptorArea) {
+
+ //
+ // we are at the first one
+ //
+
+ PrevLinkFieldAddr = &(Adapter->LastReceiveDescriptor->Link);
+
+ } else {
+
+ PrevLinkFieldAddr = &((CurrentDescriptor-1)->Link);
+
+ }
+
+ REMOVE_EOL_AND_ACK(
+ Adapter,
+ PrevLinkFieldAddr
+ );
+
+ //
+ // Now figure out if the RBA is done with.
+ //
+
+ if (ReceiveStatus & SONIC_RCR_LAST_PACKET_IN_RBA) {
+
+ //
+ // Advance which RBA we are looking at.
+ //
+
+ ++CurrentRbaIndex;
+
+ if (CurrentRbaIndex == Adapter->NumberOfReceiveBuffers) {
+
+ CurrentRbaIndex = 0;
+
+ }
+
+ Adapter->CurrentReceiveBufferIndex = CurrentRbaIndex;
+
+ CurrentRbaVa = Adapter->ReceiveBufferArea[CurrentRbaIndex];
+
+ CurrentRbaPhysical =
+ SONIC_GET_RECEIVE_RESOURCE_ADDRESS(&Adapter->ReceiveResourceArea[CurrentRbaIndex]);
+
+ WRITE_RWP_AND_ACK(
+ Adapter,
+ (USHORT)(CurrentRbaPhysical & 0xffff)
+ );
+
+ }
+
+ //
+ // Update statistics now based on the receive status.
+ //
+
+ if (ReceiveStatus & SONIC_RCR_PACKET_RECEIVED_OK) {
+
+ ++Adapter->GeneralMandatory[GM_RECEIVE_GOOD];
+
+ if (ReceiveStatus & SONIC_RCR_BROADCAST_RECEIVED) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_BROADCAST_RECEIVES],
+ PacketSize);
+
+ } else if (ReceiveStatus & SONIC_RCR_MULTICAST_RECEIVED) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_MULTICAST_RECEIVES],
+ PacketSize);
+
+ } else {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_RECEIVES];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_DIRECTED_RECEIVES],
+ PacketSize);
+
+ }
+
+ } else {
+
+ ++Adapter->GeneralMandatory[GM_RECEIVE_BAD];
+
+ if (ReceiveStatus & SONIC_RCR_CRC_ERROR) {
+ ++Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START];
+ } else if (ReceiveStatus & SONIC_RCR_FRAME_ALIGNMENT) {
+ ++Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT];
+ }
+
+ }
+
+ //
+ // Advance our pointers to the next packet.
+
+ if (CurrentDescriptor == Adapter->LastReceiveDescriptor) {
+
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+
+ } else {
+
+ ++(Adapter->CurrentReceiveDescriptorIndex);
+
+ }
+
+ CurrentDescriptor = &Adapter->ReceiveDescriptorArea[
+ Adapter->CurrentReceiveDescriptorIndex];
+
+ ++PacketsIndicated;
+
+ } while (PacketsIndicated < SONIC_RECEIVE_LIMIT);
+
+ //
+ // Indicate that we returned because we indicated SONIC_RECEIVE_
+ // LIMIT packets, not because we ran out of packets to indicate.
+ //
+
+ return FALSE;
+
+}
+
+STATIC
+BOOLEAN
+ProcessTransmitInterrupts(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ Process the packets that have finished transmitting.
+
+Arguments:
+
+ Adapter - The adapter that was sent from.
+
+Return Value:
+
+ This function will return TRUE if it finished up the
+ send on a packet. It will return FALSE if for some
+ reason there was no packet to process.
+
+--*/
+
+{
+ //
+ // Index into the ring to packet structure. This index points
+ // to the first ring entry for the first buffer used for transmitting
+ // the packet.
+ //
+ UINT DescriptorIndex;
+
+ //
+ // The transmit desctiptor for the packet at Transmitting Descriptor
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+
+ //
+ // Temporarily holds the transmit descriptor after TransmitDescriptor
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR NextTransmitDescriptor;
+
+ //
+ // Pointer to the packet that started this transmission.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Points to the reserved part of the OwningPacket.
+ //
+ PSONIC_PACKET_RESERVED Reserved;
+
+ //
+ // Used to hold the ring to packet mapping information so that
+ // we can release the ring entries as quickly as possible.
+ //
+ SONIC_DESCRIPTOR_TO_PACKET SavedDescriptorMapping;
+
+ //
+ // The status of the transmit.
+ //
+ USHORT TransmitStatus;
+
+ //
+ // Get hold of the first transmitted packet.
+ //
+
+ //
+ // First we check that this is a packet that was transmitted
+ // but not already processed. Recall that this routine
+ // will be called repeatedly until this tests false, Or we
+ // hit a packet that we don't completely own.
+ //
+
+ if (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor) {
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ //
+ // We put the mapping into a local variable so that we
+ // can return the mapping as soon as possible.
+ //
+
+ SavedDescriptorMapping = Adapter->DescriptorToPacket[DescriptorIndex];
+
+ //
+ // Get a pointer to the transmit descriptor for this packet.
+ //
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+
+ //
+ // Get a pointer to the owning packet and the reserved part of
+ // the packet.
+ //
+
+ OwningPacket = SavedDescriptorMapping.OwningPacket;
+
+ Reserved = PSONIC_RESERVED_FROM_PACKET(OwningPacket);
+
+
+ //
+ // Check that status bits were written into the transmit
+ // descriptor.
+ //
+
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ //
+ // The transmit has not completed.
+ //
+
+ return FALSE;
+
+ } else {
+
+ //
+ // Holds whether the packet successfully transmitted or not.
+ //
+ BOOLEAN Successful = TRUE;
+
+ //
+ // Length of the packet
+ //
+ UINT PacketLength;
+
+ //
+ // Points to data in NDIS_BUFFER
+ //
+ PUCHAR BufferVa;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ if (SavedDescriptorMapping.UsedSonicBuffer) {
+
+ //
+ // This packet used adapter buffers. We can
+ // now return these buffers to the adapter.
+ //
+
+ //
+ // The adapter buffer descriptor that was allocated to this packet.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor = Adapter->SonicBuffers +
+ SavedDescriptorMapping.SonicBuffersIndex;
+
+ //
+ // Index of the listhead that heads the list that the adapter
+ // buffer descriptor belongs too.
+ //
+ INT ListHeadIndex = BufferDescriptor->Next;
+
+
+ //
+ // Put the adapter buffer back on the free list.
+ //
+
+ BufferDescriptor->Next = Adapter->SonicBufferListHeads[ListHeadIndex];
+ Adapter->SonicBufferListHeads[ListHeadIndex] = SavedDescriptorMapping.SonicBuffersIndex;
+
+ } else {
+
+ //
+ // Which map register we use for this buffer.
+ //
+ UINT CurMapRegister;
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ while (CurrentBuffer) {
+
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+
+ //
+ // Now release the transmit descriptor, since we have
+ // gotten all the information we need from it.
+ //
+
+ if (TransmitDescriptor == Adapter->LastTransmitDescriptor) {
+
+ NextTransmitDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ NextTransmitDescriptor = Adapter->TransmittingDescriptor + 1;
+
+ }
+
+ if (TransmitStatus &
+ (SONIC_TCR_EXCESSIVE_DEFERRAL |
+ SONIC_TCR_EXCESSIVE_COLLISIONS |
+ SONIC_TCR_FIFO_UNDERRUN |
+ SONIC_TCR_BYTE_COUNT_MISMATCH)) {
+
+ //
+ // If the packet completed with an abort state, then we
+ // need to restart the transmitter unless we are the
+ // last transmit queued up. We set CTDA to point after
+ // this descriptor in any case.
+ //
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint ("SONIC: Advancing CTDA after abort\n");
+ }
+#endif
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ ((PUCHAR)NextTransmitDescriptor -
+ (PUCHAR)Adapter->TransmitDescriptorArea))
+ );
+
+ if (Adapter->FirstUncommittedDescriptor != NextTransmitDescriptor) {
+#if DBG
+ if (SonicDbg) {
+ DbgPrint ("SONIC: Restarting transmit after abort\n");
+ }
+#endif
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS);
+ }
+
+ }
+
+ Adapter->TransmittingDescriptor = NextTransmitDescriptor;
+ Adapter->NumberOfAvailableDescriptors++;
+
+ //
+ // Check if the packet completed OK, and update statistics.
+ //
+
+ if (!(TransmitStatus & SONIC_TCR_PACKET_TRANSMITTED_OK)) {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: Transmit failed: %lx\n", TransmitStatus);
+ }
+#endif
+ Successful = FALSE;
+
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_BAD];
+
+ if (TransmitStatus & SONIC_TCR_EXCESSIVE_COLLISIONS) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_MAX_COLLISIONS];
+ }
+
+ if (TransmitStatus & SONIC_TCR_FIFO_UNDERRUN) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_UNDERRUN];
+ }
+
+ } else {
+
+ INT Collisions = (TransmitStatus & SONIC_TCR_COLLISIONS_MASK) >> SONIC_TCR_COLLISIONS_SHIFT;
+
+ UINT Tmp;
+
+ Successful = TRUE;
+
+ ++Adapter->GeneralMandatory[GM_TRANSMIT_GOOD];
+
+ if (Collisions > 0) {
+ if (Collisions == 1) {
+ ++Adapter->MediaMandatory[MM_TRANSMIT_ONE_COLLISION];
+ } else {
+ ++Adapter->MediaMandatory[MM_TRANSMIT_MORE_COLLISIONS];
+ }
+ }
+
+ if (TransmitStatus &
+ (SONIC_TCR_DEFERRED_TRANSMISSION |
+ SONIC_TCR_NO_CARRIER_SENSE |
+ SONIC_TCR_CARRIER_LOST |
+ SONIC_TCR_OUT_OF_WINDOW)) {
+
+ if (TransmitStatus & SONIC_TCR_DEFERRED_TRANSMISSION) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_DEFERRED];
+ }
+ if (TransmitStatus & SONIC_TCR_NO_CARRIER_SENSE) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_HEARTBEAT_FAILURE];
+ }
+ if (TransmitStatus & SONIC_TCR_CARRIER_LOST) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_TIMES_CRS_LOST];
+ }
+ if (TransmitStatus & SONIC_TCR_OUT_OF_WINDOW) {
+ ++Adapter->MediaOptional[MO_TRANSMIT_LATE_COLLISIONS];
+ }
+ }
+
+ NdisQueryPacket(
+ OwningPacket,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ &PacketLength
+ );
+
+ NdisQueryBuffer(
+ CurrentBuffer,
+ (PVOID *)&BufferVa,
+ &Tmp
+ );
+
+ if (BufferVa[0] == 0xFF) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_BROADCAST_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_BROADCAST_TRANSMITS],
+ PacketLength);
+
+ } else if (BufferVa[0] & 0x01) {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_MULTICAST_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_MULTICAST_TRANSMITS],
+ PacketLength);
+
+ } else {
+
+ ++Adapter->GeneralOptionalFrameCount[GO_DIRECTED_TRANSMITS];
+ SonicAddUlongToLargeInteger(
+ &Adapter->GeneralOptionalByteCount[GO_DIRECTED_TRANSMITS],
+ PacketLength);
+
+ }
+
+ }
+
+ //
+ // Remove packet from queue.
+ //
+
+ if (Adapter->LastFinishTransmit == OwningPacket) {
+
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+
+ } else {
+
+ Adapter->FirstFinishTransmit = Reserved->Next;
+ }
+
+#ifdef CHECK_DUP_SENDS
+ {
+ VOID SonicRemovePacketFromList(PSONIC_ADAPTER, PNDIS_PACKET);
+ SonicRemovePacketFromList(Adapter, OwningPacket);
+ }
+#endif
+
+ NdisMSendComplete(
+ Adapter->MiniportAdapterHandle,
+ OwningPacket,
+ ((Successful)?(NDIS_STATUS_SUCCESS):(NDIS_STATUS_FAILURE))
+ );
+
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ return TRUE;
+ }
+
+}
+
+BOOLEAN
+SonicCheckForHang(
+ IN PVOID MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks on the transmit descriptor ring. This is
+ to solve problems where no status is written into the currently
+ transmitting transmit descriptor, which hangs our transmit
+ completion processing. If we detect this state, we simulate
+ a transmit interrupt.
+
+Arguments:
+
+ MiniportAdapterContext - Really a pointer to the adapter.
+
+Return Value:
+
+ FALSE - This routine actually does a wake up, rather than having
+ the wrapper do it.
+
+--*/
+{
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)MiniportAdapterContext;
+ UINT DescriptorIndex;
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor;
+ USHORT TransmitStatus;
+
+ //
+ // If hardware failed, then return now
+ //
+ if (Adapter->HardwareFailure) {
+ return(TRUE);
+ }
+
+ if (Adapter->WakeUpTimeout) {
+
+ //
+ // We had a pending send the last time we ran,
+ // and it has not been completed...we need to fake
+ // its completion.
+ //
+
+ ASSERT (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor);
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ NdisWriteRegisterUshort ((PUSHORT)&TransmitDescriptor->TransmitStatus,
+ SONIC_TCR_PACKET_TRANSMITTED_OK);
+
+#if DBG
+ DbgPrint ("SONIC: Woke up descriptor at %lx\n", TransmitDescriptor);
+#endif
+
+ }
+
+ Adapter->SimulatedIsr |= SONIC_INT_PACKET_TRANSMITTED;
+
+ Adapter->WakeUpTimeout = FALSE;
+
+ if (Adapter->WakeUpErrorCount < 10) {
+
+ Adapter->WakeUpErrorCount++;
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_HARDWARE_FAILURE,
+ 1,
+ (ULONG)0xFFFFFFFF
+ );
+ }
+
+ } else if (Adapter->TransmittingDescriptor !=
+ Adapter->FirstUncommittedDescriptor) {
+
+ DescriptorIndex =
+ Adapter->TransmittingDescriptor - Adapter->TransmitDescriptorArea;
+
+ TransmitDescriptor = Adapter->TransmitDescriptorArea + DescriptorIndex;
+ NdisReadRegisterUshort((PUSHORT)&TransmitDescriptor->TransmitStatus, &TransmitStatus);
+
+ if (!(TransmitStatus & SONIC_TCR_STATUS_MASK)) {
+
+ Adapter->WakeUpTimeout = TRUE;
+
+ }
+
+ }
+
+ return(FALSE);
+
+}
diff --git a/private/ntos/ndis/sonic/makefile b/private/ntos/ndis/sonic/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/ndis/sonic/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/ndis/sonic/mips/sonicdet.h b/private/ntos/ndis/sonic/mips/sonicdet.h
new file mode 100644
index 000000000..9325bec47
--- /dev/null
+++ b/private/ntos/ndis/sonic/mips/sonicdet.h
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicdet.h
+
+Abstract:
+
+ This file has processor-specific definitions.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 5-Nov-1991
+
+Environment:
+
+ This driver is expected to work at the equivalent of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+
+//
+// Handy macros to read out of sonic ports.
+//
+// Because the use of PortShift makes the code more complicated,
+// we make some assumptions about when it is needed. On MIPS, we
+// only support the internal version unless MIPS_EISA_SONIC
+// is defined, in which case we support both.
+//
+// We define two constants, SONIC_EISA and SONIC_INTERNAL, if
+// that particular adapter type is supported by this driver.
+// This is to prevent unneeded code from being compiled in.
+//
+
+
+#ifdef MIPS_EISA_SONIC
+
+
+//
+// mips, with support for the EISA card; we have to use PortShift.
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port << (_Adapter)->PortShift), (PUSHORT)(_Value))
+
+#define SONIC_EISA
+#define SONIC_INTERNAL
+
+
+#else // MIPS_EISA_SONIC
+
+
+//
+// mips, internal support only, the registers are always 32 bits
+//
+
+#define SONIC_WRITE_PORT(_Adapter, _Port, _Value) \
+ NdisRawWritePortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (USHORT)(_Value))
+
+#define SONIC_READ_PORT(_Adapter, _Port, _Value) \
+ NdisRawReadPortUshort((_Adapter)->SonicPortAddress + (_Port * 4), (PUSHORT)(_Value))
+
+#undef SONIC_EISA
+#define SONIC_INTERNAL
+
+
+#endif // MIPS_EISA_SONIC
+
+
+//
+// The default adapter type for mips is Internal
+//
+
+#define SONIC_ADAPTER_TYPE_DEFAULT SONIC_ADAPTER_TYPE_INTERNAL
diff --git a/private/ntos/ndis/sonic/request.c b/private/ntos/ndis/sonic/request.c
new file mode 100644
index 000000000..d17d67791
--- /dev/null
+++ b/private/ntos/ndis/sonic/request.c
@@ -0,0 +1,890 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ request.c
+
+Abstract:
+
+ This is the cose to handle requests for the National Semiconductor
+ SONIC Ethernet controller. This driver conforms to the NDIS 3.0
+ miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This macro determines if the directed address
+// filtering in the CAM is actually necessary given
+// the current filter.
+//
+
+#define CAM_DIRECTED_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_DIRECTED) && \
+ (!((_Filter) & NDIS_PACKET_TYPE_PROMISCUOUS))) ? 1 : 0)
+
+
+//
+// This macro determines if the multicast filtering in
+// the CAM are actually necessary given the current filter.
+//
+
+#define CAM_MULTICAST_SIGNIFICANT(_Filter) \
+ ((((_Filter) & NDIS_PACKET_TYPE_MULTICAST) && \
+ (!((_Filter) & (NDIS_PACKET_TYPE_ALL_MULTICAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS)))) ? 1 : 0)
+
+
+STATIC
+NDIS_STATUS
+ChangeClassDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT NewFilterClasses
+ );
+
+STATIC
+NDIS_STATUS
+ChangeAddressDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS]
+ );
+
+
+
+
+extern
+NDIS_STATUS
+SonicQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ SonicQueryInformation handles a query operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Oid - The OID of the query.
+
+ InformationBuffer - Holds the result of the query.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesWritten - If the call is successful, returns the number
+ of bytes written to InformationBuffer.
+
+ BytesNeeded - If there is not enough room in InformationBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+ INT i;
+ INT SupportedOids;
+ NDIS_OID MaskOid;
+ PVOID SourceBuffer;
+ ULONG SourceBufferLength;
+ ULONG GenericUlong;
+ USHORT GenericUshort;
+ UCHAR VendorId[4];
+#ifdef SONIC_EISA
+ static const UCHAR EisaDescriptor[] = "SONIC EISA Bus Master Ethernet Adapter (DP83932EB-EISA)";
+#endif
+#ifdef SONIC_INTERNAL
+ static const UCHAR InternalDescriptor[] = "MIPS R4000 on-board network controller";
+#endif
+
+ static const NDIS_OID SonicSupportedOids[] = {
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_LOOKAHEAD,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MAC_OPTIONS,
+ OID_GEN_PROTOCOL_OPTIONS,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+ OID_GEN_DIRECTED_BYTES_XMIT,
+ OID_GEN_DIRECTED_FRAMES_XMIT,
+ OID_GEN_MULTICAST_BYTES_XMIT,
+ OID_GEN_MULTICAST_FRAMES_XMIT,
+ OID_GEN_BROADCAST_BYTES_XMIT,
+ OID_GEN_BROADCAST_FRAMES_XMIT,
+ OID_GEN_DIRECTED_BYTES_RCV,
+ OID_GEN_DIRECTED_FRAMES_RCV,
+ OID_GEN_MULTICAST_BYTES_RCV,
+ OID_GEN_MULTICAST_FRAMES_RCV,
+ OID_GEN_BROADCAST_BYTES_RCV,
+ OID_GEN_BROADCAST_FRAMES_RCV,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS
+ };
+
+ //
+ // Check that the OID is valid.
+ //
+
+ SupportedOids = sizeof(SonicSupportedOids)/sizeof(ULONG);
+
+ for (i=0; i<SupportedOids; i++) {
+ if (Oid == SonicSupportedOids[i]) {
+ break;
+ }
+ }
+
+ if (i == SupportedOids) {
+ *BytesWritten = 0;
+ return NDIS_STATUS_INVALID_OID;
+ }
+
+ //
+ // Initialize these once, since this is the majority
+ // of cases.
+ //
+
+ SourceBuffer = &GenericUlong;
+ SourceBufferLength = sizeof(ULONG);
+
+ switch (Oid & OID_TYPE_MASK) {
+
+ case OID_TYPE_GENERAL_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_GEN_MAC_OPTIONS:
+
+ GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
+ NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+ NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_NO_LOOPBACK
+ );
+
+ break;
+
+ case OID_GEN_SUPPORTED_LIST:
+
+ SourceBuffer = (PVOID)SonicSupportedOids;
+ SourceBufferLength = SupportedOids * sizeof(ULONG);
+ break;
+
+ case OID_GEN_HARDWARE_STATUS:
+
+ GenericUlong = NdisHardwareStatusReady;
+ break;
+
+ case OID_GEN_MEDIA_SUPPORTED:
+
+ GenericUlong = NdisMedium802_3;
+ break;
+
+ case OID_GEN_MEDIA_IN_USE:
+
+ GenericUlong = NdisMedium802_3;
+ break;
+
+ case OID_GEN_MAXIMUM_LOOKAHEAD:
+
+ GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ?
+ SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM;
+ break;
+
+ case OID_GEN_MAXIMUM_FRAME_SIZE:
+
+ GenericUlong = 1500;
+ break;
+
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+
+ GenericUlong = 1514;
+ break;
+
+ case OID_GEN_LINK_SPEED:
+
+ GenericUlong = 100000; // 10 Mbps in 100 bps units
+ break;
+
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS;
+ break;
+
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE * SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS;
+ break;
+
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+
+ GenericUlong = SONIC_LARGE_BUFFER_SIZE;
+ break;
+
+ case OID_GEN_VENDOR_ID:
+
+ SONIC_MOVE_MEMORY(VendorId, Adapter->PermanentNetworkAddress, 3);
+ VendorId[3] = 0x0;
+ SourceBuffer = VendorId;
+ SourceBufferLength = sizeof(VendorId);
+ break;
+
+ case OID_GEN_VENDOR_DESCRIPTION:
+
+ switch (Adapter->AdapterType) {
+#ifdef SONIC_EISA
+ case SONIC_ADAPTER_TYPE_EISA:
+ SourceBuffer = (PVOID)EisaDescriptor;
+ SourceBufferLength = sizeof(EisaDescriptor);
+ break;
+#endif
+#ifdef SONIC_INTERNAL
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ SourceBuffer = (PVOID)InternalDescriptor;
+ SourceBufferLength = sizeof(InternalDescriptor);
+ break;
+#endif
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ break;
+
+ case OID_GEN_DRIVER_VERSION:
+
+ GenericUshort = (SONIC_NDIS_MAJOR_VERSION << 8) + SONIC_NDIS_MINOR_VERSION;
+ SourceBuffer = &GenericUshort;
+ SourceBufferLength = sizeof(USHORT);
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ GenericUlong = Adapter->CurrentPacketFilter;
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ GenericUlong = (SONIC_INDICATE_MAXIMUM-14 < SONIC_LOOPBACK_MAXIMUM) ?
+ SONIC_INDICATE_MAXIMUM-14 : SONIC_LOOPBACK_MAXIMUM;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_GENERAL_STATISTICS:
+
+ MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < GM_ARRAY_SIZE);
+
+ if (MaskOid == GM_RECEIVE_NO_BUFFER) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT MissedPacket;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &MissedPacket);
+
+ if ((Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff) <
+ MissedPacket) {
+
+ Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] =
+ (Adapter->GeneralMandatory[GM_RECEIVE_NO_BUFFER] & 0xffff0000) +
+ MissedPacket;
+
+ }
+ }
+
+ GenericUlong = Adapter->GeneralMandatory[MaskOid];
+ break;
+
+ case OID_REQUIRED_OPTIONAL:
+
+ ASSERT (MaskOid < GO_ARRAY_SIZE);
+
+ if (MaskOid == GO_RECEIVE_CRC) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT CrcError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &CrcError);
+
+ if ((Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff) <
+ CrcError) {
+
+ Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] =
+ (Adapter->GeneralOptional[GO_RECEIVE_CRC - GO_ARRAY_START] & 0xffff0000) +
+ CrcError;
+
+ }
+ }
+
+ if ((MaskOid / 2) < GO_COUNT_ARRAY_SIZE) {
+
+ if (MaskOid & 0x01) {
+ // Frame count
+ GenericUlong = Adapter->GeneralOptionalFrameCount[MaskOid / 2];
+ } else {
+ // Byte count
+ SourceBuffer = &Adapter->GeneralOptionalByteCount[MaskOid / 2];
+ SourceBufferLength = sizeof(LARGE_INTEGER);
+ }
+
+ } else {
+
+ GenericUlong = Adapter->GeneralOptional[MaskOid - GO_ARRAY_START];
+
+ }
+
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_OPERATIONAL:
+
+ switch (Oid) {
+
+ case OID_802_3_PERMANENT_ADDRESS:
+
+ SourceBuffer = Adapter->PermanentNetworkAddress;
+ SourceBufferLength = 6;
+ break;
+
+ case OID_802_3_CURRENT_ADDRESS:
+
+ SourceBuffer = Adapter->CurrentNetworkAddress;
+ SourceBufferLength = 6;
+ break;
+
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+
+ GenericUlong = SONIC_CAM_ENTRIES - 1;
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ case OID_TYPE_802_3_STATISTICS:
+
+ MaskOid = (Oid & OID_INDEX_MASK) - 1;
+
+ switch (Oid & OID_REQUIRED_MASK) {
+
+ case OID_REQUIRED_MANDATORY:
+
+ ASSERT (MaskOid < MM_ARRAY_SIZE);
+
+ if (MaskOid == MM_RECEIVE_ERROR_ALIGNMENT) {
+
+ //
+ // This one is read off the card, update unless our
+ // counter is more (which indicates an imminent
+ // overflow interrupt, so we don't update).
+ //
+
+ USHORT FaError;
+ SONIC_READ_PORT(Adapter, SONIC_FRAME_ALIGNMENT_ERROR, &FaError);
+
+ if ((Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff) <
+ FaError) {
+
+ Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] =
+ (Adapter->MediaMandatory[MM_RECEIVE_ERROR_ALIGNMENT] & 0xffff0000) +
+ FaError;
+
+ }
+ }
+
+ GenericUlong = Adapter->MediaMandatory[MaskOid];
+ break;
+
+ case OID_REQUIRED_OPTIONAL:
+
+ ASSERT (MaskOid < MO_ARRAY_SIZE);
+ GenericUlong = Adapter->MediaOptional[MaskOid];
+ break;
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ break;
+
+ }
+
+ if (SourceBufferLength > InformationBufferLength) {
+ *BytesNeeded = SourceBufferLength;
+ return NDIS_STATUS_INVALID_LENGTH;
+ }
+
+ SONIC_MOVE_MEMORY (InformationBuffer, SourceBuffer, SourceBufferLength);
+ *BytesWritten = SourceBufferLength;
+
+ return NDIS_STATUS_SUCCESS;
+
+}
+
+
+STATIC
+NDIS_STATUS
+SonicSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+
+/*++
+
+Routine Description:
+
+ SonicQueryInformation handles a set operation for a
+ single OID.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Oid - The OID of the set.
+
+ InformationBuffer - Holds the data to be set.
+
+ InformationBufferLength - The length of InformationBuffer.
+
+ BytesRead - If the call is successful, returns the number
+ of bytes read from InformationBuffer.
+
+ BytesNeeded - If there is not enough data in InformationBuffer
+ to satisfy the OID, returns the amount of storage needed.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_PENDING
+ NDIS_STATUS_INVALID_LENGTH
+ NDIS_STATUS_INVALID_OID
+
+--*/
+
+{
+
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+ NDIS_STATUS Status;
+ ULONG PacketFilter;
+
+ //
+ // Now check for the most common OIDs
+ //
+
+ switch (Oid) {
+
+ case OID_802_3_MULTICAST_LIST:
+
+ if (InformationBufferLength % ETH_LENGTH_OF_ADDRESS != 0) {
+
+ //
+ // The data must be a multiple of the Ethernet
+ // address size.
+ //
+
+ return NDIS_STATUS_INVALID_DATA;
+
+ }
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Change Multicast List request\n");
+ }
+#endif
+
+ //
+ // Now make the change.
+ //
+
+ Status = ChangeAddressDispatch(
+ Adapter,
+ InformationBufferLength / ETH_LENGTH_OF_ADDRESS,
+ InformationBuffer
+ );
+
+ *BytesRead = InformationBufferLength;
+
+ return Status;
+
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+
+ if (InformationBufferLength != 4) {
+
+ *BytesNeeded = 4;
+ return NDIS_STATUS_INVALID_LENGTH;
+
+ }
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Change Packet Filter request\n");
+ }
+#endif
+
+ //
+ // Now call the filter package to set the packet filter.
+ //
+
+ SONIC_MOVE_MEMORY ((PVOID)&PacketFilter, InformationBuffer, sizeof(ULONG));
+
+ //
+ // Verify bits
+ //
+
+ if (PacketFilter & (NDIS_PACKET_TYPE_SOURCE_ROUTING |
+ NDIS_PACKET_TYPE_SMT |
+ NDIS_PACKET_TYPE_MAC_FRAME |
+ NDIS_PACKET_TYPE_FUNCTIONAL |
+ NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+ NDIS_PACKET_TYPE_GROUP
+ )) {
+
+ *BytesRead = 4;
+ *BytesNeeded = 0;
+
+ return NDIS_STATUS_NOT_SUPPORTED;
+
+ }
+
+ Status = ChangeClassDispatch(
+ Adapter,
+ PacketFilter
+ );
+
+ *BytesRead = 4;
+ return Status;
+
+ break;
+
+ case OID_GEN_CURRENT_LOOKAHEAD:
+
+ //
+ // No need to record requested lookahead length since we
+ // always indicate the whole packet.
+ //
+
+ *BytesRead = 4;
+ return NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+
+ return NDIS_STATUS_INVALID_OID;
+ break;
+
+ }
+
+}
+
+STATIC
+NDIS_STATUS
+ChangeClassDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT NewFilterClasses
+ )
+
+/*++
+
+Routine Description:
+
+ Modifies the Receive Control Register and Cam Enable registers,
+ then re-loads the CAM if necessary.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ NewFilterClasses - New set of filters.
+
+Return Value:
+
+ NDIS_STATUS_PENDING - if the CAM was reloaded.
+ NDIS_STATUS_SUCCESS - otherwise.
+
+--*/
+
+{
+ //
+ // The new value for the RCR.
+ //
+ USHORT NewReceiveControl = SONIC_RCR_DEFAULT_VALUE;
+
+ //
+ // First take care of the Receive Control Register.
+ //
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) {
+
+ NewReceiveControl |= SONIC_RCR_PROMISCUOUS_PHYSICAL |
+ SONIC_RCR_ACCEPT_BROADCAST |
+ SONIC_RCR_ACCEPT_ALL_MULTICAST;
+
+ } else {
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) {
+
+ NewReceiveControl |= SONIC_RCR_ACCEPT_ALL_MULTICAST;
+
+ }
+
+ if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) {
+
+ NewReceiveControl |= SONIC_RCR_ACCEPT_BROADCAST;
+
+ }
+
+ }
+
+ Adapter->ReceiveControlRegister = NewReceiveControl;
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL,
+ Adapter->ReceiveControlRegister
+ );
+
+ if (CAM_DIRECTED_SIGNIFICANT(NewFilterClasses)) {
+
+ Adapter->CamDescriptorArea->CamEnable |= 1;
+
+ } else {
+
+ Adapter->CamDescriptorArea->CamEnable &= ~1;
+
+ }
+
+ if (CAM_MULTICAST_SIGNIFICANT(NewFilterClasses)) {
+
+ Adapter->CamDescriptorArea->CamEnable |=
+ Adapter->MulticastCamEnableBits;
+
+ } else {
+
+ Adapter->CamDescriptorArea->CamEnable &= 1;
+
+ }
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+ Adapter->CurrentPacketFilter = NewFilterClasses;
+
+ return NDIS_STATUS_PENDING;
+
+}
+
+STATIC
+NDIS_STATUS
+ChangeAddressDispatch(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT AddressCount,
+ IN CHAR Addresses[][ETH_LENGTH_OF_ADDRESS]
+ )
+
+/*++
+
+Routine Description:
+
+ Modifies the Receive Control Register and Cam Enable registers,
+ then re-loads the CAM if necessary.
+
+Arguments:
+
+ Adapter - The adapter.
+
+ AddressCount - The number of addresses in Addresses
+
+ Addresses - The new multicast address list.
+
+Return Value:
+
+ NDIS_STATUS_PENDING - if the CAM was reloaded.
+ NDIS_STATUS_SUCCESS - otherwise.
+
+--*/
+
+{
+
+ ULONG EnableBit;
+ NDIS_STATUS Status;
+ UINT i;
+
+ //
+ // The first entry in the CAM is for our address.
+ //
+
+ Adapter->MulticastCamEnableBits = 1;
+ EnableBit = 1;
+
+ //
+ // Loop through, copying the addresses into the CAM.
+ //
+
+ for (i=0; i<AddressCount; i++) {
+
+ EnableBit <<= 1;
+ Adapter->MulticastCamEnableBits |= EnableBit;
+
+ SONIC_LOAD_CAM_FRAGMENT(
+ &Adapter->CamDescriptorArea->CamFragments[i+1],
+ i+1,
+ Addresses[i]
+ );
+
+ }
+
+ Adapter->CamDescriptorAreaSize = AddressCount + 1;
+
+ //
+ // Now see if we have to worry about re-loading the
+ // CAM also.
+ //
+
+ if (CAM_MULTICAST_SIGNIFICANT(Adapter->CurrentPacketFilter)) {
+
+ Adapter->CamDescriptorArea->CamEnable = Adapter->MulticastCamEnableBits;
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Address request pended\n");
+ }
+#endif
+
+
+ Status = NDIS_STATUS_PENDING;
+
+ } else {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("Processing Address request succeeded\n");
+ }
+#endif
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ }
+
+ return Status;
+
+}
+
diff --git a/private/ntos/ndis/sonic/send.c b/private/ntos/ndis/sonic/send.c
new file mode 100644
index 000000000..7f41a8f07
--- /dev/null
+++ b/private/ntos/ndis/sonic/send.c
@@ -0,0 +1,1305 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ send.c
+
+Abstract:
+
+ This file contains the code for putting a packet through the
+ 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 those ring entries to the hardware.
+
+Author:
+
+ Adam Barr (adamba) 16-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This macro will poke the sonic hardware into noticing that
+// there is a packet available for transmit.
+//
+
+#define START_TRANSMIT(_Adapter) \
+ SONIC_WRITE_PORT(_Adapter, SONIC_COMMAND, SONIC_CR_TRANSMIT_PACKETS)
+
+
+STATIC
+VOID
+AssignPacketToDescriptor(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT DescriptorIndex
+ );
+
+STATIC
+VOID
+RelinquishPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT RingIndex
+ );
+
+STATIC
+VOID
+CalculatePacketConstraints(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+STATIC
+BOOLEAN
+ConstrainPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ );
+
+
+#ifdef CHECK_DUP_SENDS
+
+#define PACKET_LIST_SIZE 20
+
+PNDIS_PACKET SonicPacketList[PACKET_LIST_SIZE];
+UINT SonicPacketListSize = 0;
+
+VOID
+SonicAddPacketToList(
+ PSONIC_ADAPTER Adapter,
+ PNDIS_PACKET NewPacket
+ )
+{
+ INT i;
+
+ for (i=0; i<SonicPacketListSize; i++) {
+
+ if (SonicPacketList[i] == NewPacket) {
+
+ DbgPrint("SONIC: dup send of %lx\n", NewPacket);
+
+ }
+
+ }
+
+ SonicPacketList[SonicPacketListSize] = NewPacket;
+ ++SonicPacketListSize;
+
+}
+
+VOID
+SonicRemovePacketFromList(
+ PSONIC_ADAPTER Adapter,
+ PNDIS_PACKET OldPacket
+ )
+{
+ INT i;
+
+ for (i=0; i<SonicPacketListSize; i++) {
+
+ if (SonicPacketList[i] == OldPacket) {
+
+ break;
+
+ }
+
+ }
+
+ if (i == SonicPacketListSize) {
+
+ DbgPrint("SONIC: bad remove of %lx\n", OldPacket);
+
+ } else {
+
+ --SonicPacketListSize;
+ SonicPacketList[i] = SonicPacketList[SonicPacketListSize];
+
+ }
+
+}
+#endif // CHECK_DUP_SENDS
+
+
+extern
+NDIS_STATUS
+SonicSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT SendFlags
+ )
+
+/*++
+
+Routine Description:
+
+ The SonicSend request instructs a driver to transmit a packet through
+ the adapter onto the medium.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ Packet - A pointer to a descriptor for the packet that is to be
+ transmitted.
+
+ SendFlags - Optional send flags
+
+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.
+ //
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ PSONIC_PACKET_RESERVED Reserved;
+
+ //
+ // Holds whether the packet has been constrained
+ // to the hardware requirements.
+ //
+ BOOLEAN SuitableForHardware;
+
+ //
+ // If we successfully acquire some ring entries, this
+ // is the index of the first one.
+ //
+ UINT DescriptorIndex;
+
+#ifdef CHECK_DUP_SENDS
+ SonicAddPacketToList(Adapter, Packet);
+#endif
+
+
+ //
+ // 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.
+ //
+
+ Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Determine if and how much adapter space would need to be allocated
+ // to meet hardware constraints.
+ //
+
+ CalculatePacketConstraints(
+ Adapter,
+ Packet
+ );
+
+ //
+ // We look to see if there are enough ring entries.
+ // If there aren't then fail this send.
+ //
+
+ if (Adapter->NumberOfAvailableDescriptors > 1) {
+
+ DescriptorIndex = Adapter->AllocateableDescriptor - Adapter->TransmitDescriptorArea;
+
+ if (Adapter->AllocateableDescriptor == Adapter->LastTransmitDescriptor) {
+
+ Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ ++(Adapter->AllocateableDescriptor);
+
+ }
+
+ --(Adapter->NumberOfAvailableDescriptors);
+
+ if (Reserved->UsedSonicBuffer == TRUE) {
+
+ //
+ // ConstrainPacket returns FALSE if an adapter buffer
+ // is needed and none is available.
+ //
+
+ SuitableForHardware = ConstrainPacket(
+ Adapter,
+ Packet
+ );
+
+ if (!SuitableForHardware) {
+
+ //
+ // Return transmit descriptor
+ //
+
+ Adapter->AllocateableDescriptor = Adapter->TransmitDescriptorArea +
+ DescriptorIndex;
+
+
+ ++(Adapter->NumberOfAvailableDescriptors);
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ goto FinishWithSend;
+
+ }
+
+ }
+
+ //
+ // Put the packet on the finish transmit queue.
+ //
+
+ if (Adapter->FirstFinishTransmit == NULL) {
+
+ Adapter->FirstFinishTransmit = Packet;
+
+ } else {
+
+ PSONIC_RESERVED_FROM_PACKET(Adapter->LastFinishTransmit)->Next = Packet;
+
+ }
+
+ Adapter->LastFinishTransmit = Packet;
+
+ Reserved->Next = NULL;
+
+ //
+ // We have the number of buffers that we need.
+ // We assign all of the buffers to the ring entries.
+ //
+
+ AssignPacketToDescriptor(
+ Adapter,
+ Packet,
+ DescriptorIndex
+ );
+
+ RelinquishPacket(
+ Adapter,
+ Packet,
+ DescriptorIndex
+ );
+
+ } else {
+
+ StatusToReturn = NDIS_STATUS_RESOURCES;
+
+ }
+
+FinishWithSend:
+
+ return StatusToReturn;
+}
+
+STATIC
+BOOLEAN
+ConstrainPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and necessary attempt to acquire adapter
+ buffer resources so that the packet meets sonic hardware
+ contraints. If a buffer is needed and is not available then
+ return FALSE.
+
+ The constraints are that the packet must have SONIC_MAX_FRAGMENTS
+ or fewer physical pieces and no piece may be less than
+ SONIC_MIN_PIECE_SIZE bytes. The first constraint is based on
+ the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
+ is to prevent underflow in the Silo.
+
+ If a packet violates either of the constraints then it
+ will be copied in its entirety into an adapter buffer.
+
+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.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Holds the adapter buffer index available for allocation.
+ //
+ INT SonicBuffersIndex;
+
+ //
+ // Points to a successfully allocated adapter buffer descriptor.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ //
+ // Will point into the virtual address space addressed
+ // by the adapter buffer if one was successfully allocated.
+ //
+ PCHAR CurrentDestination;
+
+ //
+ // 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.
+ //
+ PVOID SourceData;
+
+ //
+ // Will point to the number of bytes of data in the source
+ // buffer.
+ //
+ UINT SourceLength;
+
+ //
+ // Simple iteration variable.
+ //
+ INT i;
+
+ //
+ // Total length of the packet
+ //
+ UINT PacketLength;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &SourceBuffer,
+ &PacketLength
+ );
+
+ if (PacketLength <= SONIC_SMALL_BUFFER_SIZE) {
+
+ i = 1;
+
+ } else if (PacketLength <= SONIC_MEDIUM_BUFFER_SIZE) {
+
+ i = 2;
+
+ } else {
+
+ i = 3;
+
+ }
+
+
+ for (
+ ;
+ i <= 3;
+ i++
+ ) {
+
+ if ((SonicBuffersIndex = Adapter->SonicBufferListHeads[i]) != -1) {
+
+ BufferDescriptor = Adapter->SonicBuffers + SonicBuffersIndex;
+ Adapter->SonicBufferListHeads[i] = BufferDescriptor->Next;
+ break;
+
+ }
+
+ }
+
+ if (SonicBuffersIndex == -1) {
+
+ //
+ // Nothing available for the packet.
+ //
+ return FALSE;
+
+ }
+
+ //
+ // Save the list head index in the buffer descriptor
+ // to permit easy deallocation later.
+ //
+
+ BufferDescriptor->Next = i;
+
+ //
+ // Fill in the adapter buffer with the data from the users
+ // buffers.
+ //
+
+ CurrentDestination = BufferDescriptor->VirtualSonicBuffer;
+
+ while (SourceBuffer) {
+
+ NdisQueryBuffer(
+ SourceBuffer,
+ &SourceData,
+ &SourceLength
+ );
+
+ SONIC_MOVE_MEMORY(
+ CurrentDestination,
+ SourceData,
+ SourceLength
+ );
+
+ CurrentDestination = (PCHAR)CurrentDestination + SourceLength;
+
+ TotalDataMoved += SourceLength;
+
+ NdisGetNextBuffer(
+ SourceBuffer,
+ &SourceBuffer
+ );
+
+ }
+
+ //
+ // If the packet is less then the minimum size then we
+ // need to zero out the rest of the packet.
+ //
+
+ if (TotalDataMoved < SONIC_MIN_PACKET_SIZE) {
+
+ SONIC_ZERO_MEMORY(
+ CurrentDestination,
+ SONIC_MIN_PACKET_SIZE - TotalDataMoved
+ );
+
+ BufferDescriptor->DataLength = SONIC_MIN_PACKET_SIZE;
+
+ } else {
+
+ BufferDescriptor->DataLength = TotalDataMoved;
+
+ }
+
+ //
+ // We need to save in the packet which adapter buffer descriptor
+ // it is using so that we can deallocate it later.
+ //
+
+ Reserved->SonicBuffersIndex = SonicBuffersIndex;
+
+ return TRUE;
+}
+
+STATIC
+VOID
+CalculatePacketConstraints(
+ IN PSONIC_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.
+
+ The constraints are that the packet must have SONIC_MAX_FRAGMENTS
+ or fewer physical pieces and no piece may be less than
+ SONIC_MIN_FRAGMENT_SIZE bytes. The first constraint is based on
+ the size of the SONIC_TRANSMIT_DESCRIPTOR, and the second
+ is to prevent underflow in the Silo (exception: the last
+ fragment in a packet may be smaller).
+
+ If the packet is found to violate the constraints, then
+ UsedSonicBuffer will be set to TRUE. This will cause the entire packet to
+ be copied into the adapter buffer (which is guaranteed
+ to be physically contiguous).
+
+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.
+
+--*/
+
+{
+
+ //
+ // Points to the MacReserved portion of the packet.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // The number of physical buffers in the entire packet.
+ //
+ UINT PacketPhysicalSegments;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // The virtual address of the current ndis buffer.
+ //
+ UINT BufferOffset;
+
+ //
+ // The length in bytes of the current ndis buffer.
+ //
+ UINT BufferVirtualLength;
+
+ //
+ // The total amount of data contained within the ndis packet.
+ //
+ UINT PacketVirtualLength;
+
+ //
+ // The number of physical buffers in a single buffer.
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // TRUE once we find a constraint violation
+ //
+ BOOLEAN ViolatedConstraints = FALSE;
+
+#ifndef NO_CHIP_FIXUP
+ //
+ // Used to keep track of the total number of fragments
+ // that the packet will occupy when assigned to a
+ // transmit descriptor (may be more than PacketPhysicalSegments
+ // if we have to worry about packets starting or ending
+ // on non-longword boundaries.
+ //
+ UINT TotalTransmitSegments = 0;
+#endif
+
+
+
+ //
+ // Get the first buffer in the packet.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ &PacketPhysicalSegments,
+ NULL,
+ &CurrentBuffer,
+ &PacketVirtualLength
+ );
+
+ //
+ // We only allow SONIC_MAX_FRAGMENTS physical pieces.
+ //
+
+ if (PacketPhysicalSegments > SONIC_MAX_FRAGMENTS) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+ //
+ // For short packets we can only allow SONIC_MAX_FRAGMENTS-1
+ // (to allow for the blank padding buffer). Also, we can't
+ // allow the padding itself to be less than the minimum
+ // fragment size.
+ //
+
+ if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE &&
+ ((PacketPhysicalSegments > (SONIC_MAX_FRAGMENTS-1)) ||
+ (PacketVirtualLength >
+ (SONIC_MIN_PACKET_SIZE - SONIC_MIN_FRAGMENT_SIZE)))) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+
+ //
+ // Now loop making sure no fragment is less than
+ // SONIC_MIN_FRAGMENT_SIZE bytes unless it is the
+ // last one.
+ //
+
+ while (CurrentBuffer) {
+
+ NdisQueryBufferOffset(
+ CurrentBuffer,
+ &BufferOffset,
+ &BufferVirtualLength
+ );
+
+
+ //
+ // See if there is only one piece in the buffer.
+ //
+
+ NdisGetBufferPhysicalArraySize(
+ CurrentBuffer,
+ &BufferPhysicalSegments
+ );
+
+ if (BufferPhysicalSegments == 1) {
+
+ //
+ // Only one piece, make sure it is large enough or
+ // is the last fragment.
+ //
+
+ if ((BufferVirtualLength < SONIC_MIN_FRAGMENT_SIZE) &&
+ (NDIS_BUFFER_LINKAGE(CurrentBuffer) != NULL)) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // See if the beginning AND end of this piece are
+ // not longword-aligned.
+ //
+
+ if (((ULONG)BufferOffset & 0x03) &&
+ (((ULONG)BufferOffset + BufferVirtualLength) & 0x03)) {
+
+ //
+ // Now see if this piece is large enough to
+ // be split into two.
+ //
+
+ if (BufferVirtualLength >
+ (UINT)(4 - ((ULONG)BufferOffset & 0x03) +
+ (2*SONIC_MIN_FRAGMENT_SIZE))) {
+
+ //
+ // Have enough to let the first fragment be
+ // SONIC_MIN_FRAGMENT_SIZE plus the extra
+ // few bytes at the beginning, and the
+ // second piece SONIC_MIN_FRAGMENT_SIZE.
+ //
+
+ TotalTransmitSegments += 2;
+
+ } else {
+
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+
+ }
+
+ } else {
+
+ //
+ // This piece won't have to be split, so
+ // just count it as one.
+ //
+
+ TotalTransmitSegments += 1;
+
+ }
+
+#endif
+
+ } else {
+
+ //
+ // Multiple pieces. We assume that the relevant low bits
+ // will be the same in a physical and virtual address, so
+ // we can check using the virtual address whether a
+ // physical segment may be too short (we are being over-
+ // cautious here, but this allows us to avoid actually
+ // querying the physical addresses here.
+ //
+
+ //
+ // See if this buffer starts less than MIN_FRAGMENT_SIZE
+ // bytes before a page boundary.
+ //
+
+ if (PAGE_SIZE - ((ULONG)BufferOffset & (PAGE_SIZE-1)) <
+ SONIC_MIN_FRAGMENT_SIZE) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+ //
+ // See if this buffer ends less than MIN_FRAGMENT_SIZE
+ // bytes after a page boundary.
+ //
+
+ if (((ULONG)BufferOffset + BufferVirtualLength) & (PAGE_SIZE-1) <
+ SONIC_MIN_FRAGMENT_SIZE) {
+ ViolatedConstraints = TRUE;
+ goto DoneExamining;
+ }
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // Add the number of fragments in this piece.
+ // We assume that physical gaps will always be
+ // on at least a 4 byte boundary, so we won't
+ // need to split this piece.
+ //
+
+ TotalTransmitSegments += BufferPhysicalSegments;
+
+#endif
+
+ }
+
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // If the packet is short, we have to allow for the
+ // padding fragment at the end.
+ //
+
+ if (PacketVirtualLength < SONIC_MIN_PACKET_SIZE) {
+
+ TotalTransmitSegments += 1;
+
+ }
+
+#endif
+
+
+DoneExamining: ;
+
+#ifndef NO_CHIP_FIXUP
+ if (ViolatedConstraints || (TotalTransmitSegments > SONIC_MAX_FRAGMENTS)) {
+#else
+ if (ViolatedConstraints) {
+#endif
+
+ Reserved->UsedSonicBuffer = TRUE;
+
+ } else {
+
+ Reserved->UsedSonicBuffer = FALSE;
+
+ }
+
+}
+
+STATIC
+VOID
+AssignPacketToDescriptor(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT DescriptorIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Given a packet and a ring index, assign all of the buffers
+ in the packet to ring entries.
+
+Arguments:
+
+ Adapter - The adapter that the packets are coming through.
+
+ Packet - The packet whose buffers are to be assigned
+ ring entries.
+
+ DescriptorIndex - The index of the start of the ring entries to
+ be assigned buffers.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Points to the reserved portion of the packet.
+ //
+ PSONIC_PACKET_RESERVED Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+
+ //
+ // Pointer to the ring entry to be filled with buffer information.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptor = Adapter->TransmitDescriptorArea
+ + DescriptorIndex;
+
+ //
+ // Pointer to the ring to packet entry that records the info about
+ // this packet.
+ //
+ PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket = Adapter->DescriptorToPacket + DescriptorIndex;
+
+ //
+ // The total amount of data in the ndis packet.
+ //
+ UINT TotalDataLength;
+
+ //
+ // Points to the current ndis buffer being walked.
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // The number of physical segments in this buffer.
+ //
+ UINT BufferPhysicalSegments;
+
+ //
+ // An array to hold the physical segments.
+ //
+ NDIS_PHYSICAL_ADDRESS_UNIT PhysicalSegmentArray[SONIC_MAX_FRAGMENTS];
+
+ //
+ // We record the owning packet information in the ring packet packet
+ // structure.
+ //
+
+
+ DescriptorToPacket->OwningPacket = Packet;
+ DescriptorToPacket->UsedSonicBuffer = (BOOLEAN)
+ Reserved->UsedSonicBuffer;
+ DescriptorToPacket->SonicBuffersIndex =
+ Reserved->SonicBuffersIndex;
+
+
+ //
+ // First initialize the fields that don't depend on
+ // how many fragments there are in the packet.
+ //
+
+ TransmitDescriptor->TransmitStatus = 0;
+
+ //
+ // Set the programmable interrupt if it has been a long
+ // time since transmit complete interrupts were processed.
+ //
+
+ if (Adapter->PacketsSinceLastInterrupt >=
+ (SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS/2)) {
+
+ TransmitDescriptor->TransmitConfiguration = (UINT)SONIC_TCR_PROG_INTERRUPT;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ } else {
+
+ TransmitDescriptor->TransmitConfiguration = 0;
+ ++Adapter->PacketsSinceLastInterrupt;
+
+ }
+
+
+ //
+ // Now check to see if the packet has been copied into an
+ // adapter buffer.
+ //
+
+ if (Reserved->UsedSonicBuffer) {
+
+ //
+ // Points to the adapter buffer descriptor allocated
+ // for this packet.
+ //
+ PSONIC_BUFFER_DESCRIPTOR BufferDescriptor;
+
+ BufferDescriptor = Adapter->SonicBuffers
+ + Reserved->SonicBuffersIndex;
+
+ TransmitDescriptor->FragmentCount = 1;
+ TransmitDescriptor->PacketSize = (UINT)BufferDescriptor->DataLength;
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[0]),
+ NdisGetPhysicalAddressLow(BufferDescriptor->PhysicalSonicBuffer)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[0]),
+ BufferDescriptor->DataLength
+ );
+
+
+ //
+ // This sets end-of-list for this descriptor.
+ //
+
+ SONIC_SET_TRANSMIT_LINK(
+ &(TransmitDescriptor->Fragments[1]),
+ TransmitDescriptor->Link
+ );
+
+ DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
+ &(TransmitDescriptor->Fragments[1]);
+
+
+ //
+ // Flush the buffer that contains the packet.
+ //
+
+ SONIC_FLUSH_WRITE_BUFFER(BufferDescriptor->FlushBuffer);
+
+ } else {
+
+ //
+ // The total length of the packet (including padding)
+ //
+ UINT TotalPacketLength;
+
+ //
+ // Which fragment we are filling;
+ //
+ UINT CurFragment;
+
+ //
+ // Which map register we use for this buffer.
+ //
+ UINT CurMapRegister;
+
+ //
+ // Simple iteration variable.
+ //
+ UINT i;
+
+
+ CurFragment = 0;
+ CurMapRegister = DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ &TotalDataLength
+ );
+
+
+ while (CurrentBuffer) {
+
+ NdisMStartBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister,
+ TRUE,
+ PhysicalSegmentArray,
+ &BufferPhysicalSegments
+ );
+
+ ++CurMapRegister;
+
+ //
+ // Put the physical segments for this buffer into
+ // the transmit descriptors.
+ //
+
+ for (i=0; i<BufferPhysicalSegments; i++) {
+
+ ASSERT (NdisGetPhysicalAddressHigh(PhysicalSegmentArray[i].PhysicalAddress) == 0);
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ PhysicalSegmentArray[i].Length
+ );
+
+ ++CurFragment;
+
+#ifndef NO_CHIP_FIXUP
+
+ //
+ // If the fragment starts and ends not on a longword
+ // boundary, split it into two fragments, the first
+ // being SONIC_MIN_FRAGMENT_SIZE plus the extra bits
+ // at the beginning, the other the rest.
+ //
+
+ if ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03) &&
+ ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) + PhysicalSegmentArray[i].Length) & 0x03)) {
+
+ UINT FirstSegmentLength;
+
+ FirstSegmentLength = (4 - ((NdisGetPhysicalAddressLow(PhysicalSegmentArray[i].PhysicalAddress) & 0x03))) +
+ SONIC_MIN_FRAGMENT_SIZE;
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment-1]),
+ FirstSegmentLength
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment-1])) +
+ FirstSegmentLength
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ PhysicalSegmentArray[i].Length - FirstSegmentLength
+ );
+
+ ++CurFragment;
+
+ }
+#endif
+ }
+
+
+ SONIC_FLUSH_WRITE_BUFFER (CurrentBuffer);
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ if (TotalDataLength < SONIC_MIN_PACKET_SIZE) {
+
+ SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ NdisGetPhysicalAddressLow(Adapter->BlankBufferAddress)
+ );
+
+ SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ SONIC_MIN_PACKET_SIZE - TotalDataLength
+ );
+
+ //
+ // Note that BlankBuffer has already been flushed.
+ //
+
+ ++CurFragment;
+
+ TotalPacketLength = SONIC_MIN_PACKET_SIZE;
+
+ } else {
+
+ TotalPacketLength = TotalDataLength;
+
+ }
+
+ //
+ // Make sure we didn't mess up and use up too
+ // many fragments.
+ //
+ ASSERT(CurFragment <= SONIC_MAX_FRAGMENTS);
+
+ TransmitDescriptor->FragmentCount = (UINT)CurFragment;
+ TransmitDescriptor->PacketSize = (UINT)TotalPacketLength;
+
+
+ //
+ // This sets end-of-list for this descriptor.
+ //
+
+ SONIC_SET_TRANSMIT_LINK(
+ &(TransmitDescriptor->Fragments[CurFragment]),
+ TransmitDescriptor->Link
+ );
+
+ DescriptorToPacket->LinkPointer = (SONIC_PHYSICAL_ADDRESS *)
+ &(TransmitDescriptor->Fragments[CurFragment]);
+
+ }
+
+ if (DescriptorIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
+
+ Adapter->DescriptorToPacket->PrevLinkPointer = DescriptorToPacket->LinkPointer;
+
+ } else {
+
+ (DescriptorToPacket+1)->PrevLinkPointer = DescriptorToPacket->LinkPointer;
+
+ }
+
+ Reserved->DescriptorIndex = DescriptorIndex;
+
+}
+
+STATIC
+VOID
+RelinquishPacket(
+ IN PSONIC_ADAPTER Adapter,
+ IN PNDIS_PACKET Packet,
+ IN UINT RingIndex
+ )
+
+/*++
+
+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 ring
+ entry for the packet.
+
+ RingIndex - Holds the index of the ring entry used
+ by this packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Holds the previous link pointer, where we turn off
+ // end-of-list.
+ //
+
+ PSONIC_PHYSICAL_ADDRESS PrevLinkPointer;
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // NOTE: We have to raise the IRQL to POWER_LEVEL around the
+ // calls to SONIC_REMOVE_END_OF_LIST and START_TRANSMIT.
+ // This is to prevent a delay between these two instructions.
+ // If a delay happens right after SONIC_REMOVE_END_OF_LIST, the
+ // Sonic could transmit the packet and stop, then the call
+ // to START_TRANSMIT would cause it to retransmit all the
+ // packets in the descriptor ring.
+ //
+ // [ChuckL 8/3/94]
+ // We believe that this is no longer necessary, but we are leaving
+ // it in for RISC builds for safety's sake. We are removing in from
+ // x86 builds in order to remain binary-compatible with Chicago.
+ //
+
+ KIRQL OldIrql;
+
+#endif
+
+ PrevLinkPointer = Adapter->DescriptorToPacket[RingIndex].PrevLinkPointer;
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // See NOTE above.
+ //
+
+ KeRaiseIrql(POWER_LEVEL, &OldIrql);
+
+#endif
+
+ //
+ // Turn off END_OF_LIST for the last one.
+ //
+
+ SONIC_REMOVE_END_OF_LIST(PrevLinkPointer);
+
+ //
+ // This turns on the correct bit in the SONIC_CONTROL
+ // register.
+ //
+
+ START_TRANSMIT(Adapter);
+
+#if !BINARY_COMPATIBLE
+
+ //
+ // See NOTE above.
+ //
+
+ KeLowerIrql(OldIrql);
+
+#endif
+
+ //
+ // We want FirstUncommittedDescriptor to point to right after us.
+ //
+
+ if (RingIndex == (Adapter->NumberOfTransmitDescriptors-1)) {
+
+ Adapter->FirstUncommittedDescriptor = Adapter->TransmitDescriptorArea;
+
+ } else {
+
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea + (RingIndex + 1);
+
+ }
+
+}
+
+
diff --git a/private/ntos/ndis/sonic/sonic.c b/private/ntos/ndis/sonic/sonic.c
new file mode 100644
index 000000000..b8322cef4
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonic.c
@@ -0,0 +1,2800 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonic.c
+
+Abstract:
+
+ This is the main file for the National Semiconductor SONIC
+ Ethernet controller. This driver conforms to the NDIS 3.0
+ miniport interface.
+
+Author:
+
+ Adam Barr (adamba) 14-Nov-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+
+//
+// This variable is used to control debug output.
+//
+
+#if DBG
+INT SonicDbg = 0;
+#endif
+
+
+STATIC
+VOID
+SonicHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+VOID
+SonicShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+NDIS_STATUS
+SonicInitalize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+
+STATIC
+NDIS_STATUS
+SonicReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+STATIC
+BOOLEAN
+SonicSynchClearIsr(
+ IN PVOID Context
+ );
+
+STATIC
+VOID
+SonicStopChip(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+SetupRegistersAndInit(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+STATIC
+BOOLEAN
+SonicInitialInit(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ );
+
+
+STATIC
+NDIS_STATUS
+SonicRegisterAdapter(
+ IN NDIS_HANDLE NdisMacHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PUCHAR NetworkAddress,
+ IN UCHAR AdapterType,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ IN UINT SonicInterruptVector,
+ IN UINT SonicInterruptLevel,
+ IN NDIS_INTERRUPT_MODE SonicInterruptMode
+ );
+
+typedef enum {
+ SonicHardwareOk,
+ SonicHardwareChecksum,
+ SonicHardwareConfig
+} SONIC_HARDWARE_STATUS;
+
+STATIC
+SONIC_HARDWARE_STATUS
+SonicHardwareGetDetails(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ OUT PULONG InitialPort,
+ OUT PULONG NumberOfPorts,
+ IN OUT PUINT InterruptVector,
+ IN OUT PUINT InterruptLevel,
+ OUT ULONG ErrorLogData[3]
+ );
+
+STATIC
+BOOLEAN
+SonicHardwareGetAddress(
+ IN PSONIC_ADAPTER Adapter,
+ OUT ULONG ErrorLogData[3]
+ );
+
+#ifdef SONIC_INTERNAL
+
+//
+// These routines are support reading the address for the
+// sonic internal implementation on the R4000 motherboards.
+//
+
+STATIC
+NTSTATUS
+SonicHardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ );
+
+STATIC
+BOOLEAN
+SonicHardwareVerifyChecksum(
+ IN PSONIC_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress,
+ OUT ULONG ErrorLogData[3]
+ );
+
+#endif
+
+
+
+SONIC_DRIVER SonicDriver;
+
+#pragma NDIS_INIT_FUNCTION(DriverEntry)
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ This is the primary initialization routine for the sonic driver.
+ It is simply responsible for the intializing the wrapper and registering
+ the MAC. It then calls a system and architecture specific routine that
+ will initialize and register each adapter.
+
+Arguments:
+
+ DriverObject - Pointer to driver object created by the system.
+
+Return Value:
+
+ The status of the operation.
+
+--*/
+
+{
+
+ //
+ // Receives the status of the NdisRegisterMac operation.
+ //
+ NDIS_STATUS Status;
+
+ NDIS_HANDLE SonicWrapperHandle;
+
+ static const NDIS_STRING MacName = NDIS_STRING_CONST("SONIC");
+ NDIS_MINIPORT_CHARACTERISTICS SonicChar;
+
+#if NDIS_WIN
+ UCHAR pIds[sizeof (EISA_MCA_ADAPTER_IDS) + sizeof (ULONG)];
+#endif
+
+#if NDIS_WIN
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nEisaAdapters=1;
+ ((PEISA_MCA_ADAPTER_IDS)pIds)->nMcaAdapters=0;
+ *(PULONG)(((PEISA_MCA_ADAPTER_IDS)pIds)->IdArray)=SONIC_COMPRESSED_ID;
+ (PVOID) DriverObject = (PVOID) pIds;
+#endif
+
+ //
+ // Initialize the wrapper.
+ //
+
+ NdisMInitializeWrapper(
+ &SonicWrapperHandle,
+ DriverObject,
+ RegistryPath,
+ NULL
+ );
+
+ SonicDriver.WrapperHandle = SonicWrapperHandle;
+
+ //
+ // Initialize the miniport characteristics for the call to
+ // NdisMRegisterMiniport.
+ //
+
+ SonicChar.MajorNdisVersion = SONIC_NDIS_MAJOR_VERSION;
+ SonicChar.MinorNdisVersion = SONIC_NDIS_MINOR_VERSION;
+ SonicChar.CheckForHangHandler = SonicCheckForHang;
+ SonicChar.DisableInterruptHandler = SonicDisableInterrupt;
+ SonicChar.EnableInterruptHandler = SonicEnableInterrupt;
+ SonicChar.HaltHandler = SonicHalt;
+ SonicChar.HandleInterruptHandler = SonicHandleInterrupt;
+ SonicChar.InitializeHandler = SonicInitialize;
+ SonicChar.ISRHandler = SonicInterruptService;
+ SonicChar.QueryInformationHandler = SonicQueryInformation;
+ SonicChar.ReconfigureHandler = NULL;
+ SonicChar.ResetHandler = SonicReset;
+ SonicChar.SendHandler = SonicSend;
+ SonicChar.SetInformationHandler = SonicSetInformation;
+ SonicChar.TransferDataHandler = SonicTransferData;
+
+ Status = NdisMRegisterMiniport(
+ SonicWrapperHandle,
+ &SonicChar,
+ sizeof(SonicChar)
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ //
+ // We can only get here if something went wrong with registering
+ // the mac or *all* of the adapters.
+ //
+
+ NdisTerminateWrapper(SonicWrapperHandle, NULL);
+
+ return NDIS_STATUS_FAILURE;
+
+}
+
+#if DBG
+PVOID SonicAdapterAddress;
+#endif
+
+
+#pragma NDIS_INIT_FUNCTION(SonicRegisterAdapter)
+
+STATIC
+NDIS_STATUS
+SonicRegisterAdapter(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle,
+ IN PUCHAR NetworkAddress,
+ IN UCHAR AdapterType,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ IN UINT SonicInterruptVector,
+ IN UINT SonicInterruptLevel,
+ IN NDIS_INTERRUPT_MODE SonicInterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for the allocation of the datastructures
+ for the driver as well as any hardware specific details necessary
+ to talk with the device.
+
+Arguments:
+
+ MiniportAdapterHandle - The handle given back to the driver from ndis when
+ the driver registered itself.
+
+ ConfigurationHandle - Config handle passed to MacAddAdapter.
+
+ NetworkAddress - The network address, or NULL if the default
+ should be used.
+
+ AdapterType - The type of the adapter; currently SONIC_ADAPTER_TYPE_EISA
+ and SONIC_ADAPTER_TYPE_INTERNAL are supported,
+
+ SlotNumber - The slot number for the EISA card.
+
+ Controller - The controller number for INTERNAL chips.
+
+ MultifunctionAdapter - The INTERNAL bus number for INTERNAL chips.
+
+ SonicInterruptVector - The interrupt vector to use for the adapter.
+
+ SonicInterruptLevel - The interrupt request level to use for this
+ adapter.
+
+ SonicInterruptMode - The interrupt mode to be use for this adapter.
+
+Return Value:
+
+ Returns a failure status if anything occurred that prevents the
+ initialization of the adapter.
+
+--*/
+
+{
+
+ //
+ // Pointer for the adapter root.
+ //
+ PSONIC_ADAPTER Adapter;
+
+ //
+ // Status of various NDIS calls.
+ //
+ NDIS_STATUS Status;
+
+ //
+ // Number of ports needed
+ //
+ ULONG InitialPort;
+ ULONG NumberOfPorts;
+
+ //
+ // Returned from SonicHardwareGetDetails; if it failed,
+ // we log an error and exit.
+ //
+ SONIC_HARDWARE_STATUS HardwareDetailsStatus;
+
+ //
+ // Used to store error log data from SonicHardwareGetDetails.
+ //
+ ULONG ErrorLogData[3];
+
+ //
+ // We put in this assertion to make sure that ushort are 2 bytes.
+ // if they aren't then the initialization block definition needs
+ // to be changed.
+ //
+ // Also all of the logic that deals with status registers assumes
+ // that control registers are only 2 bytes.
+ //
+
+ ASSERT(sizeof(USHORT) == 2);
+
+ //
+ // The Sonic uses four bytes four physical addresses, so we
+ // must ensure that this is the case (SONIC_PHYSICAL_ADDRESS)
+ // is defined as a ULONG).
+ //
+
+ ASSERT(sizeof(SONIC_PHYSICAL_ADDRESS) == 4);
+
+ //
+ // Allocate the Adapter block.
+ //
+
+ SONIC_ALLOC_MEMORY(&Status, &Adapter, sizeof(SONIC_ADAPTER));
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+#if DBG
+ SonicAdapterAddress = Adapter;
+#endif
+
+ SONIC_ZERO_MEMORY(
+ Adapter,
+ sizeof(SONIC_ADAPTER)
+ );
+
+ Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
+
+ Adapter->AdapterType = AdapterType;
+ if (SonicInterruptMode == NdisInterruptLatched) {
+ Adapter->InterruptLatched = TRUE;
+ }
+ Adapter->PermanentAddressValid = FALSE;
+
+ //
+ // Set the attributes
+ //
+
+ NdisMSetAttributes(
+ MiniportAdapterHandle,
+ (NDIS_HANDLE)Adapter,
+ TRUE,
+ (AdapterType == SONIC_ADAPTER_TYPE_EISA) ?
+ NdisInterfaceEisa :
+ NdisInterfaceInternal
+ );
+
+
+ //
+ // Allocate the map registers
+ //
+
+ Status = NdisMAllocateMapRegisters(
+ MiniportAdapterHandle,
+ 0,
+ FALSE,
+ SONIC_MAX_FRAGMENTS * SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS,
+ SONIC_LARGE_BUFFER_SIZE
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ //
+ // This returns the I/O ports used by the Sonic and may
+ // modify SonicInterruptVector and SonicInterruptLevel,
+ // as well as modiying some fields in Adapter.
+ //
+
+ if ((HardwareDetailsStatus =
+ SonicHardwareGetDetails(
+ Adapter,
+ SlotNumber,
+ Controller,
+ MultifunctionAdapter,
+ &InitialPort,
+ &NumberOfPorts,
+ &SonicInterruptVector,
+ &SonicInterruptLevel,
+ ErrorLogData)) != SonicHardwareOk) {
+
+ //
+ // Error out.
+ //
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_NETWORK_ADDRESS,
+ 6,
+ hardwareDetails,
+ SONIC_ERRMSG_HARDWARE_ADDRESS,
+ NDIS_STATUS_FAILURE,
+ ErrorLogData[0],
+ ErrorLogData[1],
+ ErrorLogData[2]
+ );
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Register the port addresses.
+ //
+
+ Status = NdisMRegisterIoPortRange(
+ (PVOID *)(&(Adapter->SonicPortAddress)),
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts
+ );
+
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ Adapter->NumberOfPorts = NumberOfPorts;
+ Adapter->InitialPort = InitialPort;
+
+ //
+ // Allocate memory for all of the adapter structures.
+ //
+
+ Adapter->NumberOfTransmitDescriptors =
+ SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS;
+ Adapter->NumberOfReceiveBuffers =
+ SONIC_NUMBER_OF_RECEIVE_BUFFERS;
+ Adapter->NumberOfReceiveDescriptors =
+ SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS;
+
+
+ if (AllocateAdapterMemory(Adapter)) {
+
+ //
+ // Get the network address. This writes
+ // an error log entry if it fails. This routine
+ // may do nothing on some systems, if
+ // SonicHardwareGetDetails has already determined
+ // the network address.
+ //
+
+ if (!SonicHardwareGetAddress(Adapter, ErrorLogData)) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_NETWORK_ADDRESS,
+ 6,
+ hardwareDetails,
+ SONIC_ERRMSG_HARDWARE_ADDRESS,
+ NDIS_STATUS_FAILURE,
+ ErrorLogData[0],
+ ErrorLogData[1],
+ ErrorLogData[2]
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ //
+ // Initialize the current hardware address.
+ //
+
+ SONIC_MOVE_MEMORY(
+ Adapter->CurrentNetworkAddress,
+ (NetworkAddress != NULL) ?
+ NetworkAddress :
+ Adapter->PermanentNetworkAddress,
+ ETH_LENGTH_OF_ADDRESS);
+
+ Adapter->LastTransmitDescriptor =
+ Adapter->TransmitDescriptorArea +
+ (Adapter->NumberOfTransmitDescriptors-1);
+ Adapter->NumberOfAvailableDescriptors =
+ Adapter->NumberOfTransmitDescriptors;
+ Adapter->AllocateableDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->TransmittingDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ Adapter->CurrentReceiveBufferIndex = 0;
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+ Adapter->LastReceiveDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1];
+
+ //
+ // Flush the current receive buffer, which is the first one.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[0],
+ FALSE
+ );
+
+ Adapter->ReceiveDescriptorsExhausted = FALSE;
+ Adapter->ReceiveBuffersExhausted = FALSE;
+ Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
+
+ Adapter->FirstFinishTransmit = NULL;
+ Adapter->LastFinishTransmit = NULL;
+
+ Adapter->ResetInProgress = FALSE;
+ Adapter->FirstInitialization = TRUE;
+
+ SONIC_ZERO_MEMORY (&Adapter->GeneralMandatory, GM_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalByteCount, GO_COUNT_ARRAY_SIZE * sizeof(SONIC_LARGE_INTEGER));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptionalFrameCount, GO_COUNT_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->GeneralOptional, (GO_ARRAY_SIZE - GO_ARRAY_START) * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->MediaMandatory, MM_ARRAY_SIZE * sizeof(ULONG));
+ SONIC_ZERO_MEMORY (&Adapter->MediaOptional, MO_ARRAY_SIZE * sizeof(ULONG));
+
+ //
+ // Initialize the CAM and associated things.
+ // At the beginning nothing is enabled since
+ // our filter is 0, although we do store
+ // our network address in the first slot.
+ //
+
+ Adapter->MulticastCamEnableBits = 0x0000;
+ Adapter->CurrentPacketFilter = 0;
+ Adapter->CamDescriptorArea->CamEnable = 0x0000;
+ Adapter->CamDescriptorsUsed = 0x0001;
+ Adapter->CamDescriptorAreaSize = 1;
+
+ SONIC_LOAD_CAM_FRAGMENT(
+ &Adapter->CamDescriptorArea->CamFragments[0],
+ 0,
+ Adapter->CurrentNetworkAddress
+ );
+
+ //
+ // Initialize the interrupt.
+ //
+
+ Status = NdisMRegisterInterrupt(
+ &Adapter->Interrupt,
+ MiniportAdapterHandle,
+ SonicInterruptVector,
+ SonicInterruptLevel,
+ FALSE,
+ FALSE,
+ SonicInterruptMode
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_INTERRUPT_CONNECT,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_INIT_INTERRUPT
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return Status;
+
+ }
+
+ //
+ // Start the card up. This writes an error
+ // log entry if it fails.
+ //
+
+ if (!SonicInitialInit(Adapter)) {
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_FAILURE;
+
+ } else {
+
+ //
+ // Register our shutdown handler.
+ //
+
+ NdisMRegisterAdapterShutdownHandler(
+ Adapter->MiniportAdapterHandle, // miniport handle.
+ Adapter, // shutdown context.
+ SonicShutdown // shutdown handler.
+ );
+
+ //
+ // All done.
+ //
+ return NDIS_STATUS_SUCCESS;
+
+ }
+
+
+ } else {
+
+ //
+ // Call to AllocateAdapterMemory failed.
+ //
+
+ NdisWriteErrorLogEntry(
+ MiniportAdapterHandle,
+ NDIS_ERROR_CODE_OUT_OF_RESOURCES,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_ALLOC_MEMORY
+ );
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ MiniportAdapterHandle,
+ InitialPort,
+ NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+ } else {
+
+ //
+ // Couldn't allocate adapter object.
+ //
+
+ return NDIS_STATUS_RESOURCES;
+
+ }
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicInitialInit)
+
+STATIC
+BOOLEAN
+SonicInitialInit(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the initial init of the driver.
+
+Arguments:
+
+ Adapter - The adapter for the hardware.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UINT Time = 50;
+
+ //
+ // First we make sure that the device is stopped.
+ //
+
+ SonicStopChip(Adapter);
+
+ //
+ // Set up the registers.
+ //
+
+ if (!SetupRegistersAndInit(Adapter)) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_ADAPTER_NOT_FOUND,
+ 3,
+ registerAdapter,
+ SONIC_ERRMSG_INITIAL_INIT
+ );
+
+ return FALSE;
+
+ }
+
+
+ //
+ // Delay execution for 1/2 second to give the sonic
+ // time to initialize.
+ //
+
+ while (Time > 0) {
+
+ if (!Adapter->FirstInitialization) {
+ break;
+ }
+
+ NdisStallExecution(10000);
+ Time--;
+
+ }
+
+
+ //
+ // The only way that first initialization could have
+ // been turned off is if we actually initialized.
+ //
+
+ if (!Adapter->FirstInitialization) {
+
+ ULONG PortValue;
+
+ //
+ // We actually did get the initialization.
+ //
+ // We can start the chip. We may not
+ // have any bindings to indicate to but this
+ // is unimportant.
+ //
+
+ SonicStartChip(Adapter);
+
+ NdisStallExecution(25000);
+
+ SONIC_READ_PORT(Adapter, SONIC_COMMAND, &PortValue);
+
+ return TRUE;
+
+
+ } else {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_TIMEOUT,
+ 2,
+ registerAdapter,
+ SONIC_ERRMSG_INITIAL_INIT
+ );
+
+ return FALSE;
+
+ }
+
+}
+
+
+STATIC
+BOOLEAN
+SonicSynchClearIsr(
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used during a reset. It ensures that no
+ interrupts will come through, and that any DPRs that run
+ will find no interrupts to process.
+
+Arguments:
+
+ Context - A pointer to a SONIC_ADAPTER structure.
+
+Return Value:
+
+ Always returns true.
+
+--*/
+
+{
+
+ PSONIC_ADAPTER Adapter = (PSONIC_ADAPTER)Context;
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS, 0xffff);
+ Adapter->SimulatedIsr = 0;
+
+ return TRUE;
+
+}
+
+extern
+VOID
+SonicStartChip(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to start an already initialized sonic.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to start.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Take us out of reset mode if we are in it.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ 0x0000
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_RECEIVER_ENABLE
+ );
+
+}
+
+STATIC
+VOID
+SonicStopChip(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to stop a sonic.
+
+ This routine is *not* portable. It is specific to the 386
+ implementation of the sonic. On the bus master card the ACON bit
+ must be set in csr3, whereas on the decstation, csr3 remains clear.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to stop.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_RECEIVER_DISABLE |
+ SONIC_CR_SOFTWARE_RESET
+ );
+
+}
+
+extern
+VOID
+SonicStartCamReload(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts a CAM reload, which will cause an
+ interrupt when it is done.
+
+Arguments:
+
+ Adapter - The adapter for the SONIC to reload.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Move CAM Enable into the appropriate spot.
+ //
+
+ SONIC_LOAD_CAM_ENABLE(
+ &Adapter->CamDescriptorArea->CamFragments[
+ Adapter->CamDescriptorAreaSize],
+ Adapter->CamDescriptorArea->CamEnable
+ );
+
+
+ //
+ // Flush the CAM before we start the reload.
+ //
+
+ SONIC_FLUSH_WRITE_BUFFER(Adapter->CamDescriptorAreaFlushBuffer);
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(Adapter->CamDescriptorAreaPhysical)
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CAM_DESCRIPTOR_COUNT,
+ (USHORT)Adapter->CamDescriptorAreaSize
+ );
+
+
+ //
+ // Start the Load CAM, which will cause an interrupt
+ // when it is done.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_LOAD_CAM
+ );
+
+}
+
+STATIC
+VOID
+SonicHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ SonicUnload is called when the driver is to remove itself.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Stop the chip.
+ //
+
+ SonicStopChip (Adapter);
+
+ NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+ DeleteAdapterMemory(Adapter);
+ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
+ NdisMDeregisterIoPortRange(
+ Adapter->MiniportAdapterHandle,
+ Adapter->InitialPort,
+ Adapter->NumberOfPorts,
+ (PVOID)Adapter->SonicPortAddress
+ );
+ SONIC_FREE_MEMORY(Adapter, sizeof(SONIC_ADAPTER));
+
+ return;
+
+}
+
+
+
+STATIC
+VOID
+SonicShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+
+/*++
+
+Routine Description:
+
+ SonicShutdown is called when the system is shutdown or it bugchecks.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter = PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ //
+ // Stop the chip.
+ //
+
+ SonicStopChip (Adapter);
+
+ return;
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicInitialize)
+
+STATIC
+NDIS_STATUS
+SonicInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ )
+
+/*++
+
+Routine Description:
+
+ SonicInitialize adds an adapter to the list supported
+ by this driver.
+
+Arguments:
+
+ OpenErrorStatus - Extra status bytes for opening token ring adapters.
+
+ SelectedMediumIndex - Index of the media type chosen by the driver.
+
+ MediumArray - Array of media types for the driver to chose from.
+
+ MediumArraySize - Number of entries in the array.
+
+ MiniportAdapterHandle - Handle for passing to the wrapper when
+ referring to this adapter.
+
+ ConfigurationHandle - A handle to pass to NdisOpenConfiguration.
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+ NDIS_STATUS_FAILURE
+
+--*/
+
+{
+
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ NDIS_HANDLE ConfigHandle;
+ NDIS_STRING AdapterTypeString = NDIS_STRING_CONST("AdapterType");
+#ifdef SONIC_INTERNAL
+ NDIS_STRING MultifunctionAdapterString = NDIS_STRING_CONST("MultifunctionAdapter");
+ NDIS_STRING NetworkControllerString = NDIS_STRING_CONST("NetworkController");
+#endif
+ PNDIS_CONFIGURATION_PARAMETER ReturnedValue;
+ PUCHAR NetworkAddress;
+ UINT NetworkAddressLength;
+ UCHAR AdapterType;
+ UINT InterruptVector;
+ UINT InterruptLevel;
+ NDIS_INTERRUPT_MODE InterruptMode;
+ UINT SlotNumber;
+ UINT Controller = 0;
+ UINT MultifunctionAdapter = 0;
+ UINT i;
+
+ //
+ // Search for the 802.3 media type
+ //
+
+ for (i=0; i<MediumArraySize; i++) {
+
+ if (MediumArray[i] == NdisMedium802_3) {
+ break;
+ }
+
+ }
+
+ if (i == MediumArraySize) {
+
+ return NDIS_STATUS_UNSUPPORTED_MEDIA;
+
+ }
+
+ *SelectedMediumIndex = i;
+
+ //
+ // Open the configuration info.
+ //
+
+ NdisOpenConfiguration(
+ &Status,
+ &ConfigHandle,
+ ConfigurationHandle
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+ return Status;
+ }
+
+
+ //
+ // Check that adapter type is supported.
+ // The default depends on the processor type.
+ //
+
+ AdapterType = SONIC_ADAPTER_TYPE_DEFAULT;
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &AdapterTypeString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ //
+ // See if the adapter type is valid. We skip to AdapterTypeRecognized
+ // if the AdapterType is known to this driver.
+ //
+
+#ifdef SONIC_EISA
+ if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_EISA) {
+ goto AdapterTypeRecognized;
+ }
+#endif
+
+#ifdef SONIC_INTERNAL
+ if (ReturnedValue->ParameterData.IntegerData == SONIC_ADAPTER_TYPE_INTERNAL) {
+ goto AdapterTypeRecognized;
+ }
+#endif
+
+ //
+ // Card type not supported by this driver
+ //
+
+#if DBG
+ DbgPrint("SONIC: Error in adapter type: %lx\n", ReturnedValue->ParameterData.IntegerData);
+#endif
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+
+
+AdapterTypeRecognized:
+
+ AdapterType = (UCHAR)ReturnedValue->ParameterData.IntegerData;
+ }
+
+ switch (AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+ {
+
+ NDIS_EISA_FUNCTION_INFORMATION EisaData;
+ USHORT Portzc88;
+ UCHAR zc88Value;
+ UCHAR Mask;
+ UCHAR InitType;
+ UCHAR PortValue;
+ USHORT PortAddress;
+ PUCHAR CurrentChar;
+ BOOLEAN LastEntry;
+
+ NdisReadEisaSlotInformation(
+ &Status,
+ ConfigurationHandle,
+ &SlotNumber,
+ &EisaData
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+#if DBG
+ DbgPrint("SONIC: Could not read EISA data\n");
+#endif
+ NdisCloseConfiguration(ConfigHandle);
+ return NDIS_STATUS_FAILURE;
+
+ }
+
+ CurrentChar = EisaData.InitializationData;
+
+ Portzc88 = (SlotNumber << 12) + 0xc88;
+
+ LastEntry = FALSE;
+ while (!LastEntry) {
+ InitType = *(CurrentChar++);
+ PortAddress = *((USHORT UNALIGNED *)CurrentChar);
+ CurrentChar += sizeof(USHORT);
+
+ if ((InitType & 0x80) == 0) {
+ LastEntry = TRUE;
+ }
+
+ PortValue = *(CurrentChar++);
+
+ if (InitType & 0x40) {
+ Mask = *(CurrentChar++);
+ } else {
+ Mask = 0;
+ }
+
+ //
+ // The only port we care about is zc88 (z is the
+ // slot number) since it has the interrupt in it.
+ //
+
+ if (PortAddress != Portzc88) {
+ continue;
+ }
+
+ zc88Value &= Mask;
+ zc88Value |= PortValue;
+
+ }
+
+ switch ((zc88Value & 0x06) >> 1) {
+ case 0:
+ InterruptVector = 5; break;
+ case 1:
+ InterruptVector = 9; break;
+ case 2:
+ InterruptVector = 10; break;
+ case 3:
+ InterruptVector = 11; break;
+ }
+
+ InterruptLevel = InterruptVector;
+
+ if ((zc88Value & 0x01) != 0) {
+ InterruptMode = NdisInterruptLatched;
+ } else {
+ InterruptMode = NdisInterruptLevelSensitive;
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ //
+ // For the internal adapter, we read the MultifunctionAdapter number
+ // and NetworkController number, which are both optional. For
+ // passing to SonicRegisterAdapter.
+ //
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &MultifunctionAdapterString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ MultifunctionAdapter = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ NdisReadConfiguration(
+ &Status,
+ &ReturnedValue,
+ ConfigHandle,
+ &NetworkControllerString,
+ NdisParameterInteger
+ );
+
+ if (Status == NDIS_STATUS_SUCCESS) {
+
+ Controller = ReturnedValue->ParameterData.IntegerData;
+
+ }
+
+ //
+ // These are filled in by SonicHardwareGetDetails.
+ //
+
+ InterruptVector = 0;
+ InterruptLevel = 0;
+
+ //
+ // The internal adapter is level-sensitive.
+ //
+
+ InterruptMode = NdisInterruptLevelSensitive;
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ //
+ // Read network address
+ //
+
+ NdisReadNetworkAddress(
+ &Status,
+ (PVOID *)&NetworkAddress,
+ &NetworkAddressLength,
+ ConfigHandle);
+
+
+ //
+ // Make sure that the address is the right length asnd
+ // at least one of the bytes is non-zero.
+ //
+
+ if ((Status == NDIS_STATUS_SUCCESS) &&
+ (NetworkAddressLength == ETH_LENGTH_OF_ADDRESS) &&
+ ((NetworkAddress[0] |
+ NetworkAddress[1] |
+ NetworkAddress[2] |
+ NetworkAddress[3] |
+ NetworkAddress[4] |
+ NetworkAddress[5]) != 0)) {
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: New Address = %.2x-%.2x-%.2x-%.2x-%.2x-%.2x\n",
+ NetworkAddress[0],
+ NetworkAddress[1],
+ NetworkAddress[2],
+ NetworkAddress[3],
+ NetworkAddress[4],
+ NetworkAddress[5]);
+ }
+#endif
+
+ } else {
+
+ //
+ // Tells SonicRegisterAdapter to use the
+ // burned-in address.
+ //
+
+ NetworkAddress = NULL;
+
+ }
+
+ //
+ // Used passed-in adapter name to register.
+ //
+
+ Status = SonicRegisterAdapter(
+ MiniportAdapterHandle,
+ ConfigurationHandle,
+ NetworkAddress,
+ AdapterType,
+ SlotNumber,
+ Controller,
+ MultifunctionAdapter,
+ InterruptVector,
+ InterruptLevel,
+ InterruptMode
+ );
+
+
+ NdisCloseConfiguration(ConfigHandle);
+
+
+ return Status; // should be NDIS_STATUS_SUCCESS
+
+}
+
+STATIC
+NDIS_STATUS
+SonicReset(
+ OUT PBOOLEAN AddressingReset,
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ The SonicReset request instructs the driver to issue a hardware reset
+ to the network adapter. The driver also resets its software state. See
+ the description of MiniportMReset for a detailed description of this request.
+
+Arguments:
+
+ MiniportAdapterContext - Pointer to the adapter structure.
+
+ AddressingReset - Does the adapter need the addressing information reloaded.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ PSONIC_ADAPTER Adapter =
+ PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
+
+ *AddressingReset = FALSE;
+
+ SetupForReset(Adapter);
+ StartAdapterReset(Adapter);
+
+ return NDIS_STATUS_PENDING;
+
+}
+
+extern
+VOID
+StartAdapterReset(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the first phase of resetting the adapter hardware.
+
+ It makes the following assumptions:
+
+ 1) That the hardware has been stopped.
+
+ 2) That it can not be preempted.
+
+ 3) That no other adapter activity can occur.
+
+ When this routine is finished all of the adapter information
+ will be as if the driver was just initialized.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // These are used for cleaning the rings.
+ //
+
+ PSONIC_RECEIVE_DESCRIPTOR CurrentReceiveDescriptor;
+ PSONIC_TRANSMIT_DESCRIPTOR CurrentTransmitDescriptor;
+ UINT i;
+ SONIC_PHYSICAL_ADDRESS SonicPhysicalAdr;
+
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete.
+ //
+
+ SonicStopChip(Adapter);
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // Any interrupts that are "queued" for processing could
+ // only possibly service this reset. It is therefore safe for
+ // us to clear the adapter global csr value.
+ //
+ Adapter->SimulatedIsr = 0;
+
+
+ Adapter->LastTransmitDescriptor =
+ Adapter->TransmitDescriptorArea +
+ (Adapter->NumberOfTransmitDescriptors-1);
+ Adapter->NumberOfAvailableDescriptors =
+ Adapter->NumberOfTransmitDescriptors;
+ Adapter->AllocateableDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->TransmittingDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->FirstUncommittedDescriptor =
+ Adapter->TransmitDescriptorArea;
+ Adapter->PacketsSinceLastInterrupt = 0;
+
+ Adapter->CurrentReceiveBufferIndex = 0;
+ Adapter->CurrentReceiveDescriptorIndex = 0;
+ Adapter->LastReceiveDescriptor =
+ &Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1];
+
+ //
+ // Flush the current receive buffer, which is the first one.
+ //
+
+ NdisFlushBuffer(
+ Adapter->ReceiveNdisBufferArea[0],
+ FALSE
+ );
+
+ Adapter->ReceiveDescriptorsExhausted = FALSE;
+ Adapter->ReceiveBuffersExhausted = FALSE;
+ Adapter->ReceiveControlRegister = SONIC_RCR_DEFAULT_VALUE;
+ Adapter->HardwareFailure = FALSE;
+
+ //
+ // Clean the receive descriptors and initialize the link
+ // fields.
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->ReceiveDescriptorArea,
+ (sizeof(SONIC_RECEIVE_DESCRIPTOR)*Adapter->NumberOfReceiveDescriptors)
+ );
+
+ for (
+ i = 0, CurrentReceiveDescriptor = Adapter->ReceiveDescriptorArea;
+ i < Adapter->NumberOfReceiveDescriptors;
+ i++,CurrentReceiveDescriptor++
+ ) {
+
+ CurrentReceiveDescriptor->InUse = SONIC_OWNED_BY_SONIC;
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_RECEIVE_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->ReceiveDescriptorArea[
+ Adapter->NumberOfReceiveDescriptors-1].Link =
+ SonicPhysicalAdr | SONIC_END_OF_LIST;
+
+ } else {
+
+ Adapter->ReceiveDescriptorArea[i-1].Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Clean the transmit descriptors and initialize the link
+ // fields.
+ //
+
+ SONIC_ZERO_MEMORY(
+ Adapter->TransmitDescriptorArea,
+ (sizeof(SONIC_TRANSMIT_DESCRIPTOR)*Adapter->NumberOfTransmitDescriptors)
+ );
+
+ for (
+ i = 0, CurrentTransmitDescriptor = Adapter->TransmitDescriptorArea;
+ i < Adapter->NumberOfTransmitDescriptors;
+ i++,CurrentTransmitDescriptor++
+ ) {
+
+ SonicPhysicalAdr = NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical) +
+ (i * sizeof(SONIC_TRANSMIT_DESCRIPTOR));
+
+ if (i == 0) {
+
+ Adapter->TransmitDescriptorArea[Adapter->NumberOfTransmitDescriptors-1].Link = SonicPhysicalAdr;
+
+ } else {
+
+ (CurrentTransmitDescriptor-1)->Link = SonicPhysicalAdr;
+
+ }
+
+ }
+
+
+ //
+ // Recover all of the adapter buffers.
+ //
+
+ {
+
+ UINT i;
+
+ for (
+ i = 0;
+ i < (SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS +
+ SONIC_NUMBER_OF_LARGE_BUFFERS);
+ i++
+ ) {
+
+ Adapter->SonicBuffers[i].Next = i+1;
+
+ }
+
+ Adapter->SonicBufferListHeads[0] = -1;
+ Adapter->SonicBufferListHeads[1] = 0;
+ Adapter->SonicBuffers[SONIC_NUMBER_OF_SMALL_BUFFERS-1].Next = -1;
+ Adapter->SonicBufferListHeads[2] = SONIC_NUMBER_OF_SMALL_BUFFERS;
+ Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS)-1].Next = -1;
+ Adapter->SonicBufferListHeads[3] = SONIC_NUMBER_OF_SMALL_BUFFERS +
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS;
+ Adapter->SonicBuffers[(SONIC_NUMBER_OF_SMALL_BUFFERS+
+ SONIC_NUMBER_OF_MEDIUM_BUFFERS+
+ SONIC_NUMBER_OF_LARGE_BUFFERS)-1].Next = -1;
+
+ }
+
+ (VOID)SetupRegistersAndInit(Adapter);
+
+}
+
+STATIC
+BOOLEAN
+SetupRegistersAndInit(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ It is this routines responsibility to make sure that the
+ initialization block is filled and the chip is initialized
+ *but not* started.
+
+ NOTE: This routine assumes that it is called with the lock
+ acquired OR that only a single thread of execution is working
+ with this particular adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ TRUE if the registers are initialized successfully.
+
+--*/
+{
+
+ USHORT CommandRegister;
+ UINT Time;
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_DATA_CONFIGURATION,
+ Adapter->DataConfigurationRegister
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RECEIVE_CONTROL,
+ Adapter->ReceiveControlRegister
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_MASK,
+ SONIC_INT_DEFAULT_VALUE
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_INTERRUPT_STATUS,
+ (USHORT)0xffff
+ );
+
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_TRANSMIT_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->TransmitDescriptorAreaPhysical))
+ );
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_DESCRIPTOR,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_CURR_RECEIVE_DESCRIPTOR,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveDescriptorAreaPhysical))
+ );
+
+
+ //
+ // The EOBC value cannot be odd (since the card register
+ // wants it in words); in addition it appears that the
+ // value in the register must be even, so this number
+ // has to be a multiple of 4.
+ //
+ ASSERT((SONIC_END_OF_BUFFER_COUNT & 0x3) == 0);
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ //
+ // For the EISA card, set EOBC to 2 words more than real
+ // size.
+ //
+ // Add the appropriate correction for the rev. C problem.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
+ ((SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2) + 2
+ );
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+
+ //
+ // Add the appropriate correction for the rev. C problem.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_END_OF_BUFFER_WORD_COUNT,
+ (SONIC_END_OF_BUFFER_COUNT+SONIC_EOBC_REV_C_CORRECTION) / 2
+ );
+ break;
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+ SONIC_WRITE_PORT(Adapter, SONIC_UPPER_RECEIVE_RESOURCE,
+ SONIC_GET_HIGH_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_START,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_END,
+ (USHORT)(SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical)) +
+ sizeof(SONIC_RECEIVE_RESOURCE) *
+ Adapter->NumberOfReceiveBuffers)
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_READ,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+ SONIC_WRITE_PORT(Adapter, SONIC_RESOURCE_WRITE,
+ SONIC_GET_LOW_PART_ADDRESS(
+ NdisGetPhysicalAddressLow(Adapter->ReceiveResourceAreaPhysical))
+ );
+
+
+ //
+ // Now take us out of reset mode...
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ 0x0000
+ );
+
+ //
+ // ...and issue the Read RRA command.
+ //
+
+ SONIC_WRITE_PORT(Adapter, SONIC_COMMAND,
+ SONIC_CR_READ_RRA
+ );
+
+
+
+ //
+ // Wait for 1/5 second for Read RRA to finish.
+ //
+
+ Time = 20;
+
+ while (Time > 0) {
+
+ NdisStallExecution(10000);
+
+ SONIC_READ_PORT(Adapter, SONIC_COMMAND, &CommandRegister);
+ if ((CommandRegister & SONIC_CR_READ_RRA) == 0) {
+ break;
+ }
+
+ Time--;
+
+ }
+
+ if (Time == 0) {
+
+#if DBG
+ DbgPrint("SONIC: Could not read RRA\n");
+#endif
+ return FALSE;
+
+ }
+
+
+ //
+ // This will cause a LOAD_CAM interrupt when it is done.
+ //
+
+ SonicStartCamReload(Adapter);
+
+ return TRUE;
+
+}
+
+extern
+VOID
+SetupForReset(
+ IN PSONIC_ADAPTER Adapter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to fill in the who and why a reset is
+ being set up as well as setting the appropriate fields in the
+ adapter.
+
+Arguments:
+
+ Adapter - The adapter whose hardware is to be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Ndis buffer mapped
+ //
+ PNDIS_BUFFER CurrentBuffer;
+
+ //
+ // Map register that was used
+ //
+ UINT CurMapRegister;
+
+ //
+ // Packet to abort
+ //
+ PNDIS_PACKET Packet;
+
+ //
+ // Reserved Section of packet
+ //
+ PSONIC_PACKET_RESERVED Reserved;
+
+
+ //
+ // Shut down the chip. We won't be doing any more work until
+ // the reset is complete. We take it out of reset mode, however.
+ //
+
+ SonicStopChip(Adapter);
+
+ Adapter->ResetInProgress = TRUE;
+
+
+ //
+ // Once the chip is stopped we can't get any more interrupts.
+ // This call ensures that any ISR which is just about to run
+ // will find no bits in the ISR, and any DPR which fires will
+ // find nothing queued to do.
+ //
+
+ NdisMSynchronizeWithInterrupt(
+ &Adapter->Interrupt,
+ SonicSynchClearIsr,
+ (PVOID)Adapter);
+
+ //
+ // Un-map all outstanding transmits
+ //
+ while (Adapter->FirstFinishTransmit != NULL) {
+
+ //
+ // Remove first packet from the queue
+ //
+ Packet = Adapter->FirstFinishTransmit;
+ Reserved = PSONIC_RESERVED_FROM_PACKET(Packet);
+ Adapter->FirstFinishTransmit = Reserved->Next;
+
+ if (Reserved->UsedSonicBuffer) {
+ continue;
+ }
+
+ //
+ // The transmit is finished, so we can release
+ // the physical mapping used for it.
+ //
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ NULL,
+ &CurrentBuffer,
+ NULL
+ );
+
+ //
+ // Get starting map register
+ //
+ CurMapRegister = Reserved->DescriptorIndex * SONIC_MAX_FRAGMENTS;
+
+ //
+ // For each buffer
+ //
+ while (CurrentBuffer) {
+
+ //
+ // Finish the mapping
+ //
+ NdisMCompleteBufferPhysicalMapping(
+ Adapter->MiniportAdapterHandle,
+ CurrentBuffer,
+ CurMapRegister
+ );
+
+ ++CurMapRegister;
+
+ NdisGetNextBuffer(
+ CurrentBuffer,
+ &CurrentBuffer
+ );
+
+ }
+
+ }
+
+}
+
+#ifdef SONIC_INTERNAL
+
+//
+// The next routines are to support reading the registry to
+// obtain information about the internal sonic on the
+// MIPS R4000 motherboards.
+//
+
+//
+// This structure is used as the Context in the callbacks
+// to SonicHardwareSaveInformation.
+//
+
+typedef struct _SONIC_HARDWARE_INFO {
+
+ //
+ // These are read out of the "Configuration Data"
+ // data.
+ //
+
+ CCHAR InterruptVector;
+ KIRQL InterruptLevel;
+ USHORT DataConfigurationRegister;
+ LARGE_INTEGER PortAddress;
+ BOOLEAN DataValid;
+ UCHAR EthernetAddress[8];
+ BOOLEAN AddressValid;
+
+ //
+ // This is set to TRUE if "Identifier" is equal to
+ // "SONIC".
+ //
+
+ BOOLEAN SonicIdentifier;
+
+} SONIC_HARDWARE_INFO, *PSONIC_HARDWARE_INFO;
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareSaveInformation)
+
+STATIC
+NTSTATUS
+SonicHardwareSaveInformation(
+ IN PWSTR ValueName,
+ IN ULONG ValueType,
+ IN PVOID ValueData,
+ IN ULONG ValueLength,
+ IN PVOID Context,
+ IN PVOID EntryContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a callback routine for RtlQueryRegistryValues.
+ It is called back with the data for the "Identifier" value
+ and verifies that it is "SONIC", then is called back with
+ the resource list and records the ports, interrupt number,
+ and DCR value.
+
+Arguments:
+
+ ValueName - The name of the value ("Identifier" or "Configuration
+ Data").
+
+ ValueType - The type of the value (REG_SZ or REG_BINARY).
+
+ ValueData - The null-terminated data for the value.
+
+ ValueLength - The length of ValueData (ignored).
+
+ Context - A pointer to the SONIC_HARDWARE_INFO structure.
+
+ EntryContext - FALSE for "Identifier", TRUE for "Configuration Data".
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+
+{
+ PSONIC_HARDWARE_INFO HardwareInfo = (PSONIC_HARDWARE_INFO)Context;
+
+ if ((BOOLEAN)EntryContext) {
+
+ //
+ // This is the "Configuration Data" callback.
+ //
+
+ if ((ValueType == REG_BINARY || ValueType == REG_FULL_RESOURCE_DESCRIPTOR) &&
+ (ValueLength >= sizeof(CM_FULL_RESOURCE_DESCRIPTOR))) {
+
+ BOOLEAN InterruptRead = FALSE;
+ BOOLEAN PortAddressRead = FALSE;
+ BOOLEAN DeviceSpecificRead = FALSE;
+ UINT i;
+
+ PCM_PARTIAL_RESOURCE_LIST ResourceList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceDescriptor;
+ PCM_SONIC_DEVICE_DATA SonicDeviceData;
+
+ ResourceList =
+ &((PCM_FULL_RESOURCE_DESCRIPTOR)ValueData)->PartialResourceList;
+
+ for (i = 0; i < ResourceList->Count; i++) {
+
+ ResourceDescriptor = &(ResourceList->PartialDescriptors[i]);
+
+ switch (ResourceDescriptor->Type) {
+
+ case CmResourceTypePort:
+
+ HardwareInfo->PortAddress = ResourceDescriptor->u.Port.Start;
+ PortAddressRead = TRUE;
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ HardwareInfo->InterruptVector = (CCHAR)ResourceDescriptor->u.Interrupt.Vector;
+ HardwareInfo->InterruptLevel = (KIRQL)ResourceDescriptor->u.Interrupt.Level;
+ InterruptRead = TRUE;
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ if (i == ResourceList->Count-1) {
+
+ SonicDeviceData = (PCM_SONIC_DEVICE_DATA)
+ &(ResourceList->PartialDescriptors[ResourceList->Count]);
+
+ //
+ // Make sure we have enough room for each element we read.
+ //
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]))) {
+
+ HardwareInfo->DataConfigurationRegister =
+ SonicDeviceData->DataConfigurationRegister;
+ DeviceSpecificRead = TRUE;
+
+ //
+ // Version.Revision later than 0.0 means that
+ // the ethernet address is there too.
+ //
+
+ if ((SonicDeviceData->Version != 0) ||
+ (SonicDeviceData->Revision != 0)) {
+
+ if (ResourceDescriptor->u.DeviceSpecificData.DataSize >=
+ (ULONG)(FIELD_OFFSET (CM_SONIC_DEVICE_DATA, EthernetAddress[0]) + 8)) {
+
+ SONIC_MOVE_MEMORY(
+ HardwareInfo->EthernetAddress,
+ SonicDeviceData->EthernetAddress,
+ 8);
+
+ HardwareInfo->AddressValid = TRUE;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ break;
+
+ }
+
+ }
+
+ //
+ // Make sure we got all we wanted.
+ //
+
+ if (PortAddressRead && InterruptRead && DeviceSpecificRead) {
+ HardwareInfo->DataValid = TRUE;
+ }
+
+ }
+
+ } else {
+
+ static const WCHAR SonicString[] = L"SONIC";
+
+ //
+ // This is the "Identifier" callback.
+ //
+
+ if ((ValueType == REG_SZ) &&
+ (ValueLength >= sizeof(SonicString)) &&
+ (RtlCompareMemory (ValueData, (PVOID)&SonicString, sizeof(SonicString)) == sizeof(SonicString))) {
+
+ HardwareInfo->SonicIdentifier = TRUE;
+
+ }
+
+ }
+
+ return STATUS_SUCCESS;
+
+}
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareVerifyChecksum)
+
+STATIC
+BOOLEAN
+SonicHardwareVerifyChecksum(
+ IN PSONIC_ADAPTER Adapter,
+ IN PUCHAR EthernetAddress,
+ OUT ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine verifies that the checksum on the address
+ for an internal sonic on a MIPS R4000 system is correct.
+
+Arguments:
+
+ Adapter - The adapter which is being verified.
+
+ EthernetAddress - A pointer to the address, with the checksum
+ following it.
+
+ ErrorLogData - If the checksum is bad, returns the address
+ and the checksum we expected.
+
+Return Value:
+
+ TRUE if the checksum is correct.
+
+--*/
+
+{
+
+ //
+ // Iteration variable.
+ //
+ UINT i;
+
+ //
+ // Holds the checksum value.
+ //
+ USHORT CheckSum = 0;
+
+
+ //
+ // The network address is stored in the first 6 bytes of
+ // EthernetAddress. Following that is a zero byte followed
+ // by a value such that the sum of a checksum on the six
+ // bytes and this value is 0xff. The checksum is computed
+ // by adding together the six bytes, with the carry being
+ // wrapped back to the first byte.
+ //
+
+ for (i=0; i<6; i++) {
+
+ CheckSum += EthernetAddress[i];
+ if (CheckSum > 0xff) {
+ CheckSum -= 0xff;
+ }
+
+ }
+
+
+ if ((EthernetAddress[6] != 0x00) ||
+ ((EthernetAddress[7] + CheckSum) != 0xff)) {
+
+ ErrorLogData[0] = ((ULONG)(EthernetAddress[3]) << 24) +
+ ((ULONG)(EthernetAddress[2]) << 16) +
+ ((ULONG)(EthernetAddress[1]) << 8) +
+ ((ULONG)(EthernetAddress[0]));
+ ErrorLogData[1] = ((ULONG)(EthernetAddress[7]) << 24) +
+ ((ULONG)(EthernetAddress[6]) << 16) +
+ ((ULONG)(EthernetAddress[5]) << 8) +
+ ((ULONG)(EthernetAddress[4]));
+ ErrorLogData[2] = 0xff - CheckSum;
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+
+}
+
+#endif // SONIC_INTERNAL
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareGetDetails)
+
+STATIC
+SONIC_HARDWARE_STATUS
+SonicHardwareGetDetails(
+ IN PSONIC_ADAPTER Adapter,
+ IN UINT SlotNumber,
+ IN UINT Controller,
+ IN UINT MultifunctionAdapter,
+ OUT PULONG InitialPort,
+ OUT PULONG NumberOfPorts,
+ IN OUT PUINT InterruptVector,
+ IN OUT PUINT InterruptLevel,
+ OUT ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the initial port and number of ports for
+ the Sonic. It also sets Adapter->PortShift. The ports are
+ numbered 0, 1, 2, etc. but may appear as 16- or 32-bit
+ ports, so PortShift will be 1 or 2 depending on how wide
+ the ports are.
+
+ It also sets the value of Adapter->DataConfigurationRegister,
+ and may modify InterruptVector, InterruptLevel, and
+ Adapter->PermanentNetworkAddress.
+
+Arguments:
+
+ Adapter - The adapter in question.
+
+ SlotNumber - For the EISA card this is the slot number that the
+ card is in.
+
+ Controller - For the internal version, it is the
+ NetworkController number.
+
+ MultifunctionAdapter - For the internal version, it is the adapter number.
+
+ InitialPort - The base of the Sonic ports.
+
+ NumberOfPorts - The number of bytes of ports to map.
+
+ InterruptVector - A pointer to the interrupt vector. Depending
+ on the card type, this may be passed in or returned by
+ this function.
+
+ InterruptLevel - A pointer to the interrupt level. Depending
+ on the card type, this may be passed in or returned by
+ this function.
+
+ ErrorLogData - If the return status is SonicHardwareChecksum,
+ this returns 3 longwords to be included in the error log.
+
+Return Value:
+
+ SonicHardwareOk if successful, SonicHardwareChecksum if the
+ checksum is bad, SonicHardwareConfig for other problems.
+
+--*/
+
+{
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ *InitialPort = (SlotNumber << 12);
+ *NumberOfPorts = 0xD00;
+ Adapter->PortShift = 1;
+ Adapter->DataConfigurationRegister =
+ SONIC_DCR_PROGRAMMABLE_OUTPUT_1 |
+ SONIC_DCR_USER_DEFINABLE_1 |
+ SONIC_DCR_3_WAIT_STATE |
+ SONIC_DCR_BLOCK_MODE_DMA |
+ SONIC_DCR_32_BIT_DATA_WIDTH |
+ SONIC_DCR_8_WORD_RECEIVE_FIFO |
+ SONIC_DCR_8_WORD_TRANSMIT_FIFO;
+
+ return SonicHardwareOk;
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ //
+ // For MIPS R4000 systems, we have to query the registry to obtain
+ // information about ports, interrupts, and the value to be
+ // stored in the DCR register.
+ //
+
+ //
+ // NOTE: The following code is NT-specific, since that is
+ // currently the only system that runs on the MIPS R4000 hardware.
+ //
+ // We initialize an RTL_QUERY_TABLE to retrieve the Identifer
+ // and ConfigurationData strings from the registry.
+ //
+
+ PWSTR ConfigDataPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter\\#\\NetworkController\\#";
+ PWSTR IdentifierString = L"Identifier";
+ PWSTR ConfigDataString = L"Configuration Data";
+ RTL_QUERY_REGISTRY_TABLE QueryTable[4];
+ SONIC_HARDWARE_INFO SonicHardwareInfo;
+ NTSTATUS Status;
+
+
+ //
+ // Set up QueryTable to do the following:
+ //
+
+ //
+ // 1) Call SonicSaveHardwareInformation for the "Identifier"
+ // value.
+ //
+
+ QueryTable[0].QueryRoutine = SonicHardwareSaveInformation;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = IdentifierString;
+ QueryTable[0].EntryContext = (PVOID)FALSE;
+ QueryTable[0].DefaultType = REG_NONE;
+
+ //
+ // 2) Call SonicSaveHardwareInformation for the "Configuration Data"
+ // value.
+ //
+
+ QueryTable[1].QueryRoutine = SonicHardwareSaveInformation;
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[1].Name = ConfigDataString;
+ QueryTable[1].EntryContext = (PVOID)TRUE;
+ QueryTable[1].DefaultType = REG_NONE;
+
+ //
+ // 3) Stop
+ //
+
+ QueryTable[2].QueryRoutine = NULL;
+ QueryTable[2].Flags = 0;
+ QueryTable[2].Name = NULL;
+
+
+ //
+ // Modify ConfigDataPath to replace the two # symbols with
+ // the MultifunctionAdapter number and NetworkController number.
+ //
+
+ ConfigDataPath[67] = (WCHAR)('0' + MultifunctionAdapter);
+ ConfigDataPath[87] = (WCHAR)('0' + Controller);
+
+ SonicHardwareInfo.DataValid = FALSE;
+ SonicHardwareInfo.AddressValid = FALSE;
+ SonicHardwareInfo.SonicIdentifier = FALSE;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ ConfigDataPath,
+ QueryTable,
+ (PVOID)&SonicHardwareInfo,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ DbgPrint ("SONIC: Could not read hardware information\n");
+#endif
+ return SonicHardwareConfig;
+ }
+
+ if (SonicHardwareInfo.DataValid && SonicHardwareInfo.SonicIdentifier) {
+
+ *InterruptVector = (UINT)SonicHardwareInfo.InterruptVector;
+ *InterruptLevel = (UINT)SonicHardwareInfo.InterruptLevel;
+ *InitialPort = SonicHardwareInfo.PortAddress.LowPart;
+ *NumberOfPorts = 192;
+ Adapter->PortShift = 2;
+ Adapter->DataConfigurationRegister =
+ SonicHardwareInfo.DataConfigurationRegister;
+
+ if (SonicHardwareInfo.AddressValid) {
+
+ if (!SonicHardwareVerifyChecksum(Adapter, SonicHardwareInfo.EthernetAddress, ErrorLogData)) {
+#if DBG
+ DbgPrint("SONIC: Invalid registry network address checksum!!\n");
+#endif
+ return SonicHardwareChecksum;
+ }
+
+ SONIC_MOVE_MEMORY(
+ Adapter->PermanentNetworkAddress,
+ SonicHardwareInfo.EthernetAddress,
+ 8);
+ Adapter->PermanentAddressValid = TRUE;
+
+ }
+
+ return SonicHardwareOk;
+
+ } else {
+
+#if DBG
+ DbgPrint ("SONIC: Incorrect registry hardware information\n");
+#endif
+ return SonicHardwareConfig;
+
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+ return SonicHardwareConfig;
+
+}
+
+
+
+#pragma NDIS_INIT_FUNCTION(SonicHardwareGetAddress)
+
+STATIC
+BOOLEAN
+SonicHardwareGetAddress(
+ IN PSONIC_ADAPTER Adapter,
+ IN ULONG ErrorLogData[3]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the network address from the hardware.
+
+Arguments:
+
+ Adapter - Where to store the network address.
+
+ ErrorLogData - If the checksum is bad, returns the address
+ and the checksum we expected.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+
+{
+#define NVRAM_READ_ONLY_BASE 0x8000b000
+
+ //
+ // Iteration variable.
+ //
+ UINT i;
+
+
+ switch (Adapter->AdapterType) {
+
+#ifdef SONIC_EISA
+
+ case SONIC_ADAPTER_TYPE_EISA:
+
+ //
+ // The EISA card has the address stored at ports xC90 to xC95,
+ // where x is the slot number.
+ //
+
+ for (i = 0; i < 6; i++) {
+
+ NdisRawReadPortUchar(
+ Adapter->SonicPortAddress + 0xc90 + i,
+ &Adapter->PermanentNetworkAddress[i]);
+
+ }
+
+ break;
+
+#endif // SONIC_EISA
+
+#ifdef SONIC_INTERNAL
+
+ case SONIC_ADAPTER_TYPE_INTERNAL:
+ {
+
+ NDIS_STATUS Status;
+ USHORT SiliconRevision;
+
+ if (!Adapter->PermanentAddressValid) {
+
+ //
+ // Physical addresses for call to NdisMapIoSpace.
+ //
+
+ NDIS_PHYSICAL_ADDRESS NvRamPhysical =
+ NDIS_PHYSICAL_ADDRESS_CONST(NVRAM_READ_ONLY_BASE, 0);
+
+ //
+ // Temporarily maps the NVRAM into our address space.
+ //
+ PVOID NvRamMapping;
+
+
+
+ //
+ // If PermanentAddressValid is still FALSE then the address
+ // was not read by SonicHardwareGetDetails, so we must do it
+ // here.
+ //
+
+ Status = NdisMMapIoSpace (
+ &NvRamMapping,
+ Adapter->MiniportAdapterHandle,
+ NvRamPhysical,
+ 8
+ );
+
+ if (Status != NDIS_STATUS_SUCCESS) {
+
+ NdisWriteErrorLogEntry(
+ Adapter->MiniportAdapterHandle,
+ NDIS_ERROR_CODE_RESOURCE_CONFLICT,
+ 0
+ );
+
+ return(FALSE);
+
+ }
+
+ //
+ // Verify that the checksum matches.
+ //
+
+ if (!SonicHardwareVerifyChecksum(Adapter, (PUCHAR)NvRamMapping, ErrorLogData)) {
+
+#if DBG
+ DbgPrint("SONIC: Invalid NVRAM network address checksum!!\n");
+#endif
+ NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
+ return FALSE;
+
+ }
+
+ //
+ // Checksum is OK, save the address.
+ //
+
+ for (i=0; i<6; i++) {
+ Adapter->PermanentNetworkAddress[i] = *((PUCHAR)NvRamMapping+i);
+ }
+ Adapter->PermanentAddressValid = TRUE;
+
+ NdisMUnmapIoSpace(Adapter->MiniportAdapterHandle, NvRamMapping, 8);
+
+ }
+
+ //
+ // The Data Configuration Register is already set up, but we
+ // change the FIFO initialization for old revisions.
+ //
+
+ SONIC_READ_PORT(Adapter, SONIC_SILICON_REVISION, &SiliconRevision);
+
+ if (SiliconRevision < 4) {
+
+ Adapter->DataConfigurationRegister =
+ (Adapter->DataConfigurationRegister & SONIC_DCR_FIFO_MASK) |
+ SONIC_DCR_8_WORD_RECEIVE_FIFO |
+ SONIC_DCR_8_WORD_TRANSMIT_FIFO;
+
+ }
+
+ break;
+
+ }
+
+#endif // SONIC_INTERNAL
+
+ default:
+
+ ASSERT(FALSE);
+ break;
+
+ }
+
+
+#if DBG
+ if (SonicDbg) {
+ DbgPrint("SONIC: ");
+ DbgPrint("[ %x-%x-%x-%x-%x-%x ]\n",
+ (UCHAR)Adapter->PermanentNetworkAddress[0],
+ (UCHAR)Adapter->PermanentNetworkAddress[1],
+ (UCHAR)Adapter->PermanentNetworkAddress[2],
+ (UCHAR)Adapter->PermanentNetworkAddress[3],
+ (UCHAR)Adapter->PermanentNetworkAddress[4],
+ (UCHAR)Adapter->PermanentNetworkAddress[5]);
+ DbgPrint("\n");
+ }
+#endif
+
+ return TRUE;
+
+}
diff --git a/private/ntos/ndis/sonic/sonic.rc b/private/ntos/ndis/sonic/sonic.rc
new file mode 100644
index 000000000..311a777c2
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonic.rc
@@ -0,0 +1,39 @@
+#include <windows.h>
+#include <ntverp.h>
+
+/*-----------------------------------------------*/
+/* the following lines are specific to this file */
+/*-----------------------------------------------*/
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_DRV
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_DRV_NETWORK
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "ARC Built-In Ethernet network driver"
+#define VER_INTERNALNAME_STR "SONIC.SYS"
+#define VER_ORIGINALFILENAME_STR "SONIC.SYS"
+
+#include "common.ver"
+
diff --git a/private/ntos/ndis/sonic/sonichrd.h b/private/ntos/ndis/sonic/sonichrd.h
new file mode 100644
index 000000000..470f18383
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonichrd.h
@@ -0,0 +1,791 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonichrd.h
+
+Abstract:
+
+ This file contains the hardware-related definitions for
+ the SONIC driver.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 16-Nov-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+#ifndef _SONICHARDWARE_
+#define _SONICHARDWARE_
+
+
+//
+// Include processor-specific definitions needed by the sonic.
+// This defines the SONIC_READ_PORT and SONIC_WRITE_PORT macros,
+// as well as whether SONIC_EISA and SONIC_INTERNAL are defined.
+//
+
+#include <sonicdet.h>
+
+//
+// Compressed ID for the adapter
+//
+
+#define SONIC_COMPRESSED_ID 0x01109841
+
+
+//
+// Offsets from the base of the Sonic registers.
+//
+// All registers are 16 bits.
+//
+
+#define SONIC_COMMAND 0x00
+#define SONIC_DATA_CONFIGURATION 0x01
+#define SONIC_RECEIVE_CONTROL 0x02
+#define SONIC_TRANSMIT_CONTROL 0x03
+#define SONIC_INTERRUPT_MASK 0x04
+#define SONIC_INTERRUPT_STATUS 0x05
+
+#define SONIC_UPPER_TRANSMIT_DESCRIPTOR 0x06
+#define SONIC_CURR_TRANSMIT_DESCRIPTOR 0x07
+
+#define SONIC_UPPER_RECEIVE_DESCRIPTOR 0x0d
+#define SONIC_CURR_RECEIVE_DESCRIPTOR 0x0e
+#define SONIC_END_OF_BUFFER_WORD_COUNT 0x13
+#define SONIC_UPPER_RECEIVE_RESOURCE 0x14
+#define SONIC_RESOURCE_START 0x15
+#define SONIC_RESOURCE_END 0x16
+#define SONIC_RESOURCE_READ 0x17
+#define SONIC_RESOURCE_WRITE 0x18
+#define SONIC_RECEIVE_SEQUENCE 0x2b
+
+#define SONIC_CAM_ENTRY_POINTER 0x21
+#define SONIC_CAM_ADDRESS_PORT_2 0x22
+#define SONIC_CAM_ADDRESS_PORT_1 0x23
+#define SONIC_CAM_ADDRESS_PORT_0 0x24
+#define SONIC_CAM_ENABLE 0x25
+#define SONIC_CAM_DESCRIPTOR 0x26
+#define SONIC_CAM_DESCRIPTOR_COUNT 0x27
+
+#define SONIC_CRC_ERROR 0x2c
+#define SONIC_FRAME_ALIGNMENT_ERROR 0x2d
+#define SONIC_MISSED_PACKET 0x2e
+
+#define SONIC_WATCHDOG_TIMER_0 0x29
+#define SONIC_WATCHDOG_TIMER_1 0x2a
+
+#define SONIC_SILICON_REVISION 0x28
+
+
+//
+// Constants for the SONIC_COMMAND register.
+//
+
+#define SONIC_CR_LOAD_CAM ((USHORT)(0x0200))
+#define SONIC_CR_READ_RRA ((USHORT)(0x0100))
+#define SONIC_CR_SOFTWARE_RESET ((USHORT)(0x0080))
+#define SONIC_CR_START_TIMER ((USHORT)(0x0020))
+#define SONIC_CR_STOP_TIMER ((USHORT)(0x0010))
+#define SONIC_CR_RECEIVER_ENABLE ((USHORT)(0x0008))
+#define SONIC_CR_RECEIVER_DISABLE ((USHORT)(0x0004))
+#define SONIC_CR_TRANSMIT_PACKETS ((USHORT)(0x0002))
+#define SONIC_CR_HALT_TRANSMISSION ((USHORT)(0x0001))
+
+
+//
+// Constants for the SONIC_DATA_CONFIGURATION register.
+//
+
+#define SONIC_DCR_LATCHED_BUS_RETRY ((USHORT)(0x2000))
+#define SONIC_DCR_PROGRAMMABLE_OUTPUT_1 ((USHORT)(0x1000))
+#define SONIC_DCR_PROGRAMMABLE_OUTPUT_0 ((USHORT)(0x0800))
+#define SONIC_DCR_SYNCH_TERMINATION ((USHORT)(0x0400))
+#define SONIC_DCR_USER_DEFINABLE_1 ((USHORT)(0x0200))
+#define SONIC_DCR_USER_DEFINABLE_0 ((USHORT)(0x0100))
+#define SONIC_DCR_0_WAIT_STATE ((USHORT)(0x0000))
+#define SONIC_DCR_1_WAIT_STATE ((USHORT)(0x0040))
+#define SONIC_DCR_2_WAIT_STATE ((USHORT)(0x0080))
+#define SONIC_DCR_3_WAIT_STATE ((USHORT)(0x00c0))
+#define SONIC_DCR_32_BIT_DATA_WIDTH ((USHORT)(0x0020))
+#define SONIC_DCR_16_BIT_DATA_WIDTH ((USHORT)(0x0000))
+#define SONIC_DCR_BLOCK_MODE_DMA ((USHORT)(0x0010))
+#define SONIC_DCR_EMPTY_FILL_DMA ((USHORT)(0x0000))
+#define SONIC_DCR_FIFO_MASK ((USHORT)(0xfff0))
+#define SONIC_DCR_12_WORD_RECEIVE_FIFO ((USHORT)(0x000c))
+#define SONIC_DCR_8_WORD_RECEIVE_FIFO ((USHORT)(0x0008))
+#define SONIC_DCR_4_WORD_RECEIVE_FIFO ((USHORT)(0x0004))
+#define SONIC_DCR_2_WORD_RECEIVE_FIFO ((USHORT)(0x0000))
+#define SONIC_DCR_14_WORD_TRANSMIT_FIFO ((USHORT)(0x0003))
+#define SONIC_DCR_12_WORD_TRANSMIT_FIFO ((USHORT)(0x0002))
+#define SONIC_DCR_8_WORD_TRANSMIT_FIFO ((USHORT)(0x0001))
+#define SONIC_DCR_4_WORD_TRANSMIT_FIFO ((USHORT)(0x0000))
+
+
+//
+// Constants for the SONIC_RECEIVE_CONTROL register.
+//
+
+#define SONIC_RCR_ACCEPT_CRC_ERRORS ((USHORT)(0x8000))
+#define SONIC_RCR_ACCEPT_RUNT_PACKETS ((USHORT)(0x4000))
+#define SONIC_RCR_ACCEPT_BROADCAST ((USHORT)(0x2000))
+#define SONIC_RCR_PROMISCUOUS_PHYSICAL ((USHORT)(0x1000))
+#define SONIC_RCR_ACCEPT_ALL_MULTICAST ((USHORT)(0x0800))
+#define SONIC_RCR_TRANSCEIVER_LOOPBACK ((USHORT)(0x0600))
+#define SONIC_RCR_ENDEC_LOOPBACK ((USHORT)(0x0400))
+#define SONIC_RCR_MAC_LOOPBACK ((USHORT)(0x0200))
+#define SONIC_RCR_NO_LOOPBACK ((USHORT)(0x0000))
+
+#define SONIC_RCR_MULTICAST_RECEIVED ((USHORT)(0x0100))
+#define SONIC_RCR_BROADCAST_RECEIVED ((USHORT)(0x0080))
+#define SONIC_RCR_LAST_PACKET_IN_RBA ((USHORT)(0x0040))
+#define SONIC_RCR_CARRIER_SENSE ((USHORT)(0x0020))
+#define SONIC_RCR_COLLISION ((USHORT)(0x0010))
+#define SONIC_RCR_CRC_ERROR ((USHORT)(0x0008))
+#define SONIC_RCR_FRAME_ALIGNMENT ((USHORT)(0x0004))
+#define SONIC_RCR_LOOPBACK_RECEIVED ((USHORT)(0x0002))
+#define SONIC_RCR_PACKET_RECEIVED_OK ((USHORT)(0x0001))
+
+
+//
+// This is needed due to a problem with the SONIC while attempting
+// to ignore these packets.
+//
+
+#define SONIC_RCR_DEFAULT_VALUE ((USHORT) \
+ (SONIC_RCR_ACCEPT_CRC_ERRORS | \
+ SONIC_RCR_ACCEPT_RUNT_PACKETS))
+
+
+//
+// Constants for the SONIC_TRANSMIT_CONTROL register.
+//
+
+#define SONIC_TCR_PROG_INTERRUPT ((USHORT)(0x8000))
+#define SONIC_TCR_CRC_INHIBIT ((USHORT)(0x2000))
+#define SONIC_TCR_EXCESSIVE_DEFERRAL ((USHORT)(0x0400))
+#define SONIC_TCR_DEFERRED_TRANSMISSION ((USHORT)(0x0200))
+#define SONIC_TCR_NO_CARRIER_SENSE ((USHORT)(0x0100))
+#define SONIC_TCR_CARRIER_LOST ((USHORT)(0x0080))
+#define SONIC_TCR_EXCESSIVE_COLLISIONS ((USHORT)(0x0040))
+#define SONIC_TCR_OUT_OF_WINDOW ((USHORT)(0x0020))
+#define SONIC_TCR_FIFO_UNDERRUN ((USHORT)(0x0004))
+#define SONIC_TCR_BYTE_COUNT_MISMATCH ((USHORT)(0x0002))
+#define SONIC_TCR_PACKET_TRANSMITTED_OK ((USHORT)(0x0001))
+
+#define SONIC_TCR_STATUS_MASK ((USHORT)(0x07ff))
+#define SONIC_TCR_COLLISIONS_MASK ((USHORT)(0xf800))
+#define SONIC_TCR_COLLISIONS_SHIFT 11
+
+
+//
+// Constants for the SONIC_INTERRUPT_MASK and
+// SONIC_INTERRUPT_STATUS registers.
+//
+
+#define SONIC_INT_BUS_RETRY ((USHORT)(0x4000))
+#define SONIC_INT_HEARTBEAT_LOST ((USHORT)(0x2000))
+#define SONIC_INT_LOAD_CAM_DONE ((USHORT)(0x1000))
+#define SONIC_INT_PROG_INTERRUPT ((USHORT)(0x0800))
+#define SONIC_INT_PACKET_RECEIVED ((USHORT)(0x0400))
+#define SONIC_INT_PACKET_TRANSMITTED ((USHORT)(0x0200))
+#define SONIC_INT_TRANSMIT_ERROR ((USHORT)(0x0100))
+#define SONIC_INT_TIMER_COMPLETE ((USHORT)(0x0080))
+#define SONIC_INT_RECEIVE_DESCRIPTORS ((USHORT)(0x0040))
+#define SONIC_INT_RECEIVE_BUFFERS ((USHORT)(0x0020))
+#define SONIC_INT_RECEIVE_OVERFLOW ((USHORT)(0x0010))
+#define SONIC_INT_CRC_TALLY_ROLLOVER ((USHORT)(0x0008))
+#define SONIC_INT_FAE_TALLY_ROLLOVER ((USHORT)(0x0004))
+#define SONIC_INT_MP_TALLY_ROLLOVER ((USHORT)(0x0002))
+
+//
+// By default, the interrupts we unmask.
+//
+
+#define SONIC_INT_DEFAULT_VALUE ((USHORT) \
+ (SONIC_INT_BUS_RETRY | \
+ SONIC_INT_LOAD_CAM_DONE | \
+ SONIC_INT_PROG_INTERRUPT | \
+ SONIC_INT_PACKET_RECEIVED | \
+ SONIC_INT_PACKET_TRANSMITTED | \
+ SONIC_INT_TRANSMIT_ERROR | \
+ SONIC_INT_RECEIVE_DESCRIPTORS | \
+ SONIC_INT_RECEIVE_BUFFERS | \
+ SONIC_INT_RECEIVE_OVERFLOW | \
+ SONIC_INT_CRC_TALLY_ROLLOVER | \
+ SONIC_INT_FAE_TALLY_ROLLOVER | \
+ SONIC_INT_MP_TALLY_ROLLOVER))
+
+//
+// The interrupts we acknowledge immediately.
+//
+
+#define SONIC_INT_IMMEDIATE_ACK ((USHORT) \
+ (SONIC_INT_DEFAULT_VALUE & \
+ ~(SONIC_INT_RECEIVE_DESCRIPTORS | \
+ SONIC_INT_RECEIVE_BUFFERS)))
+
+
+
+//
+// The maximum number of fragments that a transmit descriptor
+// can hold. If a packet has more than this, we have to merge
+// it into a single buffer before we transmit it. Increasing
+// this will prevent us from merging packets with more fragments
+// (which are rare) but use more memory in our transmit descriptors
+// (which are permanently allocated). For every one that we
+// increase this, memory usage goes up by 12 bytes in each
+// descriptor.
+//
+
+#define SONIC_MAX_FRAGMENTS 4
+
+
+//
+// The smallest size that a fragment can be. This is due to
+// their potentially being underrun problems if a fragment
+// shorted than this is transmitted. If a packet has a fragment
+// that is too short, we merge it into a single buffer before
+// we transmit it. This should not change unless the hardware
+// changes in some way.
+//
+
+#define SONIC_MIN_FRAGMENT_SIZE 12
+
+
+//
+// The smallest Ethernet packet size. Packets smaller than this
+// have blanks appended to pad them out to this length.
+//
+
+#define SONIC_MIN_PACKET_SIZE 60
+
+
+//
+// The number of entries in the CAM. The CAM (Content Addressable
+// Memory) holds the directed and multicast addresses that we
+// monitor. We reserve one of these spots for our directed address,
+// allowing us SONIC_CAM_ENTRIES - 1 multicast addresses. Changing
+// this allows us to handle more multicast addresses without
+// forcing the protocol into "all multicast" mode, but allocates
+// more memory in the CAM (16 bytes per entry).
+//
+
+#define SONIC_CAM_ENTRIES 16
+
+
+//
+// The number of transmit descriptors in the ring we allocate,
+// each of which can hold SONIC_MAX_FRAGMENTS fragments.
+// The size of a transmit descriptor is ~100 bytes, varying
+// based on SONIC_MAX_FRAGMENTS.
+//
+
+#define SONIC_NUMBER_OF_TRANSMIT_DESCRIPTORS 5
+
+
+//
+// The number and size of the receive buffers we allocate,
+// which hold the actual data received off the network. Increasing
+// this allows us to receive more large packets, but the
+// number of receive descriptors also needs to be increased.
+//
+
+#define SONIC_NUMBER_OF_RECEIVE_BUFFERS 10
+#define SONIC_SIZE_OF_RECEIVE_BUFFERS 4000
+
+
+//
+// This seems to have to be a multiple of four
+// (not just two). When there is less than this
+// amount left in a Receive Buffer after packet
+// reception, the sonic will use the next
+// ReceiveBuffer for the next packet. We define it
+// larger than the maximum Ethernet packet size,
+// so we never get a buffer overflow.
+//
+
+#define SONIC_END_OF_BUFFER_COUNT 1520
+
+//
+// ERRATA: This is the amount we have to add to
+// the EOBC value to account for the bug in revision
+// C of the chip, which decrements the RBWC registers
+// by two words (four bytes) less than they should be
+// on each packet reception. To handle this we
+// overestimate EOBC by four bytes times the maximum
+// number of packets we could receive in a buffer.
+//
+
+#define SONIC_EOBC_REV_C_CORRECTION ((SONIC_SIZE_OF_RECEIVE_BUFFERS / 64) * 4)
+
+
+//
+// The number of receive descriptors we allocate, which hold
+// pointers to packets received in the receive buffers. This
+// is now kept at twice the number of receive buffers since
+// two full-size packets can be received into each receive
+// buffer.
+//
+
+#define SONIC_NUMBER_OF_RECEIVE_DESCRIPTORS 20
+
+
+//
+// The small, medium and large buffers are used for merging
+// packets that violate our constraints (two many fragments,
+// fragments too small). The packet is merged into the smallest
+// buffer that can hold it. These should not be increased unless
+// there is a problem with many packets being merged; in that
+// case it might be better to increase SONIC_MAX_FRAGMENTS
+// first (if the problem is too many fragments).
+//
+
+#define SONIC_SMALL_BUFFER_SIZE ((UINT)64)
+#define SONIC_MEDIUM_BUFFER_SIZE ((UINT)256)
+#define SONIC_LARGE_BUFFER_SIZE ((UINT)1514)
+
+#define SONIC_NUMBER_OF_SMALL_BUFFERS ((UINT)10)
+#define SONIC_NUMBER_OF_MEDIUM_BUFFERS ((UINT)10)
+#define SONIC_NUMBER_OF_LARGE_BUFFERS ((UINT)3)
+
+
+//
+// This bit in a link field signifies "end of list" to the
+// sonic.
+//
+
+#define SONIC_END_OF_LIST 0x01
+
+
+//
+// These are used in the InUse field of Receive Descriptors.
+//
+
+#define SONIC_OWNED_BY_SYSTEM 0x00
+#define SONIC_OWNED_BY_SONIC 0x01
+
+
+//
+// This type defines the physical addresses used by the Sonic
+// chip itself. This should always be four bytes.
+//
+
+typedef ULONG SONIC_PHYSICAL_ADDRESS, *PSONIC_PHYSICAL_ADDRESS;
+
+
+
+//
+// Describes a Receive Buffer Area; the Receive Resource
+// Area is an array of these structures. In 32-bit mode the
+// upper 16 bits of all the elements are not used.
+//
+
+typedef struct _SONIC_RECEIVE_RESOURCE {
+
+ //
+ // Pointer to the receive buffer. It must be
+ // longword (4 bytes) aligned.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowBufferAddress;
+ SONIC_PHYSICAL_ADDRESS HighBufferAddress;
+
+ //
+ // The number of WORDS in the receive buffer.
+ //
+
+ UINT LowBufferWordCount;
+ UINT HighBufferWordCount;
+
+} SONIC_RECEIVE_RESOURCE, * PSONIC_RECEIVE_RESOURCE;
+
+
+//
+// A receive descriptor; the Receive Descriptor Area is a
+// linked list of these structures.
+//
+
+typedef struct _SONIC_RECEIVE_DESCRIPTOR {
+
+ //
+ // After reception this field will contain the contents
+ // of the SONIC_RECEIVE_CONTROL register. Bits 8-0 are
+ // status bits.
+ //
+
+ UINT ReceiveStatus;
+
+ //
+ // The length of the packet (including the CRC field).
+ //
+
+ UINT ByteCount;
+
+ //
+ // A pointer to the location in the RBA where the packet
+ // resides. A packet is always received into a contiguous
+ // piece of memory.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowPacketAddress;
+ SONIC_PHYSICAL_ADDRESS HighPacketAddress;
+
+ //
+ // Contains the RBA and packet sequence number.
+ //
+
+ UINT SequenceNumber;
+
+ //
+ // A link to the next receive descriptor. This is set up
+ // at initialization and is not modified by the SONIC.
+ // The low bit is the EOL bit, indicating the end of
+ // the linked list of receive descriptors.
+ //
+
+ SONIC_PHYSICAL_ADDRESS Link;
+
+ //
+ // Denotes the ownership of this receive descriptor.
+ // 0 = driver, non-zero = SONIC.
+ //
+
+ UINT InUse;
+
+} SONIC_RECEIVE_DESCRIPTOR, * PSONIC_RECEIVE_DESCRIPTOR;
+
+
+
+//
+// Describes a fragment of a packet.
+//
+
+typedef struct _SONIC_TRANSMIT_FRAGMENT {
+
+ //
+ // A pointer to the fragment. May be aligned on any
+ // byte boundary.
+ //
+
+ SONIC_PHYSICAL_ADDRESS LowFragmentAddress;
+ SONIC_PHYSICAL_ADDRESS HighFragmentAddress;
+
+ //
+ // The size of the fragment.
+ //
+
+ UINT FragmentByteCount;
+
+} SONIC_TRANSMIT_FRAGMENT, * PSONIC_TRANSMIT_FRAGMENT;
+
+
+//
+// A transmit descriptor for a packet (containing up to
+// SONIC_MAX_PACKET_FRAGMENTS pieces); the Transmit
+// Descriptor Area is a linked list of these structures.
+// If there are fewer than SONIC_MAX_PACKET_FRAGMENTS
+// pieces, then the Link field will not be used and
+// the link value will instead be put in
+// PacketFragments[FragmentCount].FragmentPointerLsb;
+// however at initialization the value will be put in
+// Link and that is the value that must be used.
+//
+
+typedef struct _SONIC_TRANSMIT_DESCRIPTOR {
+
+ //
+ // Contains the status after transmission. The status
+ // is bits 10-0 of the SONIC_TRANSMIT_CONTROL register.
+ //
+
+ UINT TransmitStatus;
+
+ //
+ // Before transmission, bits 15-12 of this field are
+ // copied into the SONIC_TRANSMIT_CONTROL register.
+ //
+
+ UINT TransmitConfiguration;
+
+ //
+ // The size of the packet to be transmitted, in bytes.
+ //
+
+ UINT PacketSize;
+
+ //
+ // The number of fragments in the packet.
+ //
+
+ UINT FragmentCount;
+
+ //
+ // Location and size of each fragment.
+ //
+
+ SONIC_TRANSMIT_FRAGMENT Fragments[SONIC_MAX_FRAGMENTS];
+
+ //
+ // A pointer to the next Transmit Descriptor. This will
+ // be set at initialization time and will not change.
+ // However, its value will be copied into the beginning
+ // of the first unused Fragments[] structure if FragmentCount
+ // is less than SONIC_MAX_FRAGMENTS (since the Link field
+ // must follow the last fragment descriptor).
+ //
+
+ SONIC_PHYSICAL_ADDRESS Link;
+
+} SONIC_TRANSMIT_DESCRIPTOR, * PSONIC_TRANSMIT_DESCRIPTOR;
+
+
+
+//
+// Describes an entry in the CAM Descriptor Area.
+//
+
+typedef struct _SONIC_CAM_FRAGMENT {
+
+ //
+ // The index (0-15) of the CAM entry
+ //
+
+ UINT CamEntryPointer;
+
+ //
+ // The Ethernet address, divided into three pieces in
+ // order from most significant to least significant.
+ // In each piece only the low-order 16 bits are
+ // used. I.e., for an Ethernet address 01-02-03-04-05-06,
+ // CamAddressPort0 would be 0x0102, CamAddressPort1
+ // would be 0x0304, and CamAddressPort2 would be 0x0506.
+ //
+
+ UINT CamAddressPort0;
+ UINT CamAddressPort1;
+ UINT CamAddressPort2;
+
+} SONIC_CAM_FRAGMENT, * PSONIC_CAM_FRAGMENT;
+
+
+
+//
+// The entire CAM Descriptor Area. In general, the CamEnable
+// field is not needed; the value will be stored in the
+// CamEntryPointer of the SONIC_CAM_FRAGMENT after the last
+// one used. However, the current value will also be
+// maintained in CamEnable.
+//
+
+typedef struct _SONIC_CAM_DESCRIPTOR_AREA {
+
+ //
+ // Holds the index and value of each of the entries.
+ //
+
+ SONIC_CAM_FRAGMENT CamFragments[SONIC_CAM_ENTRIES];
+
+ //
+ // A bit mask indicating which of the entries are enabled
+ // (only the low 16 bits are used).
+ //
+
+ UINT CamEnable;
+
+} SONIC_CAM_DESCRIPTOR_AREA, * PSONIC_CAM_DESCRIPTOR_AREA;
+
+
+
+//
+// Identifies the AdapterType values that the driver supports.
+//
+
+#define SONIC_ADAPTER_TYPE_EISA 1
+#define SONIC_ADAPTER_TYPE_INTERNAL 2
+
+
+//
+// Macros to get MSB and LSB of an address.
+//
+
+#define SONIC_GET_LOW_PART_ADDRESS(Adr) ((USHORT)((Adr) & 0xffff))
+#define SONIC_GET_HIGH_PART_ADDRESS(Adr) ((USHORT)(((Adr) & 0xffff0000) >> 16))
+
+
+//
+// Set up a SONIC_CAM_FRAGMENT given the entry pointer and
+// Ethernet address.
+//
+// Cfp is a pointer to a CAM Fragment.
+//
+// Ep is the entry pointer.
+//
+// Addr is the Ethernet address.
+//
+
+#define SONIC_LOAD_CAM_FRAGMENT(Cfp, Ep, Addr) \
+{ \
+ PSONIC_CAM_FRAGMENT _Cfp = (Cfp); \
+ UINT _Ep = (Ep); \
+ PVOID _Addr = (Addr); \
+ _Cfp->CamEntryPointer = _Ep; \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort0), (ULONG)(((PUSHORT)Addr)[0])); \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort1), (ULONG)(((PUSHORT)Addr)[1])); \
+ NdisWriteRegisterUlong((PULONG)(&_Cfp->CamAddressPort2), (ULONG)(((PUSHORT)Addr)[2])); \
+}
+
+
+//
+// Set up a SONIC_CAM_FRAGMENT to hold the CamEnable value
+// in it.
+//
+// Cfp is a pointer to the CAM Fragment.
+//
+// Ce is the value for CAM Enable.
+//
+
+#define SONIC_LOAD_CAM_ENABLE(_Cfp, _Ce) \
+ NdisWriteRegisterUlong((PULONG)(&(_Cfp)->CamEntryPointer), (ULONG)(_Ce))
+
+
+//
+// Set a link field to be the end of a list.
+//
+// Plink is a pointer to a link field.
+//
+
+#define SONIC_SET_END_OF_LIST(Plink) \
+ { \
+ ULONG _Data; \
+ NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \
+ NdisWriteRegisterUlong((PULONG)(Plink),(ULONG)(_Data | SONIC_END_OF_LIST)); \
+ }
+
+//
+// Set a link field to not be the end of a list.
+//
+// Plink is a pointer to a link field.
+//
+
+#define SONIC_REMOVE_END_OF_LIST(Plink) \
+ { \
+ ULONG _Data; \
+ NdisReadRegisterUlong((PULONG)(Plink), (PULONG)(&_Data)); \
+ NdisWriteRegisterUlong((PULONG)(Plink), (ULONG)(_Data & ~SONIC_END_OF_LIST)); \
+ }
+
+//
+// Used to set the address of a transmit descriptor fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Adr is a *physical* address.
+//
+
+#define SONIC_SET_TRANSMIT_FRAGMENT_ADDRESS(Tdf,Adr) \
+{ \
+ SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \
+ PSONIC_TRANSMIT_FRAGMENT _Tdf = (Tdf); \
+ _Tdf->LowFragmentAddress = (SONIC_PHYSICAL_ADDRESS)_Adr; \
+ _Tdf->HighFragmentAddress = (SONIC_PHYSICAL_ADDRESS)(SONIC_GET_HIGH_PART_ADDRESS(_Adr)); \
+}
+
+
+//
+// Used to retrieve the address of a transmit descriptor fragment.
+// It takes advantage of the fact that we store the entire address
+// at LowFragmentAddress, not just the low bits.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+#define SONIC_GET_TRANSMIT_FRAGMENT_ADDRESS(Tdf) \
+ (Tdf)->LowFragmentAddress
+
+
+//
+// Used to set the length of the transmit descriptor fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Len is the unsigned short length of the buffer.
+//
+#define SONIC_SET_TRANSMIT_FRAGMENT_LENGTH(Tdf,Len) \
+ (Tdf)->FragmentByteCount = (UINT)(Len)
+
+
+//
+// Used to put the link field on top of a transmit descriptor
+// fragment.
+//
+// Tdf is a pointer to a transmit descriptor fragment.
+//
+// Link is the link field to copy.
+//
+#define SONIC_SET_TRANSMIT_LINK(Tdf,Link) \
+ NdisWriteRegisterUlong((PULONG)(&(Tdf)->LowFragmentAddress), (ULONG)((Link) | SONIC_END_OF_LIST))
+
+
+
+//
+// Used to set the address of a receive resource.
+//
+// Rrp is a pointer to a receive resource.
+//
+// Adr is a *physical* address.
+//
+#define SONIC_SET_RECEIVE_RESOURCE_ADDRESS(Rrp,Adr) \
+{ \
+ SONIC_PHYSICAL_ADDRESS _Adr = (Adr); \
+ PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferAddress), (ULONG)(_Adr)); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferAddress), (ULONG)(SONIC_GET_HIGH_PART_ADDRESS(_Adr))); \
+}
+
+
+//
+// Used to retrieve the address of a receive resource.
+// It takes advantage of the fact that we store the entire address
+// at LowBufferAddress, not just the low bits.
+//
+// Rrp is a pointer to a receive resource.
+//
+#define SONIC_GET_RECEIVE_RESOURCE_ADDRESS(Rrp) \
+ (Rrp)->LowBufferAddress
+
+
+//
+// Used to set the length of a receive resource.
+//
+// Rrp is a pointer to a receive resource.
+//
+// Len is the length of the buffer.
+//
+#define SONIC_SET_RECEIVE_RESOURCE_LENGTH(Rrp,Len) \
+{ \
+ ULONG _Len = (Len); \
+ PSONIC_RECEIVE_RESOURCE _Rrp = (Rrp); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->LowBufferWordCount), (ULONG)(((_Len) & 0x1ffff) >> 1)); \
+ NdisWriteRegisterUlong((PULONG)(&_Rrp->HighBufferWordCount), (ULONG)((_Len) >> 17)); \
+}
+
+
+#endif // _SONICHARDWARE_
+
diff --git a/private/ntos/ndis/sonic/sonicsft.h b/private/ntos/ndis/sonic/sonicsft.h
new file mode 100644
index 000000000..24967e32c
--- /dev/null
+++ b/private/ntos/ndis/sonic/sonicsft.h
@@ -0,0 +1,1039 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ sonicsft.h
+
+Abstract:
+
+ The main header for a SONIC NDIS driver.
+
+ The overall structure is taken from the Lance driver
+ by Tony Ercolano.
+
+Author:
+
+ Anthony V. Ercolano (tonye) creation-date 19-Jun-1990
+ Adam Barr (adamba) 20-Nov-1990
+
+Environment:
+
+ This driver is expected to work in DOS, OS2 and NT at the equivalent
+ of kernel mode.
+
+ Architecturally, there is an assumption in this driver that we are
+ on a little endian machine.
+
+Revision History:
+
+
+--*/
+
+#ifndef _SONICSFT_
+#define _SONICSFT_
+
+
+//
+// We use STATIC to define procedures that will be static in the
+// final build but which we now make extern to allow them to be
+// debugged (breakpoints can be set on them).
+//
+
+#if DEVL
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+
+//
+// This variable is used to control debug output.
+//
+
+#if DBG
+extern INT SonicDbg;
+#endif
+
+
+
+//
+// Used when registering ourselves with NDIS.
+//
+
+#define SONIC_NDIS_MAJOR_VERSION 3
+#define SONIC_NDIS_MINOR_VERSION 0
+
+
+//
+// The maximum number of bytes that we will pass to an NDIS
+// indication (since we receive packets contiguously, there is
+// no reason to limit this). This number includes header and
+// data.
+//
+
+#define SONIC_INDICATE_MAXIMUM 1514
+
+//
+// The maximum number of bytes we will pass to a loopback
+// indication (unless it all is in one buffer). This number
+// includes only data, not the header.
+//
+
+#define SONIC_LOOPBACK_MAXIMUM 208
+
+//
+// Used for parsing OIDs
+//
+
+#define OID_TYPE_MASK 0xffff0000
+#define OID_TYPE_GENERAL_OPERATIONAL 0x00010000
+#define OID_TYPE_GENERAL_STATISTICS 0x00020000
+#define OID_TYPE_802_3_OPERATIONAL 0x01010000
+#define OID_TYPE_802_3_STATISTICS 0x01020000
+
+#define OID_REQUIRED_MASK 0x0000ff00
+#define OID_REQUIRED_MANDATORY 0x00000100
+#define OID_REQUIRED_OPTIONAL 0x00000200
+
+#define OID_INDEX_MASK 0x000000ff
+
+//
+// Indexes in the GeneralMandatory array.
+//
+
+#define GM_TRANSMIT_GOOD 0x00
+#define GM_RECEIVE_GOOD 0x01
+#define GM_TRANSMIT_BAD 0x02
+#define GM_RECEIVE_BAD 0x03
+#define GM_RECEIVE_NO_BUFFER 0x04
+#define GM_ARRAY_SIZE 0x05
+
+//
+// Indexes in the GeneralOptional array. There are
+// two sections, the ones up to COUNT_ARRAY_SIZE
+// have entries for number (4 bytes) and number of
+// bytes (8 bytes), the rest are a normal array.
+//
+
+#define GO_DIRECTED_TRANSMITS 0x00
+#define GO_MULTICAST_TRANSMITS 0x01
+#define GO_BROADCAST_TRANSMITS 0x02
+#define GO_DIRECTED_RECEIVES 0x03
+#define GO_MULTICAST_RECEIVES 0x04
+#define GO_BROADCAST_RECEIVES 0x05
+#define GO_COUNT_ARRAY_SIZE 0x06
+
+#define GO_ARRAY_START 0x0C
+#define GO_RECEIVE_CRC 0x0C
+#define GO_TRANSMIT_QUEUE_LENGTH 0x0D
+#define GO_ARRAY_SIZE 0x0E
+
+//
+// Indexes in the MediaMandatory array.
+//
+
+#define MM_RECEIVE_ERROR_ALIGNMENT 0x00
+#define MM_TRANSMIT_ONE_COLLISION 0x01
+#define MM_TRANSMIT_MORE_COLLISIONS 0x02
+#define MM_ARRAY_SIZE 0x03
+
+//
+// Indexes in the MediaOptional array.
+//
+
+#define MO_TRANSMIT_DEFERRED 0x00
+#define MO_TRANSMIT_MAX_COLLISIONS 0x01
+#define MO_RECEIVE_OVERRUN 0x02
+#define MO_TRANSMIT_UNDERRUN 0x03
+#define MO_TRANSMIT_HEARTBEAT_FAILURE 0x04
+#define MO_TRANSMIT_TIMES_CRS_LOST 0x05
+#define MO_TRANSMIT_LATE_COLLISIONS 0x06
+#define MO_ARRAY_SIZE 0x07
+
+
+
+//
+// Macros used for memory allocation and deallocation.
+//
+// Note that for regular memory we put no limit on the physical
+// address, but for contiguous and noncached we limit it to
+// 32 bits since that is all the card can handle (presumably
+// such memory will be DMAed to/from by the card).
+//
+
+#define SONIC_ALLOC_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ 0, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ 0 \
+ )
+
+
+#define SONIC_ALLOC_CONTIGUOUS_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_CONTIGUOUS_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS \
+ )
+
+
+#define SONIC_ALLOC_NONCACHED_MEMORY(_Status, _Address, _Length) \
+ { \
+ NDIS_PHYSICAL_ADDRESS Temp = NDIS_PHYSICAL_ADDRESS_CONST(-1, 0); \
+ *(_Status) = NdisAllocateMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED, \
+ Temp \
+ ); \
+ }
+
+#define SONIC_FREE_NONCACHED_MEMORY(_Address, _Length) \
+ NdisFreeMemory( \
+ (PVOID)(_Address), \
+ (_Length), \
+ NDIS_MEMORY_CONTIGUOUS | NDIS_MEMORY_NONCACHED \
+ )
+
+
+
+//
+// Macros to move and zero memory.
+//
+
+#define SONIC_MOVE_MEMORY(Destination,Source,Length) NdisMoveMemory(Destination,Source,Length)
+#define SONIC_ZERO_MEMORY(Destination,Length) NdisZeroMemory(Destination,Length)
+
+
+//
+// Used to record the 8-byte counters.
+//
+
+typedef struct _SONIC_LARGE_INTEGER {
+ ULONG LowPart;
+ ULONG HighPart;
+} SONIC_LARGE_INTEGER, *PSONIC_LARGE_INTEGER;
+
+//
+// This initializes an 8-byte counter.
+//
+
+#define SonicZeroLargeInteger(LargeInteger) \
+{ \
+ LargeInteger.LowPart = 0L;\
+ LargeInteger.HighPart = 0L; \
+}
+
+//
+// This adds a longword to an 8-byte counter.
+//
+
+#define SonicAddUlongToLargeInteger(LargeInteger, Ulong) \
+{ \
+ PSONIC_LARGE_INTEGER TmpLarge = (LargeInteger); \
+ TmpLarge->LowPart += (ULONG)Ulong; \
+ if (TmpLarge->LowPart < (ULONG)Ulong) { \
+ ++TmpLarge->HighPart; \
+ } \
+}
+
+
+
+//
+// This flushes a buffer for write.
+//
+
+#define SONIC_FLUSH_WRITE_BUFFER(Buffer) \
+ NdisFlushBuffer( \
+ Buffer, \
+ TRUE \
+ )
+
+
+//
+// This record type is used to store sonic global data.
+//
+
+typedef struct _SONIC_DRIVER {
+
+ //
+ // The handle returned by NdisMInitializeWrapper.
+ //
+
+ NDIS_HANDLE WrapperHandle;
+
+} SONIC_DRIVER, *PSONIC_DRIVER;
+
+
+//
+// This identifies the type of the packet for quick reference
+// in the SONIC_PACKET_RESERVED.PacketType field.
+//
+
+#define SONIC_DIRECTED 1
+#define SONIC_MULTICAST 2
+#define SONIC_BROADCAST 3
+#define SONIC_LOOPBACK 4
+
+
+//
+// This record type is inserted into the MiniportReserved portion
+// of the packet header.
+//
+typedef struct _SONIC_PACKET_RESERVED {
+
+ //
+ // Points to the next packet in the chain of queued packets
+ // being allocated, or waiting for the finish of transmission.
+ //
+ // The packet will either be on the stage list for allocation,
+ // or on an adapter wide doubly linked list (see below) for
+ // post transmission processing.
+ //
+ PNDIS_PACKET Next;
+
+ //
+ // If TRUE then the packet caused an adapter buffer to
+ // be allocated.
+ //
+ BOOLEAN UsedSonicBuffer;
+
+ //
+ // If the previous field was TRUE then this gives the
+ // index into the array of adapter buffer descriptors that
+ // contains the old packet information.
+ //
+ UCHAR SonicBuffersIndex;
+
+ //
+ // Gives the index into the ring to packet structure as well
+ // as the ring descriptors.
+ //
+ USHORT DescriptorIndex;
+
+} SONIC_PACKET_RESERVED,*PSONIC_PACKET_RESERVED;
+
+
+//
+// This macro will return a pointer to the sonic reserved portion
+// of a packet given a pointer to a packet.
+//
+#define PSONIC_RESERVED_FROM_PACKET(Packet) \
+ ((PSONIC_PACKET_RESERVED)((PVOID)((Packet)->MiniportReserved)))
+
+
+//
+// The return code from a multicast operation.
+//
+typedef enum { CAM_LOADED, CAM_NOT_LOADED } MULTICAST_STATUS;
+
+
+//
+// This structure is used to map entries in the ring descriptors
+// back to the packets from which the data in the ring descriptor
+// originated.
+//
+
+typedef struct _SONIC_DESCRIPTOR_TO_PACKET {
+
+ //
+ // Points to the packet from which data is being transmitted
+ // through this ring entry.
+ //
+ PNDIS_PACKET OwningPacket;
+
+ //
+ // Location of our link field.
+ //
+ SONIC_PHYSICAL_ADDRESS * LinkPointer;
+
+ //
+ // Location of the previous link field.
+ //
+ SONIC_PHYSICAL_ADDRESS * PrevLinkPointer;
+
+ //
+ // When a packet is submitted to the hardware we record
+ // here whether it used adapter buffers and if so, the buffer
+ // index.
+ //
+ UINT SonicBuffersIndex;
+ BOOLEAN UsedSonicBuffer;
+
+} SONIC_DESCRIPTOR_TO_PACKET,*PSONIC_DESCRIPTOR_TO_PACKET;
+
+
+//
+// If an ndis packet does not meet the hardware contraints then
+// an adapter buffer will be allocated. Enough data will be copied
+// out of the ndis packet so that by using a combination of the
+// adapter buffer and remaining ndis buffers the hardware
+// constraints are satisfied.
+//
+// In the SONIC_ADAPTER structure three threaded lists are kept in
+// one array. One points to a list of SONIC_BUFFER_DESCRIPTORS
+// that point to small adapter buffers. Another is for medium sized
+// buffers and the last for full sized (large) buffers.
+//
+// The allocation is controlled via a free list head and
+// the free lists are "threaded" by a field in the adapter buffer
+// descriptor.
+//
+
+typedef struct _SONIC_BUFFER_DESCRIPTOR {
+
+ //
+ // A Physical pointer to a small, medium, or large buffer.
+ //
+ NDIS_PHYSICAL_ADDRESS PhysicalSonicBuffer;
+
+ //
+ // A virtual pointer to a small, medium, or large buffer.
+ //
+ PVOID VirtualSonicBuffer;
+
+ //
+ // This is used to flush the buffer when it is used.
+ //
+ PNDIS_BUFFER FlushBuffer;
+
+ //
+ // Threads the elements of an array of these descriptors into
+ // a free list. -1 implies no more entries in the list.
+ //
+ INT Next;
+
+ //
+ // Holds the length of data placed into the buffer. This
+ // can (and likely will) be less that the actual buffers
+ // length.
+ //
+ UINT DataLength;
+
+} SONIC_BUFFER_DESCRIPTOR,*PSONIC_BUFFER_DESCRIPTOR;
+
+
+//
+// This is the basic structure that defines the state of an
+// adapter. There is one of these allocate per adapter that
+// the sonic driver supports.
+//
+
+typedef struct _SONIC_ADAPTER {
+
+ //
+ // Will be true the first time that the hardware is initialized
+ // by the driver initialization.
+ //
+ BOOLEAN FirstInitialization;
+
+ //
+ // The type of the adapter; current supported values are:
+ //
+ // 1: EISA 9010E/B card from National Semiconductor
+ // 2: Sonic chip on the MIPS R4000 motherbaord.
+ //
+ UCHAR AdapterType;
+
+ //
+ // TRUE if the permanent address is valid. On some cards the
+ // permanent address is read by SonicHardwareGetDetails;
+ // if not, it is read later by SonicHardwareGetAddress.
+ //
+ BOOLEAN PermanentAddressValid;
+
+ //
+ // The burned-in network address from the hardware.
+ //
+ CHAR PermanentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // The current network address from the hardware.
+ //
+ CHAR CurrentNetworkAddress[ETH_LENGTH_OF_ADDRESS];
+
+ //
+ // This is the buffer pool used to allocate flush buffers
+ // out of.
+ //
+ NDIS_HANDLE FlushBufferPoolHandle;
+
+ //
+ // Holds the interrupt object for this adapter.
+ //
+ NDIS_MINIPORT_INTERRUPT Interrupt;
+
+ //
+ // TRUE if the adapter is latched, FALSE for level-sensitive.
+ //
+ BOOLEAN InterruptLatched;
+
+ //
+ // Holds a value for simulating an interrupt.
+ //
+ USHORT SimulatedIsr;
+
+ //
+ // The current value to put in the Receive Control Register.
+ //
+ USHORT ReceiveControlRegister;
+
+ //
+ // The value that the Data Configuration Register should be
+ // initialized to.
+ //
+ USHORT DataConfigurationRegister;
+
+ //
+ // Have we receive an unacknowledged Receive Buffers
+ // Exhausted interrupt.
+ //
+ BOOLEAN ReceiveBuffersExhausted;
+
+ //
+ // Have we receive an unacknowledged Receive Descriptors
+ // Exhausted interrupt.
+ //
+ BOOLEAN ReceiveDescriptorsExhausted;
+
+ //
+ // Flag used for checking if a transmit interrupt was dropped.
+ //
+ BOOLEAN WakeUpTimeout;
+
+ //
+ // Used to limit the number of error log entries written.
+ //
+ UCHAR WakeUpErrorCount;
+
+ //
+ // Location of the beginning of the SONIC ports.
+ //
+ ULONG SonicPortAddress;
+
+ //
+ // Number of ports in use
+ //
+ UINT NumberOfPorts;
+
+ //
+ // Hardware address of the first port.
+ //
+ UINT InitialPort;
+
+ //
+ // The number of bits that port numbers need to be shifted left
+ // before adding them to PortAddress (1 for 16-bit ports, 2
+ // for 32-bit ports).
+ //
+ UINT PortShift;
+
+ //
+ // The virtual address of the blank buffer used for padding.
+ //
+ PUCHAR BlankBuffer;
+
+ //
+ // The Physical address of the blank buffer used for padding.
+ //
+ NDIS_PHYSICAL_ADDRESS BlankBufferAddress;
+
+ //
+ // Handle given by NDIS when the adapter was registered.
+ //
+ NDIS_HANDLE MiniportAdapterHandle;
+
+ //
+ // The current packet filter.
+ //
+ UINT CurrentPacketFilter;
+
+ //
+ // The value of the bits in CamEnable, except for
+ // the first one (which is for our network address);
+ // as opposed to the value stored in the real CamEnable,
+ // which may have some bits off if multicast addresses
+ // are not included in the current packet filter.
+ //
+ UINT MulticastCamEnableBits;
+
+ //
+ // The number of transmit descriptors.
+ //
+ UINT NumberOfTransmitDescriptors;
+
+ //
+ // The number of receive buffers
+ //
+ UINT NumberOfReceiveBuffers;
+
+ //
+ // The number of receive descriptors
+ //
+ UINT NumberOfReceiveDescriptors;
+
+ //
+ // Pointer to the transmit descriptors (this is
+ // allocated to be of size NumberOfTransmitDescriptors).
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmitDescriptorArea;
+
+ //
+ // The physical address of the transmit descriptor area.
+ //
+ NDIS_PHYSICAL_ADDRESS TransmitDescriptorAreaPhysical;
+
+ //
+ // Pointer to the last transmit descriptor.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR LastTransmitDescriptor;
+
+ //
+ // Counter that records the number of transmit rings currently
+ // available for allocation.
+ //
+ UINT NumberOfAvailableDescriptors;
+
+ //
+ // This is used to determine whether to use the programmable
+ // interrupt on a packet or not.
+ //
+ UINT PacketsSinceLastInterrupt;
+
+ //
+ // Pointer to transmit descriptor ring entry that is the
+ // first ring entry available for allocation of transmit
+ // buffers.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR AllocateableDescriptor;
+
+ //
+ // Pointer to a transmit descriptor ring entry that is the
+ // first ring entry that the MAC currently has made available
+ // for transmission.
+ //
+ // Can only be accessed when the adapter lock
+ // is held.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR TransmittingDescriptor;
+
+ //
+ // Pointer to the first packet that has been allocated to
+ // a transmit packet but has not yet been relinquished to
+ // the hardware. We need this pointer to keep the transmit
+ // post processing from running into a packet that has not
+ // been transmitted.
+ //
+ PSONIC_TRANSMIT_DESCRIPTOR FirstUncommittedDescriptor;
+
+ //
+ // Pointer to an array of structs that map transmit ring entries
+ // back to a packet (this is allocated to be of size
+ // NumberOfTransmitDescriptors).
+ //
+ PSONIC_DESCRIPTOR_TO_PACKET DescriptorToPacket;
+
+ //
+ // Pointer to the receive resource area (this is
+ // allocated to be of size NumberofReceiveBuffers).
+ //
+ PSONIC_RECEIVE_RESOURCE ReceiveResourceArea;
+
+ //
+ // The physical address of ReceiveResourceArea.
+ //
+ NDIS_PHYSICAL_ADDRESS ReceiveResourceAreaPhysical;
+
+ //
+ // Pointer to the array holding the receive buffers (this
+ // is allocated to be of size NumberofReceiveBuffers).
+ //
+
+ PVOID * ReceiveBufferArea;
+
+ PNDIS_BUFFER * ReceiveNdisBufferArea;
+
+ //
+ // The RBA which we are currently taking packets out of
+ // (will be one of the entries in the ReceiveBufferArea
+ // array).
+ //
+ UINT CurrentReceiveBufferIndex;
+
+ //
+ // Pointer to the receive descriptor area
+ // (this is allocated to be of size NumberOfReceiveDescriptors).
+ //
+ PSONIC_RECEIVE_DESCRIPTOR ReceiveDescriptorArea;
+
+ //
+ // The physical address of ReceiveDescriptorArea
+ //
+ NDIS_PHYSICAL_ADDRESS ReceiveDescriptorAreaPhysical;
+
+ //
+ // The last receive descriptor in the area.
+ //
+ PSONIC_RECEIVE_DESCRIPTOR LastReceiveDescriptor;
+
+ //
+ // The index receive descriptor we should look at next (will be
+ // one of the entries in ReceiveDescriptorArea).
+ //
+ UINT CurrentReceiveDescriptorIndex;
+
+ //
+ // Pointer to the CAM descriptor area. This will be
+ // located directly after the receive resource area,
+ // the separate pointer is for convenience.
+ //
+ PSONIC_CAM_DESCRIPTOR_AREA CamDescriptorArea;
+
+ //
+ // The physical address corresponding to CamDescriptorArea.
+ // This is stored as a 4-byte address since it is just
+ // a fixed offset from ReceiveResourceAreaPhysical and
+ // is not allocated with NdisAllocateSharedMemory.
+ //
+ SONIC_PHYSICAL_ADDRESS CamDescriptorAreaPhysical;
+
+ //
+ // This is used to flush the CAM descriptor area.
+ //
+ PNDIS_BUFFER CamDescriptorAreaFlushBuffer;
+
+ //
+ // The last entry in the CAM that is used.
+ //
+ UINT CamDescriptorAreaSize;
+
+ //
+ // An bitmask showing which entries in the CAM are
+ // used or reserved for use.
+ //
+ UINT CamDescriptorsUsed;
+
+ //
+ // Pointer to the first transmitting packet that is actually
+ // sending.
+ //
+ PNDIS_PACKET FirstFinishTransmit;
+
+ //
+ // Pointer to the last transmitting packet that is actually
+ // sending.
+ //
+ PNDIS_PACKET LastFinishTransmit;
+
+ //
+ // Listheads for the adapters buffers. If the list
+ // head is equal to -1 then there are no free elements
+ // on the list.
+ //
+ // The list heads must only be accessed when the
+ // adapter lock is held.
+ //
+ // Note that the listhead at index 0 will always be -1.
+ //
+ INT SonicBufferListHeads[4];
+
+ //
+ // Pointers to an array of adapter buffer descriptors.
+ // The array will actually be threaded together by
+ // three free lists. The lists will be for small,
+ // medium and full sized packets.
+ //
+ PSONIC_BUFFER_DESCRIPTOR SonicBuffers;
+
+ //
+ // This holds the actual memory used by the small
+ // sonic buffers (so that it can be a single piece
+ // of memory and therefore only use a single physical
+ // address.
+ //
+ PVOID SmallSonicBuffers;
+
+ //
+ // This holds the memory for the medium sonic buffers.
+ //
+ PVOID MediumSonicBuffers;
+
+ //
+ // Flag that when enabled lets routines know that a reset
+ // is in progress, for the purposes of blocking other
+ // requests (except other resets).
+ //
+ BOOLEAN ResetInProgress;
+
+ //
+ // Has there been a hardware failure
+ //
+ BOOLEAN HardwareFailure;
+
+ //
+ // Count how often we log an error from finding a packet in
+ // the wrong RBA.
+ //
+
+ USHORT WrongRbaErrorLogCount;
+
+ //
+ // These hold adapter statistics.
+ //
+ ULONG GeneralMandatory[GM_ARRAY_SIZE];
+ SONIC_LARGE_INTEGER GeneralOptionalByteCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptionalFrameCount[GO_COUNT_ARRAY_SIZE];
+ ULONG GeneralOptional[GO_ARRAY_SIZE - GO_ARRAY_START];
+ ULONG MediaMandatory[MM_ARRAY_SIZE];
+ ULONG MediaOptional[MO_ARRAY_SIZE];
+
+ //
+ // For indicating loopback packets.
+ //
+
+ UCHAR Loopback[SONIC_LOOPBACK_MAXIMUM];
+
+} SONIC_ADAPTER,*PSONIC_ADAPTER;
+
+
+//
+// Given a MacContextHandle return the PSONIC_ADAPTER
+// it represents.
+//
+
+#define PSONIC_ADAPTER_FROM_CONTEXT_HANDLE(Handle) \
+ ((PSONIC_ADAPTER)((PVOID)(Handle)))
+
+
+//
+// procedures which do error logging
+//
+
+typedef enum _SONIC_PROC_ID{
+ registerAdapter,
+ openAdapter,
+ hardwareDetails,
+ handleDeferred,
+ processReceiveInterrupts
+} SONIC_PROC_ID;
+
+
+//
+// Error log values
+//
+
+#define SONIC_ERRMSG_INIT_INTERRUPT (ULONG)0x01
+#define SONIC_ERRMSG_CREATE_FILTER (ULONG)0x02
+#define SONIC_ERRMSG_ALLOC_MEMORY (ULONG)0x03
+#define SONIC_ERRMSG_REGISTER_ADAPTER (ULONG)0x04
+#define SONIC_ERRMSG_ALLOC_DEVICE_NAME (ULONG)0x05
+#define SONIC_ERRMSG_ALLOC_ADAPTER (ULONG)0x06
+#define SONIC_ERRMSG_INITIAL_INIT (ULONG)0x07
+#define SONIC_ERRMSG_OPEN_DB (ULONG)0x08
+#define SONIC_ERRMSG_ALLOC_OPEN (ULONG)0x09
+#define SONIC_ERRMSG_HARDWARE_ADDRESS (ULONG)0x0A
+#define SONIC_ERRMSG_WRONG_RBA (ULONG)0x0B
+
+
+
+
+//
+// Definitions of sonic functions which are used by multiple
+// source files.
+//
+
+
+//
+// alloc.c
+//
+
+extern
+BOOLEAN
+AllocateAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+DeleteAdapterMemory(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+
+//
+// interrup.c
+//
+
+extern
+VOID
+SonicDisableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicEnableInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicHandleInterrupt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ );
+
+extern
+VOID
+SonicInterruptService(
+ OUT PBOOLEAN InterruptRecognized,
+ OUT PBOOLEAN QueueDpc,
+ IN PVOID Context
+ );
+
+extern
+BOOLEAN
+SonicCheckForHang(
+ IN PVOID MiniportAdapterContext
+ );
+
+//
+// request.c
+//
+
+extern
+NDIS_STATUS
+SonicQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+SonicSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ );
+
+extern
+NDIS_STATUS
+SonicChangeClass(
+ IN UINT OldFilterClasses,
+ IN UINT NewFilterClasses,
+ IN NDIS_HANDLE NdisBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+extern
+NDIS_STATUS
+SonicChangeAddresses(
+ IN UINT OldAddressCount,
+ IN CHAR OldAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN UINT NewAddressCount,
+ IN CHAR NewAddresses[][ETH_LENGTH_OF_ADDRESS],
+ IN NDIS_HANDLE MacBindingHandle,
+ IN PNDIS_REQUEST NdisRequest,
+ IN BOOLEAN Set
+ );
+
+//
+// send.c
+//
+
+extern
+NDIS_STATUS
+SonicSend(
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN PNDIS_PACKET Packet,
+ IN UINT SendFlags
+ );
+
+//
+// sonic.c
+//
+
+extern
+VOID
+SonicStartChip(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+StartAdapterReset(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+SetupForReset(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+VOID
+SonicStartCamReload(
+ IN PSONIC_ADAPTER Adapter
+ );
+
+extern
+NDIS_STATUS
+SonicInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE ConfigurationHandle
+ );
+//
+// transfer.c
+//
+
+extern
+NDIS_STATUS
+SonicTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ );
+
+#endif // _SONICSFT_
diff --git a/private/ntos/ndis/sonic/sources b/private/ntos/ndis/sonic/sources
new file mode 100644
index 000000000..3f3e59baa
--- /dev/null
+++ b/private/ntos/ndis/sonic/sources
@@ -0,0 +1,61 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=ndis2
+
+TARGETNAME=sonic
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER
+
+INCLUDES=..\inc;..\..\inc
+
+SOURCES=
+
+i386_SOURCES=alloc.c \
+ interrup.c \
+ request.c \
+ send.c \
+ sonic.c \
+ sonic.rc \
+ transfer.c
+
+MIPS_SOURCES=alloc.c \
+ interrup.c \
+ request.c \
+ send.c \
+ sonic.c \
+ sonic.rc \
+ transfer.c
+
+ALPHA_SOURCES=
+
+RELATIVE_DEPTH=..\..
+
+MSC_WARNING_LEVEL=/W3 /WX
+
diff --git a/private/ntos/ndis/sonic/transfer.c b/private/ntos/ndis/sonic/transfer.c
new file mode 100644
index 000000000..403e51ee8
--- /dev/null
+++ b/private/ntos/ndis/sonic/transfer.c
@@ -0,0 +1,247 @@
+/*++
+
+Copyright (c) 1990-1992 Microsoft Corporation
+
+Module Name:
+
+ transfer.c
+
+Abstract:
+
+ This file contains the code to implement the MacTransferData
+ API for the NDIS 3.0 miniport interface.
+
+Author:
+
+ Anthony V. Ercolano (Tonye) 12-Sept-1990
+
+Environment:
+
+ Kernel Mode - Or whatever is the equivalent.
+
+Revision History:
+
+
+--*/
+
+#include <ndis.h>
+
+#include <sonichrd.h>
+#include <sonicsft.h>
+
+
+extern
+NDIS_STATUS
+SonicTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+
+/*++
+
+Routine Description:
+
+ A protocol calls the SonicTransferData request (indirectly via
+ NdisTransferData) from within its Receive event handler
+ to instruct the driver to copy the contents of the received packet
+ a specified paqcket buffer.
+
+Arguments:
+
+ MiniportAdapterContext - Context registered with the wrapper, really
+ a pointer to the adapter.
+
+ MiniportReceiveContext - The context value passed by the driver on its call
+ to NdisMEthIndicateReceive. The driver can use this value to determine
+ which packet, on which adapter, is being received.
+
+ ByteOffset - An unsigned integer specifying the offset within the
+ received packet at which the copy is to begin. If the entire packet
+ is to be copied, ByteOffset must be zero.
+
+ BytesToTransfer - An unsigned integer specifying the number of bytes
+ to copy. It is legal to transfer zero bytes; this has no effect. If
+ the sum of ByteOffset and BytesToTransfer is greater than the size
+ of the received packet, then the remainder of the packet (starting from
+ ByteOffset) is transferred, and the trailing portion of the receive
+ buffer is not modified.
+
+ Packet - A pointer to a descriptor for the packet storage into which
+ the MAC is to copy the received packet.
+
+ BytesTransfered - A pointer to an unsigned integer. The MAC writes
+ the actual number of bytes transferred into this location. This value
+ is not valid if the return status is STATUS_PENDING.
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+ //
+ // Buffer is the buffer to copy from.
+ //
+ PCHAR Buffer = (PCHAR)MiniportReceiveContext + ByteOffset;
+
+ //
+ // Holds the count of the number of ndis buffers comprising the
+ // destination packet.
+ //
+ UINT DestinationBufferCount;
+
+ //
+ // Points to the buffer into which we are putting data.
+ //
+ PNDIS_BUFFER DestinationCurrentBuffer;
+
+ //
+ // Points to the location in Buffer from which we are extracting data.
+ //
+ PUCHAR SourceCurrentAddress;
+
+ //
+ // Holds the virtual address of the current destination buffer.
+ //
+ PVOID DestinationVirtualAddress;
+
+ //
+ // Holds the length of the current destination buffer.
+ //
+ UINT DestinationCurrentLength;
+
+ //
+ // Keep a local variable of BytesTransferred so we aren't referencing
+ // through a pointer.
+ //
+ UINT LocalBytesTransferred = 0;
+
+ //
+ // MiniportAdapterContext is not referenced.
+ //
+ MiniportAdapterContext;
+
+ //
+ // Take care of boundary condition of zero length copy.
+ //
+
+ if (BytesToTransfer == 0) {
+ *BytesTransferred = 0;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ //
+ // Get the first buffer of the destination.
+ //
+
+ NdisQueryPacket(
+ Packet,
+ NULL,
+ &DestinationBufferCount,
+ &DestinationCurrentBuffer,
+ NULL
+ );
+
+ //
+ // Could have a null packet.
+ //
+
+ if (DestinationBufferCount == 0) {
+ *BytesTransferred = 0;
+ return NDIS_STATUS_SUCCESS;
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ //
+ // Set up the source address.
+ //
+
+ SourceCurrentAddress = Buffer;
+
+
+ while (LocalBytesTransferred < BytesToTransfer) {
+
+ //
+ // Check to see whether we've exhausted the current destination
+ // buffer. If so, move onto the next one.
+ //
+
+ if (DestinationCurrentLength == 0) {
+
+ NdisGetNextBuffer(
+ DestinationCurrentBuffer,
+ &DestinationCurrentBuffer
+ );
+
+ if (DestinationCurrentBuffer == NULL) {
+
+ //
+ // We've reached the end of the packet. We return
+ // with what we've done so far. (Which must be shorter
+ // than requested.)
+ //
+
+ break;
+
+ }
+
+ NdisQueryBuffer(
+ DestinationCurrentBuffer,
+ &DestinationVirtualAddress,
+ &DestinationCurrentLength
+ );
+
+ continue;
+
+ }
+
+ //
+ // Copy the data.
+ //
+
+ {
+
+ //
+ // Holds the amount of data to move.
+ //
+ UINT AmountToMove;
+
+ //
+ // Holds the amount desired remaining.
+ //
+ UINT Remaining = BytesToTransfer - LocalBytesTransferred;
+
+
+ AmountToMove = DestinationCurrentLength;
+
+ AmountToMove = ((Remaining < AmountToMove)?
+ (Remaining):(AmountToMove));
+
+ SONIC_MOVE_MEMORY(
+ DestinationVirtualAddress,
+ SourceCurrentAddress,
+ AmountToMove
+ );
+
+ SourceCurrentAddress += AmountToMove;
+ LocalBytesTransferred += AmountToMove;
+ DestinationCurrentLength -= AmountToMove;
+
+ }
+
+ }
+
+ *BytesTransferred = LocalBytesTransferred;
+ return NDIS_STATUS_SUCCESS;
+}