- Compile with W32API headers.

- Add multicast support.
- Add media state detection support.
- Protect the adapter context with spinlock and move code talking to card to inside NdisMSynchronizeWithInterrupt calls where necessary.

svn path=/trunk/; revision=11301
This commit is contained in:
Filip Navara 2004-10-17 01:55:54 +00:00
parent 3d1e209ba7
commit d788739c0e
4 changed files with 263 additions and 109 deletions

View file

@ -6,9 +6,9 @@ TARGET_NAME = pcnet
# - must define NDIS50 to get the right characteristics struct
# - must define anonymous unions to make physical addresses work right
#
TARGET_CFLAGS = -I. -Wall -Werror -DNDIS50 -DANONYMOUSUNIONS
# TARGET_CFLAGS += -I$(W32API_PATH)/include/ddk -D__USE_W32API
TARGET_CFLAGS = -I. -Wall -Werror -DNDIS50_MINIPORT
TARGET_CFLAGS += -I$(W32API_PATH)/include/ddk -D__USE_W32API
# TARGET_CFLAGS += -DDBG=1
TARGET_OBJECTS = pcnet.o requests.o
TARGET_DDKLIBS = ndis.a

View file

@ -27,9 +27,14 @@
* - Don't read slot number from registry and
* report itself as NDIS 5.0 miniport.
* 11-Oct-2004 navaraf - Fix nasty bugs in halt code path.
* 17-Oct-2004 navaraf - Add multicast support.
* - Add media state detection support.
* - Protect the adapter context with spinlock
* and move code talking to card to inside
* NdisMSynchronizeWithInterrupt calls where
* necessary.
*
* NOTES:
* - this is hard-coded to NDIS5
* - this assumes a 32-bit machine
*/
@ -52,15 +57,11 @@ MiniportHandleInterrupt(
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
USHORT Data;
#if DBG
BOOLEAN ReceiveHandled = FALSE;
BOOLEAN ErrorHandled = FALSE;
BOOLEAN IdonHandled = FALSE;
BOOLEAN TransmitHandled = FALSE;
#endif
PCNET_DbgPrint(("Called\n"));
NdisDprAcquireSpinLock(&Adapter->Lock);
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
@ -73,46 +74,16 @@ MiniportHandleInterrupt(
if(Data & CSR0_ERR)
{
#if DBG
if(ErrorHandled)
{
PCNET_DbgPrint(("ERROR HANDLED TWO TIMES\n"));
ASSERT(0);
}
ErrorHandled = TRUE;
#endif
PCNET_DbgPrint(("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS)))
if (Data & CSR0_CERR)
Adapter->Statistics.XmtCollisions++;
}
else if(Data & CSR0_IDON)
{
#if DBG
if(IdonHandled)
{
PCNET_DbgPrint(("IDON HANDLED TWO TIMES\n"));
ASSERT(0);
}
IdonHandled = TRUE;
#endif
PCNET_DbgPrint(("IDON\n"));
}
else if(Data & CSR0_RINT)
{
#if DBG
if(ReceiveHandled)
{
PCNET_DbgPrint(("RECEIVE HANDLED TWO TIMES\n"));
ASSERT(0);
}
ReceiveHandled = TRUE;
#endif
PCNET_DbgPrint(("receive interrupt\n"));
while(1)
@ -171,16 +142,6 @@ MiniportHandleInterrupt(
{
PTRANSMIT_DESCRIPTOR Descriptor;
#if DBG
if(TransmitHandled)
{
PCNET_DbgPrint(("TRANSMIT HANDLED TWO TIMES\n"));
ASSERT(0);
}
TransmitHandled = TRUE;
#endif
PCNET_DbgPrint(("transmit interrupt\n"));
while (Adapter->CurrentTransmitStartIndex !=
@ -198,6 +159,14 @@ MiniportHandleInterrupt(
break;
}
if (Descriptor->FLAGS & TD1_STP)
{
if (Descriptor->FLAGS & TD1_ONE)
Adapter->Statistics.XmtOneRetry++;
else if (Descriptor->FLAGS & TD1_MORE)
Adapter->Statistics.XmtMoreThanOneRetry++;
}
if (Descriptor->FLAGS & TD1_ERR)
{
PCNET_DbgPrint(("major error: %x\n", Descriptor->FLAGS2));
@ -237,6 +206,8 @@ MiniportHandleInterrupt(
NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
PCNET_DbgPrint(("CSR0 is now 0x%x\n", Data));
NdisDprAcquireSpinLock(&Adapter->Lock);
}
NDIS_STATUS
@ -546,6 +517,22 @@ MiFreeSharedMemory(
}
}
BOOLEAN
STDCALL
MiSyncStop(
IN PVOID SynchronizeContext)
/*
* FUNCTION: Stop the adapter
* ARGUMENTS:
* SynchronizeContext: Adapter context
*/
{
PADAPTER Adapter = (PADAPTER)SynchronizeContext;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
return TRUE;
}
VOID
STDCALL
MiniportHalt(
@ -559,13 +546,16 @@ MiniportHalt(
*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
BOOLEAN TimerCancelled;
PCNET_DbgPrint(("Called\n"));
ASSERT(Adapter);
/* stop the media detection timer */
NdisMCancelTimer(&Adapter->MediaDetectionTimer, &TimerCancelled);
/* stop the chip */
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStop, Adapter);
/* deregister the interrupt */
NdisMDeregisterInterrupt(&Adapter->InterruptObject);
@ -579,10 +569,65 @@ MiniportHalt(
/* free map registers */
NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
/* free the lock */
NdisFreeSpinLock(&Adapter->Lock);
/* free the adapter */
NdisFreeMemory(Adapter, 0, 0);
}
BOOLEAN
STDCALL
MiSyncMediaDetection(
IN PVOID SynchronizeContext)
/*
* FUNCTION: Stop the adapter
* ARGUMENTS:
* SynchronizeContext: Adapter context
*/
{
PADAPTER Adapter = (PADAPTER)SynchronizeContext;
NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter);
PCNET_DbgPrint(("Called\n"));
PCNET_DbgPrint(("MediaState: %d\n", MediaState));
if (MediaState != Adapter->MediaState)
{
Adapter->MediaState = MediaState;
return TRUE;
}
return FALSE;
}
VOID
STDCALL
MiniportMediaDetectionTimer(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3)
/*
* FUNCTION: Periodially query media state
* ARGUMENTS:
* FunctionContext: Adapter context
* NOTES:
* - Called by NDIS at DISPATCH_LEVEL
*/
{
PADAPTER Adapter = (PADAPTER)FunctionContext;
if (NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject,
MiSyncMediaDetection,
FunctionContext))
{
NdisMIndicateStatus(Adapter->MiniportAdapterHandle,
Adapter->MediaState == NdisMediaStateConnected ?
NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
(PVOID)0, 0);
NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
}
}
VOID
MiInitChip(
PADAPTER Adapter)
@ -655,6 +700,11 @@ MiInitChip(
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
/* detect the media state */
NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE|BCR4_FDLSE/*|BCR4_XMTE|BCR4_RCVME|BCR4_MPSE|BCR4_JABE*/);
Adapter->MediaState = MiGetMediaState(Adapter);
PCNET_DbgPrint(("card started\n"));
Adapter->Flags &= ~RESET_IN_PROGRESS;
@ -849,6 +899,8 @@ MiniportInitialize(
/* Initialize and start the chip */
MiInitChip(Adapter);
NdisAllocateSpinLock(&Adapter->Lock);
Status = NDIS_STATUS_SUCCESS;
}
while(0);
@ -870,6 +922,16 @@ MiniportInitialize(
NdisFreeMemory(Adapter, 0, 0);
}
if(Status == NDIS_STATUS_SUCCESS)
{
NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
Adapter->MiniportAdapterHandle,
MiniportMediaDetectionTimer,
Adapter);
NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
MEDIA_DETECTION_INTERVAL);
}
#if DBG
if(!MiTestCard(Adapter))
ASSERT(0);
@ -958,6 +1020,22 @@ MiniportReset(
return NDIS_STATUS_SUCCESS;
}
BOOLEAN
STDCALL
MiSyncStartTransmit(
IN PVOID SynchronizeContext)
/*
* FUNCTION: Stop the adapter
* ARGUMENTS:
* SynchronizeContext: Adapter context
*/
{
PADAPTER Adapter = (PADAPTER)SynchronizeContext;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD);
return TRUE;
}
NDIS_STATUS
STDCALL
MiniportSend(
@ -985,6 +1063,8 @@ MiniportSend(
PCNET_DbgPrint(("Called\n"));
NdisDprAcquireSpinLock(&Adapter->Lock);
/* Check if we have free entry in our circular buffer. */
if ((Adapter->CurrentTransmitEndIndex + 1 ==
Adapter->CurrentTransmitStartIndex) ||
@ -992,6 +1072,7 @@ MiniportSend(
Adapter->CurrentTransmitStartIndex == 0))
{
PCNET_DbgPrint(("No free space in circular buffer\n"));
NdisDprReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_RESOURCES;
}
@ -1017,7 +1098,7 @@ MiniportSend(
NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
}
#if DBG
#if DBG && 0
{
PUCHAR Ptr = Adapter->TransmitBufferPtrVirt +
Adapter->CurrentTransmitEndIndex * BUFFER_SIZE;
@ -1037,12 +1118,73 @@ MiniportSend(
Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
Desc->BCNT = 0xf000 | -TotalPacketLength;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD);
NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
NdisDprReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_SUCCESS;
}
ULONG
STDCALL
MiEthernetCrc(UCHAR *Address)
/*
* FUNCTION: Calculate Ethernet CRC32
* ARGUMENTS:
* Address: 6-byte ethernet address
* RETURNS:
* The calculated CRC32 value.
*/
{
UINT Counter, Length;
ULONG Value = ~0;
for (Length = 0; Length < 6; Length++)
{
Value ^= *Address++;
for (Counter = 0; Counter < 8; Counter++)
{
Value >>= 1;
Value ^= (Value & 1) * 0xedb88320;
}
}
return Value;
}
NDIS_STATUS
STDCALL
MiSetMulticast(
PADAPTER Adapter,
UCHAR *Addresses,
UINT AddressCount)
{
UINT Index;
ULONG CrcIndex;
NdisZeroMemory(Adapter->InitializationBlockVirt->LADR, 8);
for (Index = 0; Index < AddressCount; Index++)
{
CrcIndex = MiEthernetCrc(Addresses) >> 26;
Adapter->InitializationBlockVirt->LADR[CrcIndex >> 3] |= 1 << (CrcIndex & 15);
Addresses += 6;
}
/* FIXME: The specification mentions we need to reload the init block here. */
return NDIS_STATUS_SUCCESS;
}
NDIS_MEDIA_STATE
STDCALL
MiGetMediaState(PADAPTER Adapter)
{
ULONG Data;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected;
}
NTSTATUS
STDCALL
DriverEntry(
@ -1066,8 +1208,8 @@ DriverEntry(
NDIS_STATUS Status;
RtlZeroMemory(&Characteristics, sizeof(Characteristics));
Characteristics.MajorNdisVersion = NDIS_MAJOR_VERSION;
Characteristics.MinorNdisVersion = NDIS_MINOR_VERSION;
Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
Characteristics.HaltHandler = MiniportHalt;
Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
Characteristics.InitializeHandler = MiniportInitialize;
@ -1075,7 +1217,7 @@ DriverEntry(
Characteristics.QueryInformationHandler = MiniportQueryInformation;
Characteristics.ResetHandler = MiniportReset;
Characteristics.SetInformationHandler = MiniportSetInformation;
Characteristics.u1.SendHandler = MiniportSend;
Characteristics.SendHandler = MiniportSend;
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);

View file

@ -28,19 +28,6 @@
#ifndef _PCNET_H_
#define _PCNET_H_
/* FIXME: We should use a general way to do this for all drivers. */
#ifdef __GNUC__
#define memcpy(a,b,c) __builtin_memcpy(a,b,c)
#define memset(a,b,c) __builtin_memset(a,b,c)
#undef RtlFillMemory
#define RtlFillMemory(a,b,c) __builtin_memset(a,b,c)
#undef RtlZeroMemory
#define RtlZeroMemory(a,b) __builtin_memset(a,0,b)
#endif
#define NDIS_MAJOR_VERSION 5
#define NDIS_MINOR_VERSION 0
/* statistics struct */
typedef struct _ADAPTER_STATS
{
@ -52,6 +39,8 @@ typedef struct _ADAPTER_STATS
ULONG XmtExcessiveDefferals;
ULONG XmtBufferUnderflows;
ULONG XmtBufferErrors;
ULONG XmtOneRetry;
ULONG XmtMoreThanOneRetry;
ULONG RcvGoodFrames;
ULONG RcvBufferErrors;
ULONG RcvCrcErrors;
@ -62,12 +51,16 @@ typedef struct _ADAPTER_STATS
/* adapter struct */
typedef struct _ADAPTER
{
NDIS_SPIN_LOCK Lock;
NDIS_HANDLE MiniportAdapterHandle;
ULONG Flags;
ULONG InterruptVector;
ULONG IoBaseAddress;
PVOID PortOffset;
NDIS_MINIPORT_INTERRUPT InterruptObject;
NDIS_MEDIA_STATE MediaState;
NDIS_MINIPORT_TIMER MediaDetectionTimer;
ULONG CurrentReceiveDescriptorIndex;
ULONG CurrentPacketFilter;
ULONG CurrentLookaheadSize;
@ -125,10 +118,23 @@ MiniportSetInformation(
OUT PULONG BytesRead,
OUT PULONG BytesNeeded);
NDIS_STATUS
STDCALL
MiSetMulticast(
PADAPTER Adapter,
UCHAR *Addresses,
UINT AddressCount);
NDIS_MEDIA_STATE
STDCALL
MiGetMediaState(PADAPTER Adapter);
/* operational constants */
#define NUMBER_OF_BUFFERS 0x20
#define LOG_NUMBER_OF_BUFFERS 5 /* log2(NUMBER_OF_BUFFERS) */
#define BUFFER_SIZE 0x600
#define MAX_MULTICAST_ADDRESSES 32
#define MEDIA_DETECTION_INTERVAL 5000
/* flags */
#define RESET_IN_PROGRESS 0x1

View file

@ -24,7 +24,13 @@
* borrowed very heavily from the ReactOS ne2000 driver by
* Casper S. Hornstrup (chorns@users.sourceforge.net)
* REVISIONS:
* 14-Sept-2003 vizzini - Created
* 14-Sep-2003 vizzini - Created
* 17-Oct-2004 navaraf - Add multicast support.
* - Add media state detection support.
* - Protect the adapter context with spinlock
* and move code talking to card to inside
* NdisMSynchronizeWithInterrupt calls where
* necessary.
*/
#include <ndis.h>
@ -61,6 +67,7 @@ static ULONG MiniportOIDList[] =
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_GEN_RCV_CRC_ERROR,
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
@ -110,6 +117,8 @@ MiniportQueryInformation(
ASSERT(Adapter);
NdisAcquireSpinLock(&Adapter->Lock);
Status = NDIS_STATUS_SUCCESS;
CopyFrom = (PVOID)&GenericULONG;
CopySize = sizeof(ULONG);
@ -191,15 +200,20 @@ MiniportQueryInformation(
case OID_GEN_VENDOR_ID:
{
GenericULONG = 0x1022;
UCHAR *CharPtr = (UCHAR *)&GenericULONG;
GenericULONG = 0;
/* Read the first three bytes of the permanent MAC address */
NdisRawReadPortUchar(Adapter->PortOffset, CharPtr);
NdisRawReadPortUchar(Adapter->PortOffset + 1, CharPtr + 1);
NdisRawReadPortUchar(Adapter->PortOffset + 2, CharPtr + 2);
break;
}
case OID_GEN_VENDOR_DESCRIPTION:
{
/* XXX implement me */
CopyFrom = 0;
CopySize = 0;
static UCHAR VendorDesc[] = "ReactOS Team";
CopyFrom = VendorDesc;
CopySize = sizeof(VendorDesc);
break;
}
@ -220,7 +234,7 @@ MiniportQueryInformation(
{
/* NDIS version used by the driver. */
static const USHORT DriverVersion =
(NDIS_MAJOR_VERSION << 8) + NDIS_MINOR_VERSION;
(NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION;
CopyFrom = (PVOID)&DriverVersion;
CopySize = sizeof(DriverVersion);
break;
@ -244,14 +258,13 @@ MiniportQueryInformation(
{
GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_NO_LOOPBACK;
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND;
break;
}
case OID_GEN_MEDIA_CONNECT_STATUS:
{
GenericULONG = (ULONG)NdisMediaStateConnected;
GenericULONG = Adapter->MediaState;
break;
}
@ -269,29 +282,12 @@ MiniportQueryInformation(
break;
}
case OID_802_3_MULTICAST_LIST:
{
/* XXX Implement me */
PCNET_DbgPrint(("OID_802_3_MULTICAST_LIST.\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
case OID_802_3_MAXIMUM_LIST_SIZE:
{
/* XXX Implement me */
GenericULONG = 0;
GenericULONG = MAX_MULTICAST_ADDRESSES;
break;
}
case OID_802_3_MAC_OPTIONS:
{
/* XXX Implement me */
PCNET_DbgPrint(("OID_802_3_MAC_OPTIONS.\n"));
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
case OID_GEN_XMIT_OK:
GenericULONG = Adapter->Statistics.XmtGoodFrames;
break;
@ -318,29 +314,30 @@ MiniportQueryInformation(
break;
case OID_GEN_RCV_NO_BUFFER:
/* FIXME: Is this correct? */
GenericULONG = Adapter->Statistics.RcvBufferErrors;
GenericULONG = Adapter->Statistics.RcvBufferErrors +
Adapter->Statistics.RcvOverflowErrors;
break;
case OID_GEN_RCV_CRC_ERROR:
GenericULONG = Adapter->Statistics.RcvCrcErrors;
break;
case OID_802_3_RCV_ERROR_ALIGNMENT:
/* XXX Implement me */
GenericULONG = 0;
GenericULONG = Adapter->Statistics.RcvFramingErrors;
break;
case OID_802_3_XMIT_ONE_COLLISION:
/* FIXME: Is this correct? */
GenericULONG = Adapter->Statistics.XmtCollisions;
GenericULONG = Adapter->Statistics.XmtOneRetry;
break;
case OID_802_3_XMIT_MORE_COLLISIONS:
/* FIXME: Is this correct? */
GenericULONG = Adapter->Statistics.XmtLateCollisions;
GenericULONG = Adapter->Statistics.XmtMoreThanOneRetry;
break;
default:
{
PCNET_DbgPrint(("Unknown OID\n"));
Status = NDIS_STATUS_INVALID_OID;
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
}
@ -361,6 +358,8 @@ MiniportQueryInformation(
}
}
NdisReleaseSpinLock(&Adapter->Lock);
PCNET_DbgPrint(("Leaving. Status is 0x%x\n", Status));
return Status;
@ -400,6 +399,8 @@ MiniportSetInformation(
PCNET_DbgPrint(("Called, OID 0x%x\n", Oid));
NdisAcquireSpinLock(&Adapter->Lock);
switch (Oid)
{
case OID_GEN_CURRENT_PACKET_FILTER:
@ -470,10 +471,13 @@ MiniportSetInformation(
break;
}
ASSERT((InformationBufferLength / 6) <= MAX_MULTICAST_ADDRESSES);
/* Set new multicast address list */
//NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength);
/* FIXME: Update hardware */
/* Update hardware */
Status = MiSetMulticast(Adapter, InformationBuffer, InformationBufferLength / 6);
break;
}
@ -483,7 +487,7 @@ MiniportSetInformation(
PCNET_DbgPrint(("Invalid object ID (0x%X).\n", Oid));
*BytesRead = 0;
*BytesNeeded = 0;
Status = NDIS_STATUS_INVALID_OID;
Status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
}
@ -494,6 +498,8 @@ MiniportSetInformation(
*BytesNeeded = 0;
}
NdisReleaseSpinLock(&Adapter->Lock);
PCNET_DbgPrint(("Leaving. Status (0x%X).\n", Status));
return Status;