4270 lines
100 KiB
C
4270 lines
100 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pc586.c
|
||
|
||
Abstract:
|
||
|
||
This is the main file for the Intel PC586
|
||
Ethernet controller. This driver conforms to the NDIS 3.0 interface.
|
||
|
||
The idea for handling loopback and sends simultaneously is largely
|
||
adapted from the EtherLink II NDIS driver by Adam Barr.
|
||
|
||
Author:
|
||
Weldon Washburn (o-weldo, Intel) 30-OCT-1990 adapted from ...
|
||
|
||
Anthony V. Ercolano (Tonye) 20-Jul-1990
|
||
|
||
Environment:
|
||
|
||
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include <ntos.h>
|
||
#include <ndis.h>
|
||
#include <filter.h>
|
||
#include <pc586hrd.h>
|
||
#include <pc586sft.h>
|
||
|
||
|
||
|
||
ULONG ResetCount, SpuriousIntCount, BadRcvCount,
|
||
RcvRestartCount, RcvSuspendCount;
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586OpenAdapter(
|
||
OUT NDIS_HANDLE *MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_HANDLE NdisBindingContext,
|
||
IN NDIS_HANDLE MacAdapterContext,
|
||
IN PSTRING AddressingInformation OPTIONAL
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586CloseAdapter(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586SetPacketFilter(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN UINT PacketFilter
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586AddMulticastAddress(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequstHandle,
|
||
IN PSTRING MulticastAddress
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586DeleteMulticastAddress(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN PSTRING MulticastAddress
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586QueryInformation(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_INFORMATION_CLASS InformationClass,
|
||
OUT PVOID Buffer,
|
||
IN UINT BufferLength
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586SetInformation(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_INFORMATION_CLASS InformationClass,
|
||
IN PVOID Buffer,
|
||
IN UINT BufferLength
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586Reset(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586Test(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586ChangeClass(
|
||
IN UINT OldFilterClasses,
|
||
IN UINT NewFilterClasses,
|
||
IN NDIS_HANDLE NdisBindingContext,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN BOOLEAN Set
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586AddMulticast(
|
||
IN UINT CurrentAddressCount,
|
||
IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
|
||
IN UINT NewAddress,
|
||
IN NDIS_HANDLE NdisBindingContext,
|
||
IN NDIS_HANDLE RequestHandle
|
||
);
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586DeleteMulticast(
|
||
IN UINT CurrentAddressCount,
|
||
IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
|
||
IN CHAR OldAddress[MAC_LENGTH_OF_ADDRESS],
|
||
IN NDIS_HANDLE NdisBindingContext,
|
||
IN NDIS_HANDLE RequestHandle
|
||
);
|
||
|
||
static
|
||
VOID
|
||
Pc586CloseAction(
|
||
IN NDIS_HANDLE MacBindingHandle
|
||
);
|
||
|
||
static
|
||
VOID
|
||
ReturnAdapterResources(
|
||
IN PPC586_ADAPTER Adapter
|
||
|
||
);
|
||
|
||
static
|
||
VOID
|
||
ProcessReceiveInterrupts(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
BOOLEAN
|
||
ProcessTransmitInterrupts(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
VOID
|
||
Pc586StandardInterruptDPC(
|
||
IN PKDPC Dpc,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
);
|
||
|
||
extern
|
||
BOOLEAN
|
||
Pc586ISR(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID Context
|
||
);
|
||
|
||
static
|
||
VOID
|
||
ProcessInterrupt(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
VOID
|
||
SetInitBlockAndInit(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
VOID
|
||
StartAdapterReset(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
VOID
|
||
SetupForReset(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN PPC586_OPEN Open,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_REQUEST_TYPE RequestType
|
||
);
|
||
|
||
static
|
||
BOOLEAN
|
||
Pc586InitialInit(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
static
|
||
VOID
|
||
LoadMCAddress(
|
||
IN PPC586_ADAPTER Adapter
|
||
);
|
||
|
||
//
|
||
// ZZZ Non portable interface.
|
||
//
|
||
|
||
UINT ww_put = 0xff; // debug, set != 0 for 4 byte xfer in PutPacket();
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the primary initialization routine for the pc586 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 InitStatus;
|
||
|
||
NDIS_HANDLE NdisMacHandle;
|
||
|
||
NDIS_HANDLE NdisWrapperHandle;
|
||
|
||
char MacName[] = "PC586";
|
||
char Tmp[sizeof(NDIS_MAC_CHARACTERISTICS) + sizeof(MacName) - 1];
|
||
PNDIS_MAC_CHARACTERISTICS Pc586Char = (PNDIS_MAC_CHARACTERISTICS)Tmp;
|
||
//
|
||
// Initialize the wrapper.
|
||
//
|
||
|
||
NdisInitializeWrapper(&NdisWrapperHandle,DriverObject,NULL,NULL);
|
||
|
||
//
|
||
// Initialize the MAC characteristics for the call to
|
||
// NdisRegisterMac.
|
||
//
|
||
|
||
Pc586Char->MajorNdisVersion = PC586_NDIS_MAJOR_VERSION;
|
||
Pc586Char->MinorNdisVersion = PC586_NDIS_MINOR_VERSION;
|
||
Pc586Char->OpenAdapterHandler = Pc586OpenAdapter;
|
||
Pc586Char->CloseAdapterHandler = Pc586CloseAdapter;
|
||
Pc586Char->SetPacketFilterHandler = Pc586SetPacketFilter;
|
||
Pc586Char->AddMulticastAddressHandler = Pc586AddMulticastAddress;
|
||
Pc586Char->DeleteMulticastAddressHandler = Pc586DeleteMulticastAddress;
|
||
Pc586Char->SendHandler = Pc586Send;
|
||
Pc586Char->TransferDataHandler = Pc586TransferData;
|
||
Pc586Char->QueryInformationHandler = Pc586QueryInformation;
|
||
Pc586Char->SetInformationHandler = Pc586SetInformation;
|
||
Pc586Char->ResetHandler = Pc586Reset;
|
||
Pc586Char->TestHandler = Pc586Test;
|
||
Pc586Char->NameLength = sizeof(MacName) - 1;
|
||
|
||
PC586_MOVE_MEMORY(
|
||
Pc586Char->Name,
|
||
MacName,
|
||
sizeof(MacName)
|
||
);
|
||
|
||
NdisRegisterMac(
|
||
&InitStatus,
|
||
&NdisMacHandle,
|
||
NdisWrapperHandle,
|
||
NULL,
|
||
Pc586Char,
|
||
sizeof(*Pc586Char)
|
||
);
|
||
|
||
if (InitStatus == NDIS_STATUS_SUCCESS) {
|
||
|
||
//
|
||
// We started our communication with the wrapper. We now
|
||
// call a routine which will attempt to allocate and register
|
||
// all of the adapters. It will return true if *any* of the
|
||
// adapters were able to start.
|
||
//
|
||
|
||
if (Pc586StartAdapters(NdisMacHandle)) {
|
||
|
||
return InitStatus;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// We can only get here if something went wrong with registering
|
||
// the mac or *all* of the adapters.
|
||
//
|
||
|
||
NdisDeregisterMac(
|
||
&InitStatus,
|
||
NdisMacHandle
|
||
);
|
||
NdisTerminateWrapper(DriverObject);
|
||
|
||
return NDIS_ADAPTER_NOT_FOUND;
|
||
|
||
}
|
||
|
||
|
||
extern
|
||
BOOLEAN
|
||
Pc586StartAdapters(
|
||
IN NDIS_HANDLE NdisMacHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to initialize each adapter card/chip.
|
||
|
||
Arguments:
|
||
|
||
NdisMacHandle - The handle given by ndis when the mac was
|
||
registered.
|
||
|
||
Return Value:
|
||
|
||
Returns false if *no* adatper was able to be initialized.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BOOLEAN Status = FALSE;
|
||
|
||
Status = Pc586RegisterAdapter(
|
||
NdisMacHandle,
|
||
(PSZ)"\\Device\\Pc586",
|
||
(PVOID)PC586_DEFAULT_STATIC_RAM,
|
||
(CCHAR)PC586_DEFAULT_INTERRUPT_VECTOR,
|
||
(KIRQL)PC586_DEFAULT_INTERRUPT_IRQL,
|
||
(UINT)16,
|
||
(UINT)32
|
||
) || Status;
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
extern
|
||
BOOLEAN
|
||
Pc586RegisterAdapter(
|
||
IN NDIS_HANDLE NdisMacHandle,
|
||
IN PSZ DeviceName,
|
||
IN PVOID Pc586BaseHardwareMemoryAddress,
|
||
IN CCHAR Pc586InterruptVector,
|
||
IN KIRQL Pc586InterruptIrql,
|
||
IN UINT MaximumMulticastAddresses,
|
||
IN UINT MaximumOpenAdapters
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine (and its interface) are not portable. They are
|
||
defined by the OS, the architecture, and the particular PC586
|
||
implementation.
|
||
|
||
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:
|
||
|
||
NdisMacHandle - The handle given back to the mac from ndis when
|
||
the mac registered itself.
|
||
|
||
DeviceName - The zero terminated string containing the name
|
||
to give to the device adapter.
|
||
|
||
Pc586NetworkAddressAddress - The address containing the ethernet network
|
||
address.
|
||
|
||
Pc586BaseHardwareMemoryAddress - Given that this is an implementation
|
||
that uses dual ported memory this is the base of the memory for the
|
||
hardware.
|
||
|
||
Pc586InterruptVector - The interrupt vector to used for the adapter.
|
||
|
||
Pc586InterruptIrql - The interrupt request level to used for this
|
||
adapter.
|
||
|
||
MaximumMulticastAddresses - The maximum number of multicast
|
||
addresses to filter at any one time.
|
||
|
||
MaximumOpenAdatpers - The maximum number of opens at any one time.
|
||
|
||
|
||
Return Value:
|
||
|
||
Returns false if anything occurred that prevents the initialization
|
||
of the adapter.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
STRING Tmp;
|
||
|
||
UINT xx;
|
||
|
||
//
|
||
// Pointer for the adapter root.
|
||
//
|
||
PPC586_ADAPTER Adapter;
|
||
PUCHAR CmdPromPhys, StaticRamPhys;
|
||
|
||
//
|
||
// 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);
|
||
|
||
//
|
||
// All of the code that manipulates physical addresses depends
|
||
// on the fact that physical addresses are 4 byte quantities.
|
||
//
|
||
ASSERT(sizeof(PHYSICAL_ADDRESS) == 4);
|
||
|
||
//
|
||
// Allocate the Adapter block.
|
||
//
|
||
|
||
if (Adapter = PC586_ALLOC_PHYS(sizeof(PC586_ADAPTER))) {
|
||
DbgPrint("PC586 &Adapter == %lx\n", Adapter);
|
||
|
||
PC586_ZERO_MEMORY(
|
||
Adapter,
|
||
sizeof(PC586_ADAPTER)
|
||
);
|
||
|
||
Adapter->NdisMacHandle = NdisMacHandle;
|
||
|
||
//
|
||
// Allocate memory to hold the name of the device and initialize
|
||
// a STRING in the adapter block to hold it.
|
||
//
|
||
|
||
RtlInitString(
|
||
&Tmp,
|
||
DeviceName
|
||
);
|
||
|
||
Adapter->DeviceName = PC586_ALLOC_PHYS(Tmp.Length+1);
|
||
|
||
if (Adapter->DeviceName) {
|
||
|
||
{
|
||
|
||
PUCHAR S,D;
|
||
|
||
D = Adapter->DeviceName;
|
||
S = DeviceName;
|
||
|
||
while (*S) {
|
||
|
||
*D = *S;
|
||
D++;
|
||
S++;
|
||
|
||
}
|
||
*D = 0;
|
||
|
||
}
|
||
//
|
||
// initialize hardware.
|
||
//
|
||
|
||
CmdPromPhys = (PUCHAR)Pc586BaseHardwareMemoryAddress;
|
||
StaticRamPhys = (PUCHAR)Pc586BaseHardwareMemoryAddress;
|
||
|
||
Adapter->CmdProm = (PUCHAR)MmMapIoSpace(
|
||
(PHYSICAL_ADDRESS)CmdPromPhys, (ULONG)32*1024, FALSE);
|
||
Adapter->StaticRam = Adapter->CmdProm;
|
||
Adapter->Cb = (PCMD)(Adapter->StaticRam + OFFSETCU);
|
||
Adapter->Tbd = (PTBD)(Adapter->StaticRam + OFFSETTBD);
|
||
Adapter->Scp = (PSCP)(Adapter->StaticRam + OFFSETSCP);
|
||
Adapter->Iscp = (PISCP)(Adapter->StaticRam + OFFSETISCP);
|
||
Adapter->Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
|
||
Adapter->CAAddr = (PUSHORT)(Adapter->StaticRam + OFFSETCHANATT);
|
||
Adapter->IntAddr = (PUSHORT)(Adapter->StaticRam + OFFSETINTENAB);
|
||
Adapter->CommandBuffer = (PUSHORT)(Adapter->StaticRam + OFFSETTBUF);
|
||
|
||
// hardware reset the 586
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD0);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
|
||
// test to see if board is really present
|
||
ShuvWord( (PUSHORT)(Adapter->StaticRam + OFFSETSCB), 0x5a5a);
|
||
xx = PullWord((PUSHORT)(Adapter->StaticRam + OFFSETSCB) );
|
||
|
||
// reset again to insure board in 8-bit mode (for reading PROM)
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD0);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
|
||
if (xx != 0x5a5a) {
|
||
DbgPrint("pc586 board not present\n");
|
||
return FALSE;
|
||
}
|
||
else DbgPrint("pc586 board was found \n");
|
||
|
||
// prom address should increment by one, however the pc586 board
|
||
// is STUCK in word mode thus ++ by two
|
||
|
||
Adapter->NetworkAddress[0] = (UCHAR)PromAddr(Adapter, 0);
|
||
Adapter->NetworkAddress[1] = (UCHAR)PromAddr(Adapter, 2);
|
||
Adapter->NetworkAddress[2] = (UCHAR)PromAddr(Adapter, 4);
|
||
Adapter->NetworkAddress[3] = (UCHAR)PromAddr(Adapter, 6);
|
||
Adapter->NetworkAddress[4] = (UCHAR)PromAddr(Adapter, 8);
|
||
Adapter->NetworkAddress[5] = (UCHAR)PromAddr(Adapter, 10);
|
||
|
||
DbgPrint("ethernet id = * %x %x %x %x %x %x * \n",
|
||
Adapter->NetworkAddress[0] ,
|
||
Adapter->NetworkAddress[1] ,
|
||
Adapter->NetworkAddress[2] ,
|
||
Adapter->NetworkAddress[3] ,
|
||
Adapter->NetworkAddress[4] ,
|
||
Adapter->NetworkAddress[5] );
|
||
|
||
DbgPrint("Pc586 is mapped at virtual address %lx \n",
|
||
Adapter->CmdProm);
|
||
|
||
|
||
//
|
||
// Initialize the interrupt.
|
||
//
|
||
|
||
KeInitializeInterrupt(
|
||
&Adapter->Interrupt,
|
||
Pc586ISR,
|
||
Adapter,
|
||
(PKSPIN_LOCK)NULL,
|
||
Pc586InterruptVector,
|
||
Pc586InterruptIrql,
|
||
Pc586InterruptIrql,
|
||
LevelSensitive,
|
||
TRUE,
|
||
0,
|
||
TRUE
|
||
);
|
||
|
||
//
|
||
// Initialize our dpc.
|
||
//
|
||
|
||
KeInitializeDpc(
|
||
&Adapter->InterruptDPC,
|
||
Pc586StandardInterruptDPC,
|
||
Adapter
|
||
);
|
||
|
||
//
|
||
// Store the device name away
|
||
//
|
||
|
||
InitializeListHead(&Adapter->OpenBindings);
|
||
InitializeListHead(&Adapter->CloseList);
|
||
NdisAllocateSpinLock(&Adapter->Lock);
|
||
|
||
Adapter->DoingProcessing = FALSE;
|
||
Adapter->FirstLoopBack = NULL;
|
||
Adapter->LastLoopBack = NULL;
|
||
Adapter->FirstFinishTransmit = NULL;
|
||
Adapter->LastFinishTransmit = NULL;
|
||
Adapter->Stage4Open = TRUE;
|
||
Adapter->Stage3Open = TRUE;
|
||
Adapter->Stage2Open = TRUE;
|
||
Adapter->Stage1Open = TRUE;
|
||
Adapter->AlreadyProcessingStage4 = FALSE;
|
||
Adapter->AlreadyProcessingStage3 = FALSE;
|
||
Adapter->AlreadyProcessingStage2 = FALSE;
|
||
Adapter->FirstStage1Packet = NULL;
|
||
Adapter->LastStage1Packet = NULL;
|
||
Adapter->FirstStage2Packet = NULL;
|
||
Adapter->LastStage2Packet = NULL;
|
||
Adapter->FirstStage3Packet = NULL;
|
||
Adapter->LastStage3Packet = NULL;
|
||
Adapter->ResetInProgress = FALSE;
|
||
Adapter->ResettingOpen = NULL;
|
||
|
||
if (!MacCreateFilter(
|
||
MaximumMulticastAddresses,
|
||
MaximumOpenAdapters,
|
||
Pc586DeleteMulticast,
|
||
Pc586AddMulticast,
|
||
Pc586ChangeClass,
|
||
Pc586CloseAction,
|
||
&Adapter->Lock,
|
||
&Adapter->FilterDB
|
||
)) {
|
||
|
||
DbgPrint(
|
||
"Pc586Initialize - Unsuccessful filter create"
|
||
" for %s\n",
|
||
Adapter->DeviceName
|
||
);
|
||
PC586_FREE_PHYS(Adapter->DeviceName);
|
||
PC586_FREE_PHYS(Adapter);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
if (!Pc586InitialInit(Adapter)) {
|
||
|
||
DbgPrint(
|
||
"Pc586Initialize - %s is unloading.\n",
|
||
Adapter->DeviceName
|
||
);
|
||
MacDeleteFilter(Adapter->FilterDB);
|
||
PC586_FREE_PHYS(Adapter->DeviceName);
|
||
PC586_FREE_PHYS(Adapter);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
return TRUE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
DbgPrint(
|
||
"Pc586Initialize - Unsuccesful allocation of"
|
||
"name for %s.",
|
||
DeviceName
|
||
);
|
||
PC586_FREE_PHYS(Adapter);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
DbgPrint(
|
||
"Pc586Intialize -- Unsucssful allocation of adapter block"
|
||
" for %s.\n",
|
||
DeviceName
|
||
);
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
extern
|
||
BOOLEAN
|
||
Pc586InitialInit(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets up the initial init of the driver.
|
||
|
||
ZZZ This routine is *not* portable. It is specific to NT.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The adapter for the hardware.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
LARGE_INTEGER Time;
|
||
//
|
||
// First we make sure that the device is stopped.
|
||
//
|
||
Pc586IntOff(Adapter);
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
SetInitBlockAndInit(Adapter);
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
//
|
||
// Delay execution for 1/2 second to give the pc586
|
||
// time to initialize.
|
||
//
|
||
|
||
Time.QuadPart = Int32x32To64( -5 * 1000 * 1000 , 1);
|
||
|
||
if (KeDelayExecutionThread(
|
||
KernelMode,
|
||
FALSE,
|
||
(PLARGE_INTEGER)&Time
|
||
) != STATUS_SUCCESS) {
|
||
|
||
DbgPrint(
|
||
"PC586 - Couldn't delay to start %s.\n",
|
||
Adapter->DeviceName);
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
STRING Name;
|
||
|
||
RtlInitString(
|
||
&Name,
|
||
Adapter->DeviceName
|
||
);
|
||
|
||
//
|
||
// start the chip after NdisRegister... We may not
|
||
// have any bindings to indicate to but this
|
||
// is unimportant.
|
||
//
|
||
|
||
if (NdisRegisterAdapter(
|
||
&Adapter->NdisAdapterHandle,
|
||
Adapter->NdisMacHandle,
|
||
Adapter,
|
||
&Name
|
||
) != NDIS_STATUS_SUCCESS) {
|
||
|
||
DbgPrint(
|
||
"Pc586Initialize -- Unsuccessful "
|
||
"status from NdisRegisterAdapter for %s.\n",
|
||
Adapter->DeviceName
|
||
);
|
||
return FALSE;
|
||
|
||
} else {
|
||
if (!KeConnectInterrupt(&Adapter->Interrupt)) {
|
||
DbgPrint(
|
||
"Pc586Initialize - Unsuccessful connect "
|
||
"to interrupt for %s.\n",Adapter->DeviceName
|
||
);
|
||
return FALSE;
|
||
}
|
||
|
||
Pc586IntOn(Adapter);
|
||
return TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
extern
|
||
BOOLEAN
|
||
Pc586ISR(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Interrupt service routine for the pc586. It's main job is
|
||
to get the value of ScbStatus and record the changes in the
|
||
adapters own list of interrupt reasons.
|
||
|
||
ZZZ This routine is *not* portable. It is specific to NT and
|
||
to the pc586 card.
|
||
|
||
Arguments:
|
||
|
||
Interrupt - Interrupt object for the Pc586.
|
||
|
||
Context - Really a pointer to the adapter.
|
||
|
||
Return Value:
|
||
|
||
Returns true if the CX|FR|CNA|RNR bit of of the pc586 was.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Holds the pointer to the adapter.
|
||
//
|
||
PPC586_ADAPTER Adapter = Context;
|
||
|
||
|
||
if (Adapter->Scb->ScbStatus & SCBINTMSK) {
|
||
|
||
//
|
||
// Insert the normal interrupt processing DPC.
|
||
//
|
||
|
||
KeInsertQueueDpc(
|
||
&Adapter->InterruptDPC,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
Pc586StandardInterruptDPC(
|
||
IN PKDPC Dpc,
|
||
IN PVOID Context,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This DPC routine is queued by the interrupt service routine
|
||
and 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.
|
||
|
||
ZZZ This routine is *not* portable. It is specific to NT.
|
||
|
||
Arguments:
|
||
|
||
DPC - The control object associated with this routine.
|
||
|
||
Context - Really a pointer to the adapter.
|
||
|
||
SystemArgument1(2) - Neither of these arguments used.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ProcessInterrupt(Context);
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586OpenAdapter(
|
||
OUT NDIS_HANDLE *MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_HANDLE NdisBindingContext,
|
||
IN NDIS_HANDLE MacAdapterContext,
|
||
IN PSTRING AddressingInformation OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is used to create an open instance of an adapter, in effect
|
||
creating a binding between an upper-level module and the MAC module over
|
||
the adapter.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - A pointer to a location in which the MAC stores
|
||
a context value that it uses to represent this binding.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
NdisBindingContext - A value to be recorded by the MAC and passed as
|
||
context whenever an indication is delivered by the MAC for this binding.
|
||
|
||
MacAdapterContext - The value associated with the adapter that is being
|
||
opened when the MAC registered the adapter with NdisRegisterAdapter.
|
||
|
||
AddressingInformation - An optional pointer to a variable length string
|
||
containing hardware-specific information that can be used to program the
|
||
device. (This is not used by this MAC.)
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation. If the MAC does not
|
||
complete this request synchronously, the value would be
|
||
NDIS_STATUS_PENDING.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// The PC586_ADAPTER that this open binding should belong too.
|
||
//
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
//
|
||
// Holds the status that should be returned to the caller.
|
||
//
|
||
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_CONTEXT_HANDLE(MacAdapterContext);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
//
|
||
// Pointer to the space allocated for the binding.
|
||
//
|
||
PPC586_OPEN NewOpen;
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
//
|
||
// Allocate the space for the open binding. Fill in the fields.
|
||
//
|
||
|
||
NewOpen = PC586_ALLOC_PHYS(sizeof(PC586_OPEN));
|
||
|
||
*MacBindingHandle = BINDING_HANDLE_FROM_PPC586_OPEN(NewOpen);
|
||
InitializeListHead(&NewOpen->OpenList);
|
||
NewOpen->NdisBindingContext = NdisBindingContext;
|
||
NewOpen->References = 0;
|
||
NewOpen->BindingShuttingDown = FALSE;
|
||
NewOpen->OwningPc586 = Adapter;
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
if (Adapter->ResetInProgress || !MacNoteFilterOpenAdapter(
|
||
NewOpen->OwningPc586->FilterDB,
|
||
NewOpen,
|
||
NdisBindingContext,
|
||
&NewOpen->FilterIndex
|
||
)) {
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
PC586_FREE_PHYS(NewOpen);
|
||
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Everything has been filled in. Synchronize access to the
|
||
// adapter block and link the new open adapter in and increment
|
||
// the opens reference count to account for the fact that the
|
||
// filter routines have a "reference" to the open.
|
||
//
|
||
|
||
InsertTailList(&Adapter->OpenBindings,&NewOpen->OpenList);
|
||
NewOpen->References++;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586CloseAdapter(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine causes the MAC to close an open handle (binding).
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality it is a PPC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the
|
||
MAC must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Hold the lock while we update the reference counts for the
|
||
// adapter and the open.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
Open->References++;
|
||
StatusToReturn = MacDeleteFilterOpenAdapter(
|
||
Adapter->FilterDB,
|
||
Open->FilterIndex,
|
||
RequestHandle
|
||
);
|
||
|
||
//
|
||
// If the status is successful that merely implies that
|
||
// we were able to delete the reference to the open binding
|
||
// from the filtering code. If we have a successful status
|
||
// at this point we still need to check whether the reference
|
||
// count to determine whether we can close.
|
||
//
|
||
//
|
||
// The delete filter routine can return a "special" status
|
||
// that indicates that there is a current NdisIndicateReceive
|
||
// on this binding. See below.
|
||
//
|
||
|
||
if (StatusToReturn == NDIS_STATUS_SUCCESS) {
|
||
|
||
//
|
||
// Check whether the reference count is two. If
|
||
// it is then we can get rid of the memory for
|
||
// this open.
|
||
//
|
||
// A count of two indicates one for this routine
|
||
// and one for the filter which we *know* we can
|
||
// get rid of.
|
||
//
|
||
|
||
if (Open->References == 2) {
|
||
|
||
RemoveEntryList(&Open->OpenList);
|
||
//
|
||
// We are the only reference to the open. Remove
|
||
// it from the open list and delete the memory.
|
||
//
|
||
|
||
RemoveEntryList(&Open->OpenList);
|
||
PC586_FREE_PHYS(Open);
|
||
|
||
} else {
|
||
|
||
Open->CloseHandle = RequestHandle;
|
||
Open->BindingShuttingDown = TRUE;
|
||
|
||
//
|
||
// Remove the open from the open list and put it on
|
||
// the closing list.
|
||
//
|
||
|
||
RemoveEntryList(&Open->OpenList);
|
||
InsertTailList(&Adapter->CloseList,&Open->OpenList);
|
||
|
||
//
|
||
// Account for this routines reference to the open
|
||
// as well as reference because of the filtering.
|
||
//
|
||
|
||
Open->References -= 2;
|
||
|
||
//
|
||
// Change the status to indicate that we will
|
||
// be closing this later.
|
||
//
|
||
|
||
StatusToReturn = NDIS_STATUS_PENDING;
|
||
|
||
}
|
||
|
||
} else if (StatusToReturn == NDIS_STATUS_PENDING) {
|
||
|
||
Open->CloseHandle = RequestHandle;
|
||
Open->BindingShuttingDown = TRUE;
|
||
|
||
//
|
||
// Remove the open from the open list and put it on
|
||
// the closing list.
|
||
//
|
||
|
||
RemoveEntryList(&Open->OpenList);
|
||
InsertTailList(&Adapter->CloseList,&Open->OpenList);
|
||
|
||
//
|
||
// Account for this routines reference to the open
|
||
// as well as reference because of the filtering.
|
||
//
|
||
|
||
Open->References -= 2;
|
||
|
||
} else if (StatusToReturn == NDIS_STATUS_CLOSING_INDICATING) {
|
||
|
||
//
|
||
// When we have this status it indicates that the filtering
|
||
// code was currently doing an NdisIndicateReceive. It
|
||
// would not be wise to delete the memory for the open at
|
||
// this point. The filtering code will call our close action
|
||
// routine upon return from NdisIndicateReceive and that
|
||
// action routine will decrement the reference count for
|
||
// the open.
|
||
//
|
||
|
||
Open->CloseHandle = RequestHandle;
|
||
Open->BindingShuttingDown = TRUE;
|
||
|
||
//
|
||
// This status is private to the filtering routine. Just
|
||
// tell the caller the the close is pending.
|
||
//
|
||
|
||
StatusToReturn = NDIS_STATUS_PENDING;
|
||
|
||
//
|
||
// Remove the open from the open list and put it on
|
||
// the closing list.
|
||
//
|
||
|
||
RemoveEntryList(&Open->OpenList);
|
||
InsertTailList(&Adapter->CloseList,&Open->OpenList);
|
||
|
||
//
|
||
// Account for this routines reference to the open.
|
||
//
|
||
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Account for this routines reference to the open.
|
||
//
|
||
|
||
Open->References--;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586SetPacketFilter(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN UINT PacketFilter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586SetPacketFilter request allows a protocol to control the types
|
||
of packets that it receives from the MAC.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
PacketFilter - A bit mask that contains flags that correspond to specific
|
||
classes of received packets. If a particular bit is set in the mask,
|
||
then packet reception for that class of packet is enabled. If the
|
||
bit is clear, then packets that fall into that class are not received
|
||
by the client. A single exception to this rule is that if the promiscuous
|
||
bit is set, then the client receives all packets on the network, regardless
|
||
of the state of the other flags.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Keeps track of the *MAC's* status. The status will only be
|
||
// reset if the filter change action routine is called.
|
||
//
|
||
NDIS_STATUS StatusOfFilterChange = NDIS_STATUS_SUCCESS;
|
||
|
||
//
|
||
// Points to the adapter that this request is coming through.
|
||
//
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
//
|
||
// Pointer to the open that is changing the packet filters.
|
||
//
|
||
PPC586_OPEN Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
//
|
||
// Increment the open while it is going through the filtering
|
||
// routines.
|
||
//
|
||
|
||
Open->References++;
|
||
StatusOfFilterChange = MacFilterAdjust(
|
||
Adapter->FilterDB,
|
||
Open->FilterIndex,
|
||
RequestHandle,
|
||
PacketFilter,
|
||
TRUE
|
||
);
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
StatusOfFilterChange = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusOfFilterChange = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusOfFilterChange;
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586AddMulticastAddress(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN PSTRING MulticastAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586AddMulticastAddress request adds a multicast address
|
||
to the list of multicast/functional addresses that are enabled
|
||
for packet reception. The address may subsequently be deleted
|
||
using the Pc586DeleteMulticastAddress request.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
MulticastAddress - A pointer to a variable-length counted string
|
||
containing the multicast or functional address as it appears in storage
|
||
when received from the adapter. When specifying multicast or functional
|
||
addresses, the multicast/functional address bit is automatically provided
|
||
by the MAC itself; it is not necessary, by it is acceptable, to specify
|
||
the string.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// We call the filter database to add the address. If the
|
||
// address was already in the database then the call can be
|
||
// completed right away. If the address wasn't in the database then
|
||
// the action routine will be called. The action routine will be
|
||
// responsible for setting up any deferred processing.
|
||
//
|
||
|
||
NDIS_STATUS StatusOfAdd;
|
||
|
||
//
|
||
// Points to the adapter that this request is coming through.
|
||
//
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
Open->References++;
|
||
StatusOfAdd = MacAddFilterAddress(
|
||
Open->OwningPc586->FilterDB,
|
||
Open->FilterIndex,
|
||
RequestHandle,
|
||
MulticastAddress->Buffer
|
||
);
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
StatusOfAdd = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusOfAdd;
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586DeleteMulticastAddress(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN PSTRING MulticastAddress
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The MacDeleteMulticastAddress request removes a multicast or functional
|
||
address from the list of multicast/functional addresses that are enabled
|
||
for packet reception. Once an address is removed from the list, packets
|
||
will no longer be received by the binding when they are directed to that
|
||
address.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
MulticastAddress - A pointer to a variable-length counted string
|
||
containing the multicast or functional address as it appears in storage
|
||
when received from the adapter. When specifying multicast or functional
|
||
addresses, the multicast/functional address bit is automatically provided
|
||
by the MAC itself; it is not necessary, by it is acceptable, to specify
|
||
the string.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// We call the filter database to delete the address. If this
|
||
// is the last reference to the address then the delete address
|
||
// action routine is called.
|
||
//
|
||
|
||
NDIS_STATUS StatusOfDelete;
|
||
|
||
//
|
||
// Points to the adapter that this request is coming through.
|
||
//
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
Open->References++;
|
||
StatusOfDelete = MacDeleteFilterAddress(
|
||
Open->OwningPc586->FilterDB,
|
||
Open->FilterIndex,
|
||
RequestHandle,
|
||
MulticastAddress->Buffer
|
||
);
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
StatusOfDelete = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusOfDelete = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusOfDelete;
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586QueryInformation(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_INFORMATION_CLASS InformationClass,
|
||
OUT PVOID Buffer,
|
||
IN UINT BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586QueryInformation request allows a protocol to inspect
|
||
the MAC's capabilities and current status. See the description
|
||
of NdisQueryInformation for a detailed description of this request.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
InformationClass - A value indicating the class of the information
|
||
to be queried. See the description of NdisQueryInformation for valid
|
||
values.
|
||
|
||
Buffer - A pointer to a buffer into which the MAC copies the information.
|
||
See the description of NdisQueryInformation for buffer formats.
|
||
|
||
BufferLength - An unsigned integer specifying the maximum length of
|
||
the information buffer, in bytes.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Get and hold the lock while we update the reference counts.
|
||
//
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
Open->References++;
|
||
|
||
//
|
||
// The only information request that we actually support
|
||
// is the info identification service.
|
||
//
|
||
|
||
switch(InformationClass) {
|
||
|
||
case NdisInfoStationAddress:
|
||
case NdisInfoFunctionalAddress:
|
||
|
||
//
|
||
// Ensure that we have enough room to return the
|
||
// information.
|
||
//
|
||
|
||
if (BufferLength < MAC_LENGTH_OF_ADDRESS) {
|
||
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
|
||
} else {
|
||
|
||
MAC_COPY_NETWORK_ADDRESS(
|
||
(PCHAR)Buffer,
|
||
(PCHAR)Adapter->NetworkAddress
|
||
);
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case NdisInfoIdentification:
|
||
|
||
//
|
||
// Let the protocol know that we adhere
|
||
// to the IEEE 802.3 communications standard.
|
||
//
|
||
// In addition return the ndis version.
|
||
//
|
||
|
||
if (BufferLength < sizeof(NDIS_INFO_IDENTIFICATION)) {
|
||
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
break;
|
||
|
||
}
|
||
|
||
((PNDIS_INFO_IDENTIFICATION)Buffer)->NdisVersion = 3;
|
||
((PNDIS_INFO_IDENTIFICATION)Buffer)->MediumType =
|
||
NdisMedium802_3;
|
||
|
||
StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// ZZZ Need to implement query information services.
|
||
//
|
||
DbgPrint("PC586 - Information not yet implemented.\n");
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
break;
|
||
|
||
}
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586SetInformation(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_INFORMATION_CLASS InformationClass,
|
||
IN PVOID Buffer,
|
||
IN UINT BufferLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586SetInformation request allows a protocol to control the MAC
|
||
by changing information maintained by the MAC. See the description
|
||
of NdisSetInformation for a detailed description of this request.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
InformationClass - A value indicating the class of the information
|
||
to be set. See the description of NdisSetInformation for valid
|
||
values.
|
||
|
||
Buffer - A pointer to a buffer containg the information for the specified
|
||
class. See the description of NdisSetInformation for buffer formats.
|
||
|
||
BufferLength - An unsigned integer specifying the maximum length of
|
||
the information buffer, in bytes.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Hold the lock while we update the reference counts for the
|
||
// adapter and the open.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
//
|
||
// ZZZ Need to implement set information services.
|
||
//
|
||
DbgPrint("PC586 - MacSetInformation not yet implemented.\n");
|
||
StatusToReturn = NDIS_STATUS_FAILURE;
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586Reset(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586Reset request instructs the MAC to issue a hardware reset
|
||
to the network adapter. The MAC also resets its software state. See
|
||
the description of NdisReset for a detailed description of this request.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
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;
|
||
|
||
PPC586_ADAPTER Adapter =
|
||
PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Hold the locks while we update the reference counts on the
|
||
// adapter and the open.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
Open->References++;
|
||
SetupForReset(
|
||
Adapter,
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
|
||
RequestHandle,
|
||
NdisRequestReset
|
||
);
|
||
Open->References--;
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586Test(
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Pc586Test request instructs the MAC to run hardware diagnostics
|
||
on the underlying network adapter without resetting the adapter.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter;
|
||
|
||
NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS;
|
||
|
||
Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Hold the lock while we update the reference counts for the
|
||
// adapter and the open.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->References++;
|
||
|
||
if (!Adapter->ResetInProgress) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
if (!Open->BindingShuttingDown) {
|
||
|
||
//
|
||
// ZZZ Need to implement test information service.
|
||
//
|
||
|
||
StatusToReturn = NDIS_STATUS_NOT_TESTABLE;
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_CLOSING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
}
|
||
|
||
PC586_DO_DEFERRED(Adapter);
|
||
return StatusToReturn;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586ChangeClass(
|
||
IN UINT OldFilterClasses,
|
||
IN UINT NewFilterClasses,
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN BOOLEAN Set
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Action routine that will get called when a particular filter
|
||
class is first used or last cleared.
|
||
|
||
NOTE: This routine assumes that it is called with the lock
|
||
acquired.
|
||
|
||
Arguments:
|
||
|
||
OldFilterClasses - The values of the class filter before it
|
||
was changed.
|
||
|
||
NewFilterClasses - The current value of the class filter
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
Set - If true the change resulted from a set, otherwise the
|
||
change resulted from a open closing.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Holds the change that should be returned to the filtering package.
|
||
//
|
||
NDIS_STATUS StatusOfChange;
|
||
|
||
if (Adapter->ResetInProgress) {
|
||
|
||
StatusOfChange = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// This local will hold the actual changes that occurred
|
||
// in the packet filtering that are of real interest.
|
||
//
|
||
UINT PacketChanges;
|
||
|
||
|
||
//
|
||
// The whole purpose of this routine is to determine whether
|
||
// the filtering changes need to result in the hardware being
|
||
// reset.
|
||
//
|
||
|
||
ASSERT(OldFilterClasses != NewFilterClasses);
|
||
|
||
//
|
||
// We only need to reset if there is a change of "state" with
|
||
// multicast, all multicast, or promiscuous.
|
||
//
|
||
|
||
PacketChanges = (OldFilterClasses ^ NewFilterClasses) &
|
||
(NDIS_PACKET_TYPE_PROMISCUOUS |
|
||
NDIS_PACKET_TYPE_ALL_MULTICAST |
|
||
NDIS_PACKET_TYPE_MULTICAST);
|
||
|
||
StatusOfChange = NDIS_STATUS_SUCCESS;
|
||
if (PacketChanges) {
|
||
|
||
//
|
||
// We had some "important" change. We first check to see if
|
||
// promiscuous filtering or all multicast has changed.
|
||
//
|
||
// Otherwise multicast addressing is changing. We only need
|
||
// to reset the hardware if somebody isn't already filtering for
|
||
// all multicast or promiscuous (which the above tests do
|
||
// *NOT* test for) and there are any multicast addresses.
|
||
//
|
||
|
||
if ((PacketChanges & NDIS_PACKET_TYPE_PROMISCUOUS) ||
|
||
(PacketChanges & NDIS_PACKET_TYPE_ALL_MULTICAST) ||
|
||
((!(NewFilterClasses & (NDIS_PACKET_TYPE_PROMISCUOUS |
|
||
NDIS_PACKET_TYPE_ALL_MULTICAST))) &&
|
||
MAC_NUMBER_OF_FILTER_ADDRESSES(Adapter->FilterDB)
|
||
)) {
|
||
|
||
SetupForReset(
|
||
Adapter,
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
|
||
RequestHandle,
|
||
NdisRequestSetPacketFilter
|
||
);
|
||
StatusOfChange = NDIS_STATUS_PENDING;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return StatusOfChange;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586AddMulticast(
|
||
IN UINT CurrentAddressCount,
|
||
IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
|
||
IN UINT NewAddress,
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Action routine that will get called when an address is added to
|
||
the filter that wasn't referenced by any other open binding.
|
||
|
||
NOTE: This routine assumes that it is called with the lock
|
||
acquired.
|
||
|
||
Arguments:
|
||
|
||
CurrentAddressCount - The number of addresses in the address array.
|
||
|
||
CurrentAddresses - An array of multicast addresses. Note that this
|
||
array already contains the new address.
|
||
|
||
NewAddress - The index in the array where the new address can be
|
||
located.
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Holds the status that should be returned to the filtering package.
|
||
//
|
||
NDIS_STATUS StatusOfAdd;
|
||
|
||
//
|
||
// Check to see if the device is already resetting. If it is
|
||
// then reject this add.
|
||
//
|
||
|
||
if (Adapter->ResetInProgress) {
|
||
|
||
StatusOfAdd = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
} else {
|
||
|
||
UINT PacketFilters;
|
||
|
||
PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
||
|
||
//
|
||
// We don't need to do a reset if an open is promiscuous or
|
||
// an open is already accepting all multicast addresses.
|
||
//
|
||
|
||
if ((PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) ||
|
||
(PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
|
||
|
||
StatusOfAdd = NDIS_STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Make sure that multicast addresses are actually enabled.
|
||
// If not then there is no point in resetting.
|
||
//
|
||
|
||
if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
|
||
|
||
//
|
||
// We need to add this to the hardware multicast filtering.
|
||
//
|
||
|
||
SetupForReset(
|
||
Adapter,
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
|
||
RequestHandle,
|
||
NdisRequestAddMulticast
|
||
);
|
||
StatusOfAdd = NDIS_STATUS_PENDING;
|
||
|
||
} else {
|
||
|
||
StatusOfAdd = NDIS_STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return StatusOfAdd;
|
||
|
||
}
|
||
|
||
static
|
||
NDIS_STATUS
|
||
Pc586DeleteMulticast(
|
||
IN UINT CurrentAddressCount,
|
||
IN CHAR CurrentAddresses[][MAC_LENGTH_OF_ADDRESS],
|
||
IN CHAR OldAddress[MAC_LENGTH_OF_ADDRESS],
|
||
IN NDIS_HANDLE MacBindingHandle,
|
||
IN NDIS_HANDLE RequestHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Action routine that will get called when a particular multicast
|
||
address is deleted for the last time.
|
||
|
||
NOTE: This routine assumes that it is called with the lock acquired.
|
||
|
||
Arguments:
|
||
|
||
CurrentAddressCount - The number of addresses in the address array.
|
||
|
||
CurrentAddresses - An array of multicast addresses. Note that this
|
||
array does not contain the old address.
|
||
|
||
OldAddress - The address that was deleted from the address filter.
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
RequestHandle - A value supplied by the NDIS interface that the MAC
|
||
must use when completing this request with the NdisCompleteRequest
|
||
service, if the MAC completes this request asynchronously.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_ADAPTER Adapter = PPC586_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
|
||
|
||
//
|
||
// Holds the status that should be returned to the filtering
|
||
// package.
|
||
//
|
||
NDIS_STATUS StatusOfDelete;
|
||
|
||
//
|
||
// Check to see if the device is already resetting. If it is
|
||
// then reject this delete if the reset isn't coming from
|
||
// this MacBindingHandle. The reason we care about the binding
|
||
// handle is that when an open closes we may getting rid of multiple
|
||
// multicast addresses at one time.
|
||
//
|
||
|
||
if (Adapter->ResetInProgress) {
|
||
|
||
if (Adapter->ResettingOpen !=
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)) {
|
||
|
||
StatusOfDelete = NDIS_STATUS_RESET_IN_PROGRESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If this open is causing the reset then any further deletes
|
||
// can only be pending (as was the first delete).
|
||
//
|
||
|
||
StatusOfDelete = NDIS_STATUS_PENDING;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
UINT PacketFilters;
|
||
|
||
PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
||
|
||
//
|
||
// We don't need to do a reset if an open is promiscuous or
|
||
// an open is already accepting all multicast addresses.
|
||
//
|
||
|
||
if ((PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) ||
|
||
(PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST)) {
|
||
|
||
StatusOfDelete = NDIS_STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Make sure that multicast filtering is actually enabled
|
||
// since if multicast isn't then there is not point in
|
||
// resetting since nobody wants multicast addresses.
|
||
//
|
||
|
||
if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
|
||
|
||
//
|
||
// We need to delete this from the hardware multicast
|
||
// filtering.
|
||
//
|
||
|
||
SetupForReset(
|
||
Adapter,
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle),
|
||
RequestHandle,
|
||
NdisRequestDeleteMulticast
|
||
);
|
||
StatusOfDelete = NDIS_STATUS_PENDING;
|
||
|
||
} else {
|
||
|
||
StatusOfDelete = NDIS_STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return StatusOfDelete;
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
Pc586CloseAction(
|
||
IN NDIS_HANDLE MacBindingHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Action routine that will get called when a particular binding
|
||
was closed while it was indicating through NdisIndicateReceive
|
||
|
||
All this routine needs to do is to decrement the reference count
|
||
of the binding.
|
||
|
||
NOTE: This routine assumes that it is called with the lock acquired.
|
||
|
||
Arguments:
|
||
|
||
MacBindingHandle - The context value returned by the MAC when the
|
||
adapter was opened. In reality, it is a pointer to PC586_OPEN.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(MacBindingHandle)->References--;
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
ProcessInterrupt(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Main routine for processing interrupts.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The Adapter to process interrupts for.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
while (TRUE) {
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
if (Adapter->DoingProcessing) {
|
||
|
||
break;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Check the interrupt source and other reasons
|
||
// for processing. If there are no reasons to
|
||
// process then exit this loop.
|
||
//
|
||
// Note that when we check the for processing sources
|
||
// that we "carefully" check to see if we are already
|
||
// processing one of the stage queues. We do this
|
||
// by checking the "AlreadyProcessingStageX" variables
|
||
// in the adapter. If any of these are true then
|
||
// we let whoever set that boolean take care of pushing
|
||
// the packet through the stage queues.
|
||
//
|
||
// By checking the "AlreadyProcessingStageX" variables
|
||
// we can prevent a possible priority inversion where
|
||
// we get "stuck" behind something that is processing
|
||
// at a lower priority level.
|
||
//
|
||
|
||
if (
|
||
(Adapter->Scb->ScbStatus &
|
||
(SCBINTMSK)) ||
|
||
Adapter->FirstLoopBack ||
|
||
(Adapter->ResetInProgress && (!Adapter->References)) ||
|
||
((!(Adapter->AlreadyProcessingStage4 ||
|
||
Adapter->AlreadyProcessingStage3 ||
|
||
Adapter->AlreadyProcessingStage2)
|
||
) &&
|
||
((Adapter->FirstStage3Packet && Adapter->Stage4Open) ||
|
||
(Adapter->FirstStage2Packet && Adapter->Stage3Open) ||
|
||
(Adapter->FirstStage1Packet && Adapter->Stage2Open)
|
||
)
|
||
) || (!IsListEmpty(&Adapter->CloseList))) {
|
||
|
||
Adapter->References++;
|
||
Adapter->DoingProcessing = TRUE;
|
||
|
||
} else {
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Note that the following code depends on the fact that
|
||
// code above left the spinlock held.
|
||
//
|
||
|
||
//
|
||
// If we have a reset in progress and the adapters reference
|
||
// count is 1 (meaning no routine is in the interface and
|
||
// we are the only "active" interrupt processing routine) then
|
||
// it is safe to start the reset.
|
||
//
|
||
|
||
if (Adapter->ResetInProgress && (Adapter->References == 1)) {
|
||
|
||
StartAdapterReset(Adapter);
|
||
goto LoopBottom;
|
||
|
||
}
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
//
|
||
// note -- need to check for non-packet related errors.
|
||
//
|
||
//
|
||
|
||
|
||
// Check the interrupt vector and see if there are any
|
||
// more receives to process. 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.
|
||
//
|
||
|
||
if ( Adapter->Scb->ScbStatus & (SCBINTFR|SCBINTRNR) ) {
|
||
|
||
ProcessReceiveInterrupts(Adapter);
|
||
|
||
//
|
||
// We need to signal every open binding that the
|
||
// receives are complete. We increment the reference
|
||
// count on the open binding while we're doing indications
|
||
// so that the open can't be deleted out from under
|
||
// us while we're indicating (recall that we can't own
|
||
// the lock during the indication).
|
||
//
|
||
|
||
{
|
||
|
||
PPC586_OPEN Open;
|
||
PLIST_ENTRY CurrentLink;
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
CurrentLink = Adapter->OpenBindings.Flink;
|
||
|
||
while (CurrentLink != &Adapter->OpenBindings) {
|
||
|
||
Open = CONTAINING_RECORD(
|
||
CurrentLink,
|
||
PC586_OPEN,
|
||
OpenList
|
||
);
|
||
|
||
Open->References++;
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
NdisIndicateReceiveComplete(Open->NdisBindingContext);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Open->References--;
|
||
|
||
CurrentLink = CurrentLink->Flink;
|
||
|
||
}
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Process the transmit interrupts if there are any.
|
||
//
|
||
|
||
if ( Adapter->Scb->ScbStatus & (SCBINTCX|SCBINTCNA) ) {
|
||
|
||
ProcessTransmitInterrupts(Adapter);
|
||
|
||
Adapter->Scb->ScbCmd =
|
||
(USHORT)(Adapter->Scb->ScbStatus & (SCBINTCX|SCBINTCNA));
|
||
if (Adapter->Scb->ScbCmd) ChanAttn(Adapter);
|
||
}
|
||
|
||
//
|
||
// Only try to push a packet through the stage queues
|
||
// if somebody else isn't already doing it and
|
||
// there is some hope of moving some packets
|
||
// ahead.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
if ((!(Adapter->AlreadyProcessingStage4 ||
|
||
Adapter->AlreadyProcessingStage3 ||
|
||
Adapter->AlreadyProcessingStage2)
|
||
) &&
|
||
((Adapter->FirstStage3Packet && Adapter->Stage4Open) ||
|
||
(Adapter->FirstStage2Packet && Adapter->Stage3Open) ||
|
||
(Adapter->FirstStage1Packet && Adapter->Stage2Open)
|
||
)
|
||
) {
|
||
|
||
Pc586StagedAllocation(Adapter);
|
||
|
||
}
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
//
|
||
// Process the loopback queue.
|
||
//
|
||
// NOTE: Incase anyone ever figures out how to make this
|
||
// loop more reentriant, special care needs to be taken that
|
||
// loopback packets and regular receive packets are NOT being
|
||
// indicated at the same time. While the filter indication
|
||
// routines can handle this, I doubt that the transport can.
|
||
//
|
||
|
||
Pc586ProcessLoopback(Adapter);
|
||
|
||
//
|
||
// If there are any opens on the closing list and their
|
||
// reference counts are zero then complete the close and
|
||
// delete them from the list.
|
||
//
|
||
// ZZZ This really needs to be improved. Currently if
|
||
// there are any outstanding sends, they are not canceled.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
if (!IsListEmpty(&Adapter->CloseList)) {
|
||
|
||
PPC586_OPEN Open;
|
||
|
||
Open = CONTAINING_RECORD(
|
||
Adapter->CloseList.Flink,
|
||
PC586_OPEN,
|
||
OpenList
|
||
);
|
||
|
||
if (!Open->References) {
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
NdisCompleteRequest(
|
||
Open->NdisBindingContext,
|
||
Open->CloseHandle,
|
||
NdisRequestCloseAdapter,
|
||
NDIS_STATUS_SUCCESS
|
||
);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
RemoveEntryList(&Open->OpenList);
|
||
PC586_FREE_PHYS(Open);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// NOTE: This code assumes that the above code left
|
||
// the spinlock acquired.
|
||
//
|
||
// Bottom of the interrupt processing loop. Another dpc
|
||
// could be coming in at this point to process interrupts.
|
||
// We clear the flag that says we're processing interrupts
|
||
// so that some invocation of the DPC can grab it and process
|
||
// any further interrupts.
|
||
//
|
||
|
||
LoopBottom:;
|
||
Adapter->DoingProcessing = FALSE;
|
||
Adapter->References--;
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
}
|
||
|
||
//
|
||
// The only way to get out of the loop (via the break above) is
|
||
// while we're still holding the spin lock.
|
||
//
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
static
|
||
VOID
|
||
ProcessReceiveInterrupts(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process the packets that have finished receiving.
|
||
|
||
NOTE: This routine assumes that no other thread of execution
|
||
is processing receives!
|
||
Get all the enet packets the 586 has for the CPU and put them in
|
||
in NDIS buffers
|
||
|
||
Arguments:
|
||
|
||
Adapter - The adapter to indicate to.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFD Fd;
|
||
PRBD LastRbd, FirstRbd;
|
||
UINT PacketLength;
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
r1:
|
||
for(Fd = Adapter->BeginFd; ; Fd = Adapter->BeginFd ) {
|
||
|
||
if (Fd == NULL) {
|
||
DbgPrint("RcvPacket(): Fd == NULL\n");
|
||
KeBugCheck(9);
|
||
}
|
||
if (Fd->FdStatus & CSCMPLT)
|
||
{
|
||
Adapter->BeginFd =
|
||
(PFD)Pc586ToVirt(Adapter, Fd->FdNxtOfst);
|
||
FirstRbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
|
||
|
||
if (Fd->FdRbdOfst != 0xffff) {
|
||
// scan for the end of the rbd's connected to the Fd
|
||
|
||
PacketLength = 14; // 6 source, 6 dest, 2 length bytes
|
||
|
||
for( LastRbd = FirstRbd; ; LastRbd = (PRBD)
|
||
Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst)) {
|
||
|
||
PacketLength += (LastRbd->RbdStatus & CSRBDCNTMSK);
|
||
|
||
if ( (LastRbd->RbdSize & 0x3fff) != RCVBUFSIZE) DbgPrint("PC586->ProcessReceiveInterrupts(): LastRbd->RbdSize = 0x%lx, H/W alignment problem\n", LastRbd->RbdSize);
|
||
|
||
if (((LastRbd->RbdStatus & CSEOF) == CSEOF) ||
|
||
((LastRbd->RbdSize & CSEL) == CSEL)) break;
|
||
}
|
||
|
||
Adapter->BeginRbd =
|
||
(PRBD)Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst);
|
||
|
||
if (Fd->FdStatus & CSOK) {
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
PutPacket(Adapter, Fd, PacketLength);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
}
|
||
else BadRcvCount++;
|
||
|
||
}
|
||
if (Fd->FdCmd & CSEL) {
|
||
ReQFd(Adapter, Fd);
|
||
break;
|
||
}
|
||
else ReQFd(Adapter, Fd);
|
||
}
|
||
else break;
|
||
}
|
||
|
||
|
||
// ack the rcv status bits
|
||
WaitScb(Adapter);
|
||
Adapter->Scb->ScbCmd =
|
||
(USHORT)(Adapter->Scb->ScbStatus & (SCBINTFR | SCBINTRNR));
|
||
if (Adapter->Scb->ScbCmd) ChanAttn(Adapter);
|
||
|
||
WaitScb(Adapter);
|
||
RuStart(Adapter);
|
||
WaitScb(Adapter);
|
||
|
||
if ( Adapter->Scb->ScbStatus & (SCBINTFR | SCBINTRNR) ) goto r1;
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
PutPacket(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN PFD Fd,
|
||
IN UINT PacketLength
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes one packet off of the 586's receive ring and "Indicates"
|
||
it to upper layer network software.
|
||
|
||
Arguments:
|
||
Adapter - The adapter that a packet came in on.
|
||
|
||
Return Value:
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUSHORT ShortAddr;
|
||
PUSHORT Buffer;
|
||
PRBD Rbd;
|
||
USHORT xx;
|
||
USHORT ByteCount, LookaheadIndex;
|
||
PC586_RECEIVE_CONTEXT Context;
|
||
|
||
Rbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
|
||
if (Rbd == NULL) return;
|
||
Buffer = (PUSHORT)Pc586ToVirt(Adapter, Rbd->RbdBuff);
|
||
if (Buffer == NULL) return;
|
||
|
||
ByteCount = (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK);
|
||
|
||
// Ndis wants a) destination address, b) source address
|
||
// c) length field and d) the data, all contiguous
|
||
|
||
LookaheadIndex = 0;
|
||
ShortAddr = (PUSHORT)Fd->FdDest;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
|
||
ShortAddr = (PUSHORT)Fd->FdSrc;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *ShortAddr++;
|
||
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = Fd->FdLength;
|
||
|
||
if (ww_put == 0) { /*88888888888*/
|
||
|
||
for (xx=0; xx < (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK); xx+=2)
|
||
Adapter->LookaheadBufferNdis[LookaheadIndex++] = *Buffer++;
|
||
|
||
} else { /*88888888888*/
|
||
|
||
for (xx=0; xx < (USHORT)(Rbd->RbdStatus & CSRBDCNTMSK); xx+=4) {
|
||
*(PULONG)(&(Adapter->LookaheadBufferNdis[LookaheadIndex])) =
|
||
*(PULONG)(Buffer);
|
||
LookaheadIndex += 2;
|
||
Buffer += 2;
|
||
}
|
||
} /*88888888888*/
|
||
//
|
||
// Check just before we do indications that we aren't
|
||
// resetting.
|
||
//
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
if (Adapter->ResetInProgress) {
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
return;
|
||
}
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
// set lsb to indicate nonloopback packet
|
||
Context.a.FrameDescriptor = (UINT)Fd | 0x01;
|
||
|
||
MacFilterIndicateReceive(
|
||
Adapter->FilterDB,
|
||
(NDIS_HANDLE)Context.a.WholeThing,
|
||
(PCHAR)Adapter->LookaheadBufferNdis,
|
||
(PVOID)Adapter->LookaheadBufferNdis,
|
||
(UINT)(LOOKAHEADBUFFERSIZE * 2),
|
||
PacketLength
|
||
);
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ReQFd(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN PFD Fd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
requeue frame
|
||
|
||
Arguments:
|
||
|
||
Adapter - the net card the packet came in on.
|
||
|
||
Fd - The 586 frame descriptor that holds the enet packet
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PRBD LastRbd, FirstRbd;
|
||
|
||
FirstRbd = (PRBD)Pc586ToVirt(Adapter, Fd->FdRbdOfst);
|
||
|
||
Fd->FdStatus = 0;
|
||
Fd->FdCmd = CSEL | CSSUSPND; // will be the last fd on the list
|
||
Fd->FdRbdOfst = 0xffff;
|
||
|
||
Adapter->EndFd->FdCmd = 0; // no longer the last
|
||
|
||
Adapter->EndFd = Fd;
|
||
|
||
if (FirstRbd != NULL) {
|
||
for(
|
||
LastRbd = FirstRbd;
|
||
|
||
(LastRbd->RbdStatus & CSEOF) != CSEOF &&
|
||
(LastRbd->RbdSize & CSEL) != CSEL;
|
||
|
||
LastRbd = (PRBD)Pc586ToVirt(Adapter, LastRbd->RbdNxtOfst)
|
||
)
|
||
LastRbd->RbdStatus = 0;
|
||
|
||
|
||
LastRbd->RbdStatus = 0;
|
||
LastRbd->RbdSize |= CSEL; // new end of rbd list
|
||
|
||
Adapter->EndRbd->RbdSize &= ~CSEL;
|
||
if ( (Adapter->EndRbd->RbdSize & 0x3fff) != RCVBUFSIZE) DbgPrint("PC586-> ReQFd: Adapter->EndRbd->RbdSize = 0x%lx, H/W alignment problems\n", LastRbd->RbdSize);
|
||
Adapter->EndRbd = LastRbd;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
RuStart(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
restart the receive unit if necessary
|
||
|
||
Arguments:
|
||
|
||
Adapter - the net card from which a bunch of packets were rcv'd.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PSCB Scb;
|
||
PFD BeginFd;
|
||
|
||
Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
|
||
|
||
BeginFd = Adapter->BeginFd;
|
||
|
||
// if RU already running - leave it alone
|
||
if ((Scb->ScbStatus & SCBRUSMSK) == SCBRUSREADY) return;
|
||
|
||
if ((Scb->ScbStatus & SCBRUSMSK) == SCBRUSSUSPND) {
|
||
RcvSuspendCount++;
|
||
WaitScb(Adapter);
|
||
Scb->ScbCmd = SCBRUCRSUM;
|
||
ChanAttn(Adapter);
|
||
return;
|
||
}
|
||
|
||
|
||
if (BeginFd->FdStatus & CSCMPLT)
|
||
// The RU is not ready but it just completed an Fd
|
||
// do NOT restart RU -- this will wipe out the just completed Fd
|
||
// There will be a second interrupt that will remove the Fd via
|
||
// RcvPacket()
|
||
return;
|
||
|
||
// if we get here, then RU is not ready and no completed fd's are
|
||
// available therefore "start" not "resume" the RU
|
||
|
||
RcvRestartCount++;
|
||
BeginFd->FdRbdOfst = VirtToPc586(Adapter,
|
||
(PCHAR)Adapter->BeginRbd);
|
||
|
||
WaitScb(Adapter);
|
||
|
||
Scb->ScbCmd = SCBRUCSTRT;
|
||
Scb->ScbRfaOfst = VirtToPc586(Adapter, (PCHAR)BeginFd);
|
||
ChanAttn(Adapter);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
static
|
||
VOID
|
||
StartAdapterReset(
|
||
IN PPC586_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.
|
||
|
||
--*/
|
||
{
|
||
|
||
|
||
Adapter->Stage4Open = TRUE;
|
||
Adapter->Stage3Open = TRUE;
|
||
Adapter->Stage2Open = TRUE;
|
||
Adapter->Stage1Open = TRUE;
|
||
|
||
Adapter->AlreadyProcessingStage4 = FALSE;
|
||
Adapter->AlreadyProcessingStage3 = FALSE;
|
||
Adapter->AlreadyProcessingStage2 = FALSE;
|
||
|
||
//
|
||
// Go through the various transmit lists and abort every packet.
|
||
//
|
||
|
||
{
|
||
|
||
UINT i;
|
||
PNDIS_PACKET Packet;
|
||
PPC586_RESERVED Reserved;
|
||
PPC586_OPEN Open;
|
||
PNDIS_PACKET Next;
|
||
|
||
for (
|
||
i = 0;
|
||
i < 5;
|
||
i++
|
||
) {
|
||
|
||
switch (i) {
|
||
|
||
case 0:
|
||
Next = Adapter->FirstLoopBack;
|
||
break;
|
||
case 1:
|
||
Next = Adapter->FirstFinishTransmit;
|
||
break;
|
||
case 2:
|
||
Next = Adapter->FirstStage3Packet;
|
||
break;
|
||
case 3:
|
||
Next = Adapter->FirstStage2Packet;
|
||
break;
|
||
case 4:
|
||
Next = Adapter->FirstStage1Packet;
|
||
break;
|
||
|
||
}
|
||
|
||
|
||
while (Next) {
|
||
|
||
Packet = Next;
|
||
Reserved = PPC586_RESERVED_FROM_PACKET(Packet);
|
||
Next = Reserved->Next;
|
||
Open =
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
|
||
|
||
//
|
||
// The completion of the packet is one less reason
|
||
// to keep the open around.
|
||
//
|
||
|
||
ASSERT(Open->References);
|
||
|
||
Open->References--;
|
||
|
||
NdisCompleteSend(
|
||
Open->NdisBindingContext,
|
||
Reserved->RequestHandle,
|
||
NDIS_STATUS_REQUEST_ABORTED
|
||
);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
Adapter->FirstLoopBack = NULL;
|
||
Adapter->LastLoopBack = NULL;
|
||
Adapter->FirstFinishTransmit = NULL;
|
||
Adapter->LastFinishTransmit = NULL;
|
||
Adapter->FirstStage3Packet = NULL;
|
||
Adapter->LastStage3Packet = NULL;
|
||
Adapter->FirstStage2Packet = NULL;
|
||
Adapter->LastStage2Packet = NULL;
|
||
Adapter->FirstStage1Packet = NULL;
|
||
Adapter->LastStage1Packet = NULL;
|
||
|
||
}
|
||
|
||
SetInitBlockAndInit(Adapter);
|
||
Pc586IntOn(Adapter);
|
||
|
||
}
|
||
|
||
static
|
||
VOID
|
||
SetInitBlockAndInit(
|
||
IN PPC586_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: ZZZ This routine is NT specific.
|
||
|
||
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:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
|
||
|
||
//
|
||
// Fill in the adapters initialization block.
|
||
//
|
||
|
||
PISCP Iscp;
|
||
ULONG xx;
|
||
PSCB Scb;
|
||
PPC586_OPEN ResettingOpen;
|
||
NDIS_REQUEST_TYPE ResetRequestType;
|
||
PPC586_OPEN Open;
|
||
PLIST_ENTRY CurrentLink;
|
||
|
||
|
||
//
|
||
// Possibly undefined request handle for the reset request.
|
||
//
|
||
NDIS_HANDLE ResetRequestHandle;
|
||
|
||
|
||
ResetCount++;
|
||
|
||
|
||
// shut off interrupts
|
||
Pc586IntOff(Adapter);
|
||
|
||
// drop chan attn -- even though it should not be raised at this point
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETCHANATT) , CMD0);
|
||
|
||
// hardware reset the 586
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), (USHORT)CMD1);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETRESET), CMD0);
|
||
KeStallExecutionProcessor((ULONG)1000);
|
||
|
||
// esi loopback - until diagnostics are run
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETNORMMODE),
|
||
(USHORT)CMD1);
|
||
|
||
//16 bit for AT bus
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSET16BXFER),
|
||
(USHORT)CMD1);
|
||
|
||
BuildCu(Adapter); // inits scp, iscp, scb, db, tdb and tbuf
|
||
BuildRu(Adapter); // inits scb, fd's, rbd's rbufs
|
||
|
||
Iscp = (PISCP) (Adapter->StaticRam + OFFSETISCP);
|
||
Iscp->IscpBusy = 1; // per user man. reset protocol
|
||
|
||
// chan attn to feed 586 its data structs
|
||
ChanAttn(Adapter);
|
||
|
||
Scb = (PSCB)(Adapter->StaticRam + OFFSETSCB);
|
||
|
||
for(xx=0; xx<0xffff; xx++)
|
||
if ( Scb->ScbStatus==(SCBINTCX | SCBINTCNA) ) goto SIB1;
|
||
|
||
DbgPrint("pc586 SetInitBlockAndInit(): first chan attn failed\n");
|
||
return;
|
||
|
||
SIB1:
|
||
Scb->ScbCmd = SCBACKCX | SCBACKCNA;
|
||
|
||
ChanAttn(Adapter); // to clear the reset's ack
|
||
|
||
// diag cmd (no. 7) will busy wait for completion
|
||
|
||
if (Diagnose586(Adapter) == FALSE) {
|
||
DbgPrint("pc586 Diagnose586() failed\n");
|
||
return;
|
||
}
|
||
if (Config586(Adapter) == FALSE) {
|
||
DbgPrint("pc586 Config586() failed\n");
|
||
return;
|
||
}
|
||
LoadMCAddress(Adapter);
|
||
|
||
// now turn esi loopback off, rcv started
|
||
|
||
ShuvWord( (PUSHORT)(Adapter->CmdProm + OFFSETNORMMODE),
|
||
(USHORT)CMD1);
|
||
WaitScb(Adapter);
|
||
RuStart(Adapter);
|
||
|
||
//
|
||
// This initialization is from either a
|
||
// reset or test. ZZZ Test not yet implemented.
|
||
//
|
||
|
||
//
|
||
// This will point (possibly null) to the open that
|
||
// initiated the reset.
|
||
//
|
||
|
||
|
||
|
||
Adapter->ResetInProgress = FALSE;
|
||
|
||
//
|
||
// We save off the open that caused this reset incase
|
||
// we get *another* reset while we're indicating the
|
||
// last reset is done.
|
||
//
|
||
|
||
ResettingOpen = Adapter->ResettingOpen;
|
||
ResetRequestType = Adapter->ResetRequestType;
|
||
ResetRequestHandle = Adapter->ResetRequestHandle;
|
||
|
||
//
|
||
// We need to signal every open binding that the
|
||
// reset is complete. We increment the reference
|
||
// count on the open binding while we're doing indications
|
||
// so that the open can't be deleted out from under
|
||
// us while we're indicating (recall that we can't own
|
||
// the lock during the indication).
|
||
//
|
||
|
||
CurrentLink = Adapter->OpenBindings.Flink;
|
||
|
||
while (CurrentLink != &Adapter->OpenBindings) {
|
||
|
||
Open = CONTAINING_RECORD(
|
||
CurrentLink,
|
||
PC586_OPEN,
|
||
OpenList
|
||
);
|
||
|
||
Open->References++;
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
NdisIndicateStatus(
|
||
Open->NdisBindingContext,
|
||
NDIS_STATUS_RESET,
|
||
0
|
||
);
|
||
|
||
NdisIndicateStatusComplete(Open->NdisBindingContext);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
Open->References--;
|
||
|
||
CurrentLink = CurrentLink->Flink;
|
||
|
||
}
|
||
|
||
//
|
||
// Look to see which open initiated the reset.
|
||
//
|
||
// If the reset was initiated by an open because it
|
||
// was closing we will let the closing binding loop
|
||
// further on in this routine indicate that the
|
||
// request was complete. ZZZ (Still need to code
|
||
// this part.)
|
||
//
|
||
// If the reset was initiated for some obscure hardware
|
||
// reason that can't be associated with a particular
|
||
// open (e.g. memory error on receiving a packet) then
|
||
// we won't have an initiating request so we can't
|
||
// indicate. (The ResettingOpen pointer will be
|
||
// NULL in this case.)
|
||
//
|
||
|
||
if (ResettingOpen &&
|
||
(ResetRequestType != NdisRequestCloseAdapter)) {
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
NdisCompleteRequest(
|
||
ResettingOpen->NdisBindingContext,
|
||
ResetRequestHandle,
|
||
ResetRequestType,
|
||
NDIS_STATUS_SUCCESS
|
||
);
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
ResettingOpen->References--;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
static
|
||
VOID
|
||
SetupForReset(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN PPC586_OPEN Open,
|
||
IN NDIS_HANDLE RequestHandle,
|
||
IN NDIS_REQUEST_TYPE RequestType
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
NOTE: This routine must be called with the lock acquired.
|
||
|
||
Arguments:
|
||
|
||
Adapter - The adapter whose hardware is to be initialized.
|
||
|
||
Open - A (possibly NULL) pointer to an pc586 open structure.
|
||
The reason it could be null is if the adapter is initiating the
|
||
reset on its own.
|
||
|
||
RequestHandle - If open is not null then the request handle of the
|
||
request that is causing the reset.
|
||
|
||
RequestType - If the open is not null then the request type that
|
||
is causing the reset.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Shut down the chip. We won't be doing any more work until
|
||
// the reset is complete.
|
||
//
|
||
|
||
Pc586IntOff(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.
|
||
//
|
||
|
||
|
||
Adapter->ResetInProgress = TRUE;
|
||
|
||
//
|
||
// Shut down all of the transmit queues so that the
|
||
// transmit portion of the chip will eventually calm down.
|
||
//
|
||
|
||
Adapter->Stage4Open = FALSE;
|
||
Adapter->Stage3Open = FALSE;
|
||
Adapter->Stage2Open = FALSE;
|
||
Adapter->Stage1Open = FALSE;
|
||
|
||
Adapter->ResetRequestHandle = RequestHandle;
|
||
Adapter->ResettingOpen = Open;
|
||
Adapter->ResetRequestType = RequestType;
|
||
|
||
//
|
||
// If there is a valid open we should up the reference count
|
||
// so that the open can't be deleted before we indicate that
|
||
// their request is finished.
|
||
//
|
||
|
||
if (Open) {
|
||
|
||
Open->References++;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
static
|
||
BOOLEAN
|
||
ProcessTransmitInterrupts(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Process the packets that have finished transmitting.
|
||
|
||
NOTE: This routine assumes that it is being executed in a
|
||
single thread of execution.
|
||
|
||
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.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Pointer to the packet that started this transmission.
|
||
//
|
||
PNDIS_PACKET OwningPacket;
|
||
|
||
//
|
||
// Points to the reserved part of the OwningPacket.
|
||
//
|
||
PPC586_RESERVED Reserved;
|
||
|
||
|
||
|
||
//
|
||
// Get a pointer to the owning packet and the reserved part of
|
||
// the packet.
|
||
//
|
||
|
||
OwningPacket = Adapter->OwningPacket;
|
||
|
||
if (OwningPacket == NULL) return FALSE;
|
||
|
||
Reserved = PPC586_RESERVED_FROM_PACKET(OwningPacket);
|
||
|
||
//
|
||
// Check that the host does indeed own this entire packet.
|
||
//
|
||
|
||
if ( !(Adapter->Cb->CmdStatus & CSCMPLT) ||
|
||
(Adapter->Cb->CmdStatus & CSBUSY) ) {
|
||
|
||
//
|
||
// We don't own the command block. We return FALSE to indicate
|
||
// that we don't have any more packets to work on.
|
||
//
|
||
|
||
return FALSE;
|
||
|
||
} else {
|
||
|
||
ReturnAdapterResources(Adapter);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
Adapter->OwningPacket = NULL;
|
||
|
||
if (Reserved->STAGE.STAGE4.ReadyToComplete) {
|
||
|
||
//
|
||
// The binding that is submitting this packet.
|
||
//
|
||
PPC586_OPEN Open =
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(Reserved->MacBindingHandle);
|
||
|
||
|
||
//
|
||
// While we're indicating we increment the reference
|
||
// count so that the open can't be deleted out
|
||
// from under us.
|
||
//
|
||
|
||
Open->References++;
|
||
|
||
//
|
||
// Along with at least one reference because of the coming
|
||
// indication there should be a reference because of the
|
||
// packet to indicate.
|
||
//
|
||
|
||
ASSERT(Open->References > 1);
|
||
|
||
//
|
||
// Either the packet is done with loopback or
|
||
// the packet didn't need to be loopbacked. In
|
||
// any case we can let the protocol know that the
|
||
// send is complete after we remove the packet from
|
||
// the finish transmit queue.
|
||
//
|
||
|
||
Pc586RemovePacketOnFinishTrans(
|
||
Adapter,
|
||
OwningPacket
|
||
);
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
NdisCompleteSend(
|
||
Open->NdisBindingContext,
|
||
Reserved->RequestHandle,
|
||
NDIS_STATUS_SUCCESS
|
||
);
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
|
||
//
|
||
// We reduce the count by two to account for the fact
|
||
// that we aren't indicating to the open and that one
|
||
// less packet is owned by this open.
|
||
//
|
||
|
||
Open->References -= 2;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Let the loopback queue know that the hardware
|
||
// is finished with the packet, and record whether
|
||
// it could transmit or not.
|
||
//
|
||
|
||
Reserved->STAGE.STAGE4.ReadyToComplete = TRUE;
|
||
Reserved->STAGE.STAGE4.SuccessfulTransmit = TRUE;
|
||
|
||
//
|
||
// Decrement the reference count by one since it
|
||
// was incremented by one when the packet was given
|
||
// to be transmitted.
|
||
//
|
||
|
||
PPC586_OPEN_FROM_BINDING_HANDLE(
|
||
Reserved->MacBindingHandle
|
||
)->References--;
|
||
|
||
}
|
||
|
||
//
|
||
// Since we've given back some ring entries we should
|
||
// open of stage3 if it was closed and we are not resetting.
|
||
//
|
||
|
||
if ((!Adapter->Stage3Open) && (!Adapter->ResetInProgress)) {
|
||
|
||
Adapter->Stage3Open = TRUE;
|
||
|
||
}
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
return TRUE;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
static
|
||
VOID
|
||
ReturnAdapterResources(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
Routine Description
|
||
Return staged resources.
|
||
|
||
Arguments:
|
||
Adapter - The adapter that the packet came through
|
||
|
||
Return Value:
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NdisAcquireSpinLock(&Adapter->Lock);
|
||
//
|
||
// If stage 2 as closed and we aren't resetting then open
|
||
// it back up.
|
||
//
|
||
|
||
if ((!Adapter->Stage2Open) && (!Adapter->ResetInProgress)) {
|
||
Adapter->Stage2Open = TRUE;
|
||
}
|
||
|
||
NdisReleaseSpinLock(&Adapter->Lock);
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
LoadMCAddress(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Download multicast addresses to 82586 chip by using a 586 command.
|
||
|
||
Arguments:
|
||
|
||
Adapter - the network chip to be loaded with multicast addresses.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
|
||
PSCB Scb;
|
||
PCMD Cb;
|
||
ULONG xx;
|
||
UINT PacketFilters;
|
||
|
||
Scb = Adapter->Scb;
|
||
Cb = Adapter->Cb;
|
||
|
||
// first ack the status bits
|
||
WaitScb(Adapter);
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
|
||
//
|
||
// Set up the address filtering.
|
||
//
|
||
// First get hold of the combined packet filter.
|
||
//
|
||
|
||
PacketFilters = MAC_QUERY_FILTER_CLASSES(Adapter->FilterDB);
|
||
|
||
if (PacketFilters & NDIS_PACKET_TYPE_PROMISCUOUS) {
|
||
|
||
DbgPrint("PC586 driver - promiscuous mode not supported\n");
|
||
|
||
} else if (PacketFilters & NDIS_PACKET_TYPE_ALL_MULTICAST) {
|
||
|
||
DbgPrint("PC586 driver - all multicast mode not supported\n");
|
||
|
||
} else if (PacketFilters & NDIS_PACKET_TYPE_MULTICAST) {
|
||
|
||
//
|
||
// At least one open binding wants multicast addresses.
|
||
//
|
||
|
||
USHORT MulticastAddresses[MAX_MULTICAST_ADDRESS]
|
||
[ MAC_LENGTH_OF_ADDRESS / 2 ];
|
||
UINT NumberOfAddresses;
|
||
|
||
MacQueryFilterAddresses(
|
||
Adapter->FilterDB,
|
||
&NumberOfAddresses,
|
||
(PCHAR)MulticastAddresses
|
||
);
|
||
|
||
ASSERT(sizeof(UINT) == 4);
|
||
|
||
if (NumberOfAddresses == 0) return;
|
||
|
||
for (
|
||
xx = 0;
|
||
xx < NumberOfAddresses;
|
||
xx++
|
||
) {
|
||
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][0] =
|
||
MulticastAddresses[xx][0];
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][1] =
|
||
MulticastAddresses[xx][1];
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][2] =
|
||
MulticastAddresses[xx][2];
|
||
|
||
/* 8888
|
||
yy.c.b = MulticastAddresses[xx][2];
|
||
zz.c.a[0] = yy.c.a[1];
|
||
zz.c.a[1] = yy.c.a[0];
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][0] = zz.c.b;
|
||
|
||
yy.c.b = MulticastAddresses[xx][1];
|
||
zz.c.a[0] = yy.c.a[1];
|
||
zz.c.a[1] = yy.c.a[0];
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][1] = zz.c.b;
|
||
|
||
yy.c.b = MulticastAddresses[xx][0];
|
||
zz.c.a[0] = yy.c.a[1];
|
||
zz.c.a[1] = yy.c.a[0];
|
||
Cb->PRMTR.PrmMcSet.McAddress[xx][2] = zz.c.b;
|
||
8888 */
|
||
}
|
||
|
||
// McCnt is the total number of bytes in the McAddress[] field
|
||
Cb->PRMTR.PrmMcSet.McCnt = (USHORT)NumberOfAddresses * 6;
|
||
|
||
|
||
// now do the multicast address command
|
||
WaitScb(Adapter);
|
||
Cb->CmdStatus = 0;
|
||
Cb->CmdCmd = CSCMDMCSET | CSEL;
|
||
Scb->ScbCmd = SCBCUCSTRT;
|
||
ChanAttn(Adapter);
|
||
WaitScb(Adapter);
|
||
for(xx=0; xx<0xfffff; xx++)
|
||
if (Cb->CmdStatus & CSOK) {
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
return;
|
||
}
|
||
|
||
DbgPrint("pc586 LoadMCAddress() mc command failed\n");
|
||
return;
|
||
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
ShuvWord(
|
||
IN PUSHORT VirtAddr,
|
||
IN USHORT Value
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Utility to write to pc586 memory mapped hardware.
|
||
|
||
Arguments:
|
||
|
||
VirtAddr - virtual address of the memory mapped item.
|
||
|
||
Value - what's to be written at memory mapped address.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
{
|
||
*VirtAddr = Value;
|
||
}
|
||
|
||
|
||
VOID
|
||
ShuvByte(
|
||
IN PUCHAR VirtAddr,
|
||
IN UCHAR Value
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Same as ShuvWord only for 8-bit quantity.
|
||
|
||
Arguments:
|
||
|
||
See ShuvWord
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
{
|
||
*VirtAddr = Value;
|
||
}
|
||
|
||
|
||
USHORT
|
||
PullWord(
|
||
IN PUSHORT VirtAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets a 16-bit quantity at a given pc586 memory mapped hardware address.
|
||
|
||
Arguments:
|
||
|
||
VirtAddr - address at which to retrieve a value.
|
||
|
||
Return Value:
|
||
|
||
The data at VirtAddr address.
|
||
|
||
--*/
|
||
{
|
||
USHORT Value;
|
||
return (Value = *VirtAddr);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
BuildCu(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets up 586 command unit data structures.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to the memory map of the net card to be set up.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PCMD Cb;
|
||
PTBD Tbd;
|
||
PSCP Scp;
|
||
PISCP Iscp;
|
||
PSCB Scb;
|
||
|
||
Cb = Adapter->Cb;
|
||
Tbd = Adapter->Tbd;
|
||
Scp = Adapter->Scp;
|
||
Iscp = Adapter->Iscp;
|
||
Scb = Adapter->Scb;
|
||
|
||
Scp->ScpSysBus = 0;
|
||
Scp->ScpIscp = OFFSETISCP;
|
||
Scp->ScpIscpBase = 0;
|
||
|
||
Iscp->IscpBusy = 1;
|
||
Iscp->IscpScbOfst = OFFSETSCB;
|
||
Iscp->IscpScbBase = 0;
|
||
|
||
Scb->ScbStatus = 0;
|
||
Scb->ScbCmd = 0;
|
||
Scb->ScbCblOfst = OFFSETCU;
|
||
Scb->ScbRfaOfst = OFFSETRU;
|
||
Scb->ScbCrcErr = 0;
|
||
Scb->ScbAlnErr = 0;
|
||
Scb->ScbRscErr = 0;
|
||
Scb->ScbOvrnErr = 0;
|
||
|
||
Cb->CmdStatus = 0;
|
||
Cb->CmdCmd = CSEL;
|
||
Cb->CmdNxtOfst = OFFSETCU;
|
||
|
||
Tbd->TbdCount = 0;
|
||
Tbd->TbdNxtOfst = 0xffff;
|
||
Tbd->TbdBuff = 0;
|
||
Tbd->TbdBuffBase = 0;
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
BuildRu(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sets up the receive data structures for 586 receive unit.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to net card's memory map to be written on.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PFD Fd;
|
||
ULONG xx;
|
||
|
||
typedef struct _RUBUF {
|
||
RBD r;
|
||
CHAR RbdPad[2]; // puts RBuffer on 4 byte boundry
|
||
UCHAR RBuffer[RCVBUFSIZE];
|
||
} RUBUF, *PRUBUF;
|
||
|
||
PRUBUF Rbd;
|
||
|
||
|
||
// FIRST BUILD THE FRAME DESCRIPTOR LIST
|
||
|
||
Fd = (PFD)(Adapter->StaticRam + OFFSETRU);
|
||
|
||
for (xx=0; xx<NFD; xx++) {
|
||
Fd->FdStatus = 0;
|
||
Fd->FdCmd = 0;
|
||
// point to the next fd
|
||
Fd->FdNxtOfst = VirtToPc586(Adapter, (PUCHAR)(Fd +1));
|
||
Fd->FdRbdOfst = 0xffff; // must be 0xffff, see manual
|
||
Fd++;
|
||
}
|
||
Adapter->EndFd = --Fd;
|
||
Fd->FdNxtOfst = OFFSETRU; // Fd's are now in a circular list
|
||
Fd->FdCmd = CSEL | CSSUSPND; // end of receive Fd list
|
||
|
||
Fd = Adapter->BeginFd =(PFD)(Adapter->StaticRam + OFFSETRU);
|
||
|
||
// SECOND BUILD THE RECEIVE BUFFER DESCRIPTOR LIST
|
||
|
||
Rbd = (PRUBUF)(Adapter->StaticRam + OFFSETRBD);
|
||
Adapter->BeginRbd = (PRBD)(Adapter->StaticRam + OFFSETRBD);
|
||
|
||
// make the first Fd point to the first Rbd
|
||
Fd->FdRbdOfst = VirtToPc586(Adapter, (PUCHAR)Rbd);
|
||
|
||
for(xx=0; xx<NRBD; xx++) {
|
||
Rbd->r.RbdStatus = 0;
|
||
Rbd->r.RbdNxtOfst = VirtToPc586(Adapter, (PUCHAR)(Rbd+1) );
|
||
Rbd->r.RbdBuff = VirtToPc586(Adapter, (PUCHAR)Rbd->RBuffer);
|
||
Rbd->r.RbdBuffBase = 0;
|
||
Rbd->r.RbdSize = RCVBUFSIZE;
|
||
Rbd++;
|
||
}
|
||
|
||
// fixup very last Rbd on the list
|
||
Rbd--;
|
||
Adapter->EndRbd = (PRBD)(Rbd);
|
||
Rbd->r.RbdNxtOfst = OFFSETRBD;
|
||
Rbd->r.RbdSize |= CSEL;
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
Diagnose586(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Runs 82586 diagnostics to see if chip is functioning.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to net card in question.
|
||
|
||
Return Value:
|
||
|
||
True - if card checks out ok.
|
||
|
||
--*/
|
||
{
|
||
PSCB Scb;
|
||
PCMD Cb;
|
||
ULONG xx;
|
||
|
||
Scb = Adapter->Scb;
|
||
Cb = Adapter->Cb;
|
||
|
||
// first ack the status bits
|
||
WaitScb(Adapter);
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
|
||
// now do the diagnose
|
||
WaitScb(Adapter);
|
||
Cb->CmdStatus = 0;
|
||
Cb->CmdCmd = CSCMDDGNS | CSEL;
|
||
Scb->ScbCmd = SCBCUCSTRT;
|
||
ChanAttn(Adapter);
|
||
WaitScb(Adapter);
|
||
for(xx=0; xx<0xfff; xx++)
|
||
if (Cb->CmdStatus & CSOK) {
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
Config586(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Configures 586 network chip for standard configuration.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to the netcard that holds 586 to be configured.
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE - if configuration went well.
|
||
|
||
--*/
|
||
{
|
||
PSCB Scb;
|
||
PCMD Cb;
|
||
ULONG xx;
|
||
PUSHORT Addr, Addr2;
|
||
|
||
Scb = Adapter->Scb;
|
||
Cb = Adapter->Cb;
|
||
|
||
// first ack the status bits
|
||
WaitScb(Adapter);
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
|
||
// now do configuration
|
||
WaitScb(Adapter);
|
||
Cb->CmdStatus = 0;
|
||
Cb->CmdCmd = CSCMDCONF | CSEL;
|
||
|
||
Cb->PRMTR.PrmConf.CnfFifoByte = 0x080c;
|
||
Cb->PRMTR.PrmConf.CnfAddMode = 0x2600;
|
||
Cb->PRMTR.PrmConf.CnfPriData = 0x6000;
|
||
Cb->PRMTR.PrmConf.CnfSlot = 0xf200;
|
||
Cb->PRMTR.PrmConf.CnfHrdwr = 0x0000;
|
||
Cb->PRMTR.PrmConf.CnfMinLen = 0x0040;
|
||
|
||
Scb->ScbCmd = SCBCUCSTRT;
|
||
ChanAttn(Adapter);
|
||
WaitScb(Adapter);
|
||
for(xx=0; xx<0xfff; xx++)
|
||
if (Cb->CmdStatus & CSOK) goto c1;
|
||
return FALSE;
|
||
|
||
c1:
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
if (Scb->ScbCmd) ChanAttn(Adapter);
|
||
|
||
// next, download ethernet address to 586 chip
|
||
|
||
WaitScb(Adapter);
|
||
Cb->CmdStatus = 0;
|
||
Cb->CmdCmd = CSCMDIASET | CSEL;
|
||
|
||
|
||
Addr = (PUSHORT)Adapter->NetworkAddress;
|
||
Addr2 = (PUSHORT)Cb->PRMTR.PrmIaSet;
|
||
|
||
for(xx=0; xx<MAC_LENGTH_OF_ADDRESS/2; xx++) {
|
||
*Addr2 = *Addr;
|
||
*Addr2++;
|
||
*Addr++;
|
||
}
|
||
|
||
Scb->ScbCmd = SCBCUCSTRT;
|
||
ChanAttn(Adapter);
|
||
|
||
for(xx=0; xx<0xfff; xx++)
|
||
if (Cb->CmdStatus & CSOK) goto c2;
|
||
return FALSE;
|
||
|
||
c2:
|
||
Scb->ScbCmd = (USHORT)(Scb->ScbStatus & SCBINTMSK);
|
||
ChanAttn(Adapter);
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
|
||
USHORT
|
||
PromAddr(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN ULONG Index
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Pulls the unique enet id out of the netcard's special eprom.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to the card to get the address from.
|
||
|
||
Index - index of which byte of enet address to get.
|
||
|
||
Return Value:
|
||
|
||
Bytes of e-net address.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUCHAR CmdProm;
|
||
|
||
CmdProm = Adapter->CmdProm;
|
||
CmdProm += OFFSETADDRPROM;
|
||
CmdProm += Index;
|
||
return *CmdProm;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
ChanAttn(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Tickles the network card to get the 82586's attention.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to the card in question.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
// first byte of word is 1 - this sets the CA
|
||
// second byte of word is 0 - this clears the CA
|
||
|
||
ShuvWord(Adapter->CAAddr, 0x01);
|
||
}
|
||
|
||
|
||
VOID
|
||
WaitScb(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine waits a reasonable length of time for the 586 to
|
||
read and dispatch a previous command.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to net card in question
|
||
|
||
Return Value:
|
||
|
||
TRUE - if 586 failed.
|
||
|
||
FALSE - if 586 dispatched previous command within time limit.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSCB Scb;
|
||
ULONG xx;
|
||
|
||
Scb = Adapter->Scb;
|
||
for (xx=0; xx<0xffff; xx++)
|
||
if (Scb->ScbCmd == 0) return;
|
||
DbgPrint("pc586 WaitScb() - timed out\n");
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
USHORT
|
||
VirtToPc586(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN PUCHAR KernelVirtAddr
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The CPU's 32-bit addresses are converted to 16-bit addresses that are
|
||
compatible with 82586.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to net card in question.
|
||
|
||
KernelVirtAddr - the address to be converted.
|
||
|
||
Return Value:
|
||
|
||
586 style address.
|
||
|
||
--*/
|
||
|
||
{
|
||
USHORT Addr586;
|
||
|
||
// 586 uses 0xffff for null as "c" uses zero for null
|
||
if (KernelVirtAddr == NULL)
|
||
return 0xffff;
|
||
|
||
if ( (KernelVirtAddr > Adapter->StaticRam + 32*1024 ) ||
|
||
(KernelVirtAddr < Adapter->StaticRam -1 ) ) {
|
||
|
||
DbgPrint("VirtToPc586(): wild kernel virt addr of 0x%x\n",
|
||
KernelVirtAddr);
|
||
return 0xffff;
|
||
}
|
||
Addr586 = (USHORT)(KernelVirtAddr - Adapter->StaticRam);
|
||
return Addr586;
|
||
}
|
||
|
||
PUCHAR
|
||
Pc586ToVirt(
|
||
IN PPC586_ADAPTER Adapter,
|
||
IN USHORT Addr586
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Converts from 82586 style 16-bit address to flat 32-bit CPU address.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to network card in question.
|
||
|
||
Addr586 - 586 16-bit address to be converted.
|
||
|
||
Return Value:
|
||
|
||
A flat 32-bit CPU address.
|
||
|
||
--*/
|
||
{
|
||
if (Addr586 == 0xffff) return NULL;
|
||
|
||
if (Addr586 > 0x7fff) {
|
||
DbgPrint("Pc586ToVirt(): wild 586 pointer of 0x%x\n", Addr586);
|
||
return NULL;
|
||
}
|
||
|
||
return (Adapter->StaticRam + Addr586);
|
||
|
||
}
|
||
|
||
|
||
|
||
static
|
||
VOID
|
||
Pc586IntOn(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Flips a switch on the network card to connect 586 interrupts to host CPU.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to network card in question.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
|
||
--*/
|
||
{
|
||
ShuvWord( (PUSHORT)(Adapter->IntAddr),
|
||
(USHORT)CMD1 );
|
||
}
|
||
|
||
static
|
||
VOID
|
||
Pc586IntOff(
|
||
IN PPC586_ADAPTER Adapter
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Flips switch on network card to disconnect 586 interrupts from
|
||
host CPU.
|
||
|
||
Arguments:
|
||
|
||
Adapter - points to netcard in question.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ShuvWord( (PUSHORT)(Adapter->IntAddr),
|
||
(USHORT)CMD0 );
|
||
}
|