📄 pcnet.c
字号:
Status = NDIS_STATUS_RESOURCES;
DPRINT1("Insufficient resources\n");
BREAKPOINT;
*OpenErrorStatus = Status;
return Status;
}
RtlZeroMemory(Adapter, sizeof(ADAPTER));
Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
/* register our adapter structwith ndis */
NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
do
{
/* Card-specific detection and setup */
Status = MiQueryCard(Adapter);
if(Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("MiQueryCard failed\n");
Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
BREAKPOINT;
break;
}
/* register an IO port range */
Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->PortOffset, Adapter->MiniportAdapterHandle,
(UINT)Adapter->IoBaseAddress, NUMBER_OF_PORTS);
if(Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("NdisMRegisterIoPortRange failed: 0x%x\n", Status);
BREAKPOINT
break;
}
/* Allocate map registers */
Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0,
NDIS_DMA_32BITS, 8, BUFFER_SIZE);
if(Status != NDIS_STATUS_SUCCESS)
{
DPRINT1("NdisMAllocateMapRegisters failed: 0x%x\n", Status);
BREAKPOINT
break;
}
/* set up the interrupt */
Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector,
Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive);
if(Status != NDIS_STATUS_SUCCESS)
{
DPRINT("NdisMRegisterInterrupt failed: 0x%x\n", Status);
BREAKPOINT
break;
}
InterruptRegistered = TRUE;
/* Allocate and initialize shared data structures */
Status = MiAllocateSharedMemory(Adapter);
if(Status != NDIS_STATUS_SUCCESS)
{
Status = NDIS_STATUS_RESOURCES;
DPRINT("MiAllocateSharedMemory failed", Status);
BREAKPOINT
break;
}
/* set up the initialization block */
MiPrepareInitializationBlock(Adapter);
DPRINT("Interrupt registered successfully\n");
/* Initialize and start the chip */
MiInitChip(Adapter);
NdisAllocateSpinLock(&Adapter->Lock);
Status = NDIS_STATUS_SUCCESS;
}
while(0);
if(Status != NDIS_STATUS_SUCCESS && Adapter)
{
DPRINT("Error; freeing stuff\n");
NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); /* doesn't hurt to free if we never alloc'd? */
if(Adapter->PortOffset)
NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
if(InterruptRegistered)
NdisMDeregisterInterrupt(&Adapter->InterruptObject);
MiFreeSharedMemory(Adapter);
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);
#endif
DPRINT("returning 0x%x\n", Status);
*OpenErrorStatus = Status;
return Status;
}
static VOID
STDCALL
MiniportISR(
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext)
/*
* FUNCTION: Miniport interrupt service routine
* ARGUMENTS:
* InterruptRecognized: the interrupt was ours
* QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
* MiniportAdapterContext: the context originally passed to NdisMSetAttributes
* NOTES:
* - called by NDIS at DIRQL
* - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
* will be called
*/
{
USHORT Data;
USHORT Rap;
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
DPRINT("Called\n");
/* save the old RAP value */
NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
/* is this ours? */
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
if(!(Data & CSR0_INTR))
{
DPRINT("not our interrupt.\n");
*InterruptRecognized = FALSE;
*QueueMiniportHandleInterrupt = FALSE;
}
else
{
DPRINT("detected our interrupt\n");
/* disable interrupts */
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
*InterruptRecognized = TRUE;
*QueueMiniportHandleInterrupt = TRUE;
}
/* restore the rap */
NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
}
static NDIS_STATUS
STDCALL
MiniportReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext)
/*
* FUNCTION: Reset the miniport
* ARGUMENTS:
* AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
* to reset our addresses and filters
* MiniportAdapterContext: context originally passed to NdisMSetAttributes
* RETURNS:
* NDIS_STATUS_SUCCESS on all requests
* Notes:
* - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
*/
{
DPRINT("Called\n");
/* MiniportReset doesn't do anything at the moment... perhaps this should be fixed. */
*AddressingReset = FALSE;
return NDIS_STATUS_SUCCESS;
}
static 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;
}
static NDIS_STATUS
STDCALL
MiniportSend(
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet,
IN UINT Flags)
/*
* FUNCTION: Called by NDIS when it has a packet for the NIC to send out
* ARGUMENTS:
* MiniportAdapterContext: context originally input to NdisMSetAttributes
* Packet: The NDIS_PACKET to be sent
* Flags: Flags associated with Packet
* RETURNS:
* NDIS_STATUS_SUCCESS on processed requests
* NDIS_STATUS_RESOURCES if there's no place in buffer ring
* NOTES:
* - Called by NDIS at DISPATCH_LEVEL
*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
PTRANSMIT_DESCRIPTOR Desc;
PNDIS_BUFFER NdisBuffer;
PVOID SourceBuffer;
UINT TotalPacketLength, SourceLength, Position = 0;
DPRINT("Called\n");
NdisDprAcquireSpinLock(&Adapter->Lock);
/* Check if we have free entry in our circular buffer. */
if ((Adapter->CurrentTransmitEndIndex + 1 ==
Adapter->CurrentTransmitStartIndex) ||
(Adapter->CurrentTransmitEndIndex == NUMBER_OF_BUFFERS - 1 &&
Adapter->CurrentTransmitStartIndex == 0))
{
DPRINT1("No free space in circular buffer\n");
NdisDprReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_RESOURCES;
}
Desc = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitEndIndex;
NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &TotalPacketLength);
ASSERT(TotalPacketLength <= BUFFER_SIZE);
DPRINT("TotalPacketLength: %x\n", TotalPacketLength);
while (NdisBuffer)
{
NdisQueryBuffer(NdisBuffer, &SourceBuffer, &SourceLength);
DPRINT("Buffer: %x Length: %x\n", SourceBuffer, SourceLength);
RtlCopyMemory(Adapter->TransmitBufferPtrVirt +
Adapter->CurrentTransmitEndIndex * BUFFER_SIZE + Position,
SourceBuffer, SourceLength);
Position += SourceLength;
NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
}
#if DBG && 0
{
PUCHAR Ptr = Adapter->TransmitBufferPtrVirt +
Adapter->CurrentTransmitEndIndex * BUFFER_SIZE;
for (Position = 0; Position < TotalPacketLength; Position++)
{
if (Position % 16 == 0)
DbgPrint("\n");
DbgPrint("%x ", *Ptr++);
}
}
DbgPrint("\n");
#endif
Adapter->CurrentTransmitEndIndex++;
Adapter->CurrentTransmitEndIndex %= NUMBER_OF_BUFFERS;
Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
Desc->BCNT = 0xf000 | -TotalPacketLength;
NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
NdisDprReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_SUCCESS;
}
static 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)
/*
* FUNCTION: Determine the link state
* ARGUMENTS:
* Adapter: Adapter context
* RETURNS:
* NdisMediaStateConnected if the cable is connected
* NdisMediaStateDisconnected if the cable is disconnected
*/
{
ULONG Data;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected;
}
NTSTATUS
STDCALL
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
/*
* FUNCTION: Start this driver
* ARGUMENTS:
* DriverObject: Pointer to the system-allocated driver object
* RegistryPath: Pointer to our SCM database entry
* RETURNS:
* NDIS_STATUS_SUCCESS on success
* NDIS_STATUS_FAILURE on failure
* NOTES:
* - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
* - TODO: convert this to NTSTATUS return values
*/
{
NDIS_HANDLE WrapperHandle;
NDIS_MINIPORT_CHARACTERISTICS Characteristics;
NDIS_STATUS Status;
RtlZeroMemory(&Characteristics, sizeof(Characteristics));
Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
Characteristics.HaltHandler = MiniportHalt;
Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
Characteristics.InitializeHandler = MiniportInitialize;
Characteristics.ISRHandler = MiniportISR;
Characteristics.QueryInformationHandler = MiniportQueryInformation;
Characteristics.ResetHandler = MiniportReset;
Characteristics.SetInformationHandler = MiniportSetInformation;
Characteristics.SendHandler = MiniportSend;
NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
if(Status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(WrapperHandle, 0);
return NDIS_STATUS_FAILURE;
}
return NDIS_STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -