mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4269 lines
100 KiB
4269 lines
100 KiB
/*++
|
|
|
|
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 );
|
|
}
|