Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371/* * ReactOS AMD PCNet Driver * * Copyright (C) 2003 Vizzini <vizzini@plasmic.com> * Copyright (C) 2004 Filip Navara <navaraf@reactos.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * REVISIONS: * 09-Sep-2003 vizzini - Created * 10-Oct-2004 navaraf - Fix receive to work on VMware adapters ( * need to set busmaster bit on PCI). * - Indicate receive completion. * - Implement packet transmitting. * - 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 assumes a 32-bit machine */
#include "pcnet.h"
#define NDEBUG#include <debug.h>
NTSTATUSNTAPIDriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);
static VOIDNTAPIMiniportHandleInterrupt( IN NDIS_HANDLE MiniportAdapterContext)/* * FUNCTION: Handle an interrupt if told to by MiniportISR * ARGUMENTS: * MiniportAdapterContext: context specified to NdisMSetAttributes * NOTES: * - Called by NDIS at DISPATCH_LEVEL */{ PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; USHORT Data; UINT i = 0;
DPRINT("Called\n");
ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
NdisDprAcquireSpinLock(&Adapter->Lock);
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
DPRINT("CSR0 is 0x%x\n", Data);
while((Data & CSR0_INTR) && i++ < INTERRUPT_LIMIT) { /* Clear interrupt flags early to avoid race conditions. */ NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
if(Data & CSR0_ERR) { DPRINT("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS)); if (Data & CSR0_CERR) Adapter->Statistics.XmtCollisions++; } if(Data & CSR0_IDON) { DPRINT("IDON\n"); } if(Data & CSR0_RINT) { BOOLEAN IndicatedData = FALSE;
DPRINT("receive interrupt\n");
while(1) { PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex; PCHAR Buffer; ULONG ByteCount;
if(Descriptor->FLAGS & RD_OWN) { DPRINT("no more receive descriptors to process\n"); break; }
if(Descriptor->FLAGS & RD_ERR) { DPRINT("receive descriptor error: 0x%x\n", Descriptor->FLAGS); if (Descriptor->FLAGS & RD_BUFF) Adapter->Statistics.RcvBufferErrors++; if (Descriptor->FLAGS & RD_CRC) Adapter->Statistics.RcvCrcErrors++; if (Descriptor->FLAGS & RD_OFLO) Adapter->Statistics.RcvOverflowErrors++; if (Descriptor->FLAGS & RD_FRAM) Adapter->Statistics.RcvFramingErrors++; break; }
if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP))) { DPRINT("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS); break; }
Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE; ByteCount = Descriptor->MCNT & 0xfff;
DPRINT("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex);
NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
IndicatedData = TRUE;
RtlZeroMemory(Descriptor, sizeof(RECEIVE_DESCRIPTOR)); Descriptor->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart + (Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE); Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000; Descriptor->FLAGS |= RD_OWN;
Adapter->CurrentReceiveDescriptorIndex++; Adapter->CurrentReceiveDescriptorIndex %= Adapter->BufferCount;
Adapter->Statistics.RcvGoodFrames++; }
if (IndicatedData) NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle); } if(Data & CSR0_TINT) { PTRANSMIT_DESCRIPTOR Descriptor;
DPRINT("transmit interrupt\n");
while (Adapter->CurrentTransmitStartIndex != Adapter->CurrentTransmitEndIndex) { Descriptor = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitStartIndex;
DPRINT("buffer %d flags %x flags2 %x\n", Adapter->CurrentTransmitStartIndex, Descriptor->FLAGS, Descriptor->FLAGS2);
if (Descriptor->FLAGS & TD1_OWN) { DPRINT("non-TXed buffer\n"); 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) { DPRINT("major error: %x\n", Descriptor->FLAGS2); if (Descriptor->FLAGS2 & TD2_RTRY) Adapter->Statistics.XmtRetryErrors++; if (Descriptor->FLAGS2 & TD2_LCAR) Adapter->Statistics.XmtLossesOfCarrier++; if (Descriptor->FLAGS2 & TD2_LCOL) Adapter->Statistics.XmtLateCollisions++; if (Descriptor->FLAGS2 & TD2_EXDEF) Adapter->Statistics.XmtExcessiveDeferrals++; if (Descriptor->FLAGS2 & TD2_UFLO) Adapter->Statistics.XmtBufferUnderflows++; if (Descriptor->FLAGS2 & TD2_BUFF) Adapter->Statistics.XmtBufferErrors++; break; }
Adapter->CurrentTransmitStartIndex++; Adapter->CurrentTransmitStartIndex %= Adapter->BufferCount;
Adapter->Statistics.XmtGoodFrames++; } NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle); } if(Data & ~(CSR0_ERR | CSR0_IDON | CSR0_RINT | CSR0_TINT)) { DPRINT("UNHANDLED INTERRUPT CSR0 0x%x\n", Data); }
NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); }
/* re-enable interrupts */ NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);
NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR0 is now 0x%x\n", Data);
NdisDprReleaseSpinLock(&Adapter->Lock);}
static NDIS_STATUSMiQueryCard( IN PADAPTER Adapter)/* * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector * ARGUMENTS: * MiniportAdapterContext: context supplied to NdisMSetAttributes * RETURNS: * NDIS_STATUS_FAILURE on a general error * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter * NDIS_STATUS_SUCCESS on succes */{ ULONG buf32 = 0; UCHAR buf8 = 0; NDIS_STATUS Status;
/* Detect the card in the configured slot */ Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_PCIID, &buf32, 4); if(Status != 4) { Status = NDIS_STATUS_FAILURE; DPRINT1("NdisReadPciSlotInformation failed\n"); return Status; }
if(buf32 != PCI_ID) { Status = NDIS_STATUS_ADAPTER_NOT_FOUND; DPRINT1("card in slot isn't our: 0x%x\n", 0, buf32); return Status; }
/* set busmaster and io space enable bits */ buf32 = PCI_BMEN | PCI_IOEN; NdisWritePciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_COMMAND, &buf32, 4);
/* get IO base physical address */ buf32 = 0; Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_IOBAR, &buf32, 4); if(Status != 4) { Status = NDIS_STATUS_FAILURE; DPRINT1("NdisReadPciSlotInformation failed\n"); return Status; }
if(!buf32) { DPRINT1("No base i/o address set\n"); return NDIS_STATUS_FAILURE; }
buf32 &= ~1; /* even up address - comes out odd for some reason */
DPRINT("detected io address 0x%x\n", buf32); Adapter->IoBaseAddress = buf32;
/* get interrupt vector */ Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_ILR, &buf8, 1); if(Status != 1) { Status = NDIS_STATUS_FAILURE; DPRINT1("NdisReadPciSlotInformation failed\n"); return Status; }
DPRINT("interrupt: 0x%x\n", buf8); Adapter->InterruptVector = buf8;
return NDIS_STATUS_SUCCESS;}
static VOIDMiFreeSharedMemory( PADAPTER Adapter)/* * FUNCTION: Free all allocated shared memory * ARGUMENTS: * Adapter: pointer to the miniport's adapter struct */{ NDIS_PHYSICAL_ADDRESS PhysicalAddress;
if(Adapter->InitializationBlockVirt) { PhysicalAddress = Adapter->InitializationBlockPhys; NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, FALSE, Adapter->InitializationBlockVirt, PhysicalAddress); Adapter->InitializationBlockVirt = NULL; }
if(Adapter->TransmitDescriptorRingVirt) { PhysicalAddress = Adapter->TransmitDescriptorRingPhys; NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength, FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress); Adapter->TransmitDescriptorRingVirt = NULL; }
if(Adapter->ReceiveDescriptorRingVirt) { PhysicalAddress = Adapter->ReceiveDescriptorRingPhys; NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength, FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress); Adapter->ReceiveDescriptorRingVirt = NULL; }
if(Adapter->TransmitBufferPtrVirt) { PhysicalAddress = Adapter->TransmitBufferPtrPhys; NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, TRUE, Adapter->TransmitBufferPtrVirt, PhysicalAddress); Adapter->TransmitBufferPtrVirt = NULL; }
if(Adapter->ReceiveBufferPtrVirt) { PhysicalAddress = Adapter->ReceiveBufferPtrPhys; NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, TRUE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress); Adapter->ReceiveBufferPtrVirt = NULL; }}
static NDIS_STATUSMiAllocateSharedMemory( PADAPTER Adapter)/* * FUNCTION: Allocate all shared memory used by the miniport * ARGUMENTS: * Adapter: Pointer to the miniport's adapter object * RETURNS: * NDIS_STATUS_RESOURCES on insufficient memory * NDIS_STATUS_SUCCESS on success */{ PTRANSMIT_DESCRIPTOR TransmitDescriptor; PRECEIVE_DESCRIPTOR ReceiveDescriptor; NDIS_PHYSICAL_ADDRESS PhysicalAddress; ULONG i; ULONG BufferCount = NUMBER_OF_BUFFERS; ULONG LogBufferCount = LOG_NUMBER_OF_BUFFERS;
while (BufferCount != 0) { /* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */ Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK); NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress); if(!Adapter->InitializationBlockVirt) { /* Buffer backoff won't help us here */ DPRINT1("insufficient resources\n"); return NDIS_STATUS_RESOURCES; }
if (((ULONG_PTR)Adapter->InitializationBlockVirt & 0x00000003) != 0) { DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt); return NDIS_STATUS_RESOURCES; }
Adapter->InitializationBlockPhys = PhysicalAddress;
/* allocate the transport descriptor ring */ Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount; NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength, FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress); if (!Adapter->TransmitDescriptorRingVirt) { DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); BufferCount = BufferCount >> 1; LogBufferCount--; MiFreeSharedMemory(Adapter); continue; }
if (((ULONG_PTR)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0) { DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt); return NDIS_STATUS_RESOURCES; }
Adapter->TransmitDescriptorRingPhys = PhysicalAddress; RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount);
/* allocate the receive descriptor ring */ Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount; NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength, FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress); if (!Adapter->ReceiveDescriptorRingVirt) { DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); BufferCount = BufferCount >> 1; LogBufferCount--; MiFreeSharedMemory(Adapter); continue; }
if (((ULONG_PTR)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0) { DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt); return NDIS_STATUS_RESOURCES; }
Adapter->ReceiveDescriptorRingPhys = PhysicalAddress; RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount);
/* allocate transmit buffers */ Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount; NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress); if(!Adapter->TransmitBufferPtrVirt) { DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); BufferCount = BufferCount >> 1; LogBufferCount--; MiFreeSharedMemory(Adapter); continue; }
if(((ULONG_PTR)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0) { DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt); return NDIS_STATUS_RESOURCES; }
Adapter->TransmitBufferPtrPhys = PhysicalAddress; RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount);
/* allocate receive buffers */ Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount; NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress); if(!Adapter->ReceiveBufferPtrVirt) { DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1)); BufferCount = BufferCount >> 1; LogBufferCount--; MiFreeSharedMemory(Adapter); continue; }
if (((ULONG_PTR)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0) { DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt); return NDIS_STATUS_RESOURCES; }
Adapter->ReceiveBufferPtrPhys = PhysicalAddress; RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount);
break; }
if (!BufferCount) { DPRINT1("Failed to allocate adapter buffers\n"); return NDIS_STATUS_RESOURCES; }
Adapter->BufferCount = BufferCount; Adapter->LogBufferCount = LogBufferCount;
/* initialize tx descriptors */ TransmitDescriptor = Adapter->TransmitDescriptorRingVirt; for(i = 0; i < BufferCount; i++) { (TransmitDescriptor+i)->TBADR = Adapter->TransmitBufferPtrPhys.QuadPart + i * BUFFER_SIZE; (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ (TransmitDescriptor+i)->FLAGS = TD1_STP | TD1_ENP; }
DPRINT("transmit ring initialized\n");
/* initialize rx */ ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt; for(i = 0; i < BufferCount; i++) { (ReceiveDescriptor+i)->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart + i * BUFFER_SIZE; (ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */ (ReceiveDescriptor+i)->FLAGS = RD_OWN; }
DPRINT("receive ring initialized\n");
return NDIS_STATUS_SUCCESS;}
static VOIDMiPrepareInitializationBlock( PADAPTER Adapter)/* * FUNCTION: Initialize the initialization block * ARGUMENTS: * Adapter: pointer to the miniport's adapter object */{ ULONG i = 0;
RtlZeroMemory(Adapter->InitializationBlockVirt, sizeof(INITIALIZATION_BLOCK));
/* read burned-in address from card */ for(i = 0; i < 6; i++) NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i); DPRINT("MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n", Adapter->InitializationBlockVirt->PADR[0], Adapter->InitializationBlockVirt->PADR[1], Adapter->InitializationBlockVirt->PADR[2], Adapter->InitializationBlockVirt->PADR[3], Adapter->InitializationBlockVirt->PADR[4], Adapter->InitializationBlockVirt->PADR[5]);
/* set up receive ring */ DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys); Adapter->InitializationBlockVirt->RDRA = Adapter->ReceiveDescriptorRingPhys.QuadPart; Adapter->InitializationBlockVirt->RLEN = (Adapter->LogBufferCount << 4) & 0xf0;
/* set up transmit ring */ DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys); Adapter->InitializationBlockVirt->TDRA = Adapter->TransmitDescriptorRingPhys.QuadPart; Adapter->InitializationBlockVirt->TLEN = (Adapter->LogBufferCount << 4) & 0xf0;}
static BOOLEANNTAPIMiSyncStop( 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;}
static VOIDNTAPIMiniportHalt( IN NDIS_HANDLE MiniportAdapterContext)/* * FUNCTION: Stop the adapter and release any per-adapter resources * ARGUMENTS: * MiniportAdapterContext: context specified to NdisMSetAttributes * NOTES: * - Called by NDIS at PASSIVE_LEVEL */{ PADAPTER Adapter = (PADAPTER)MiniportAdapterContext; BOOLEAN TimerCancelled;
DPRINT("Called\n"); ASSERT(Adapter);
/* stop the media detection timer */ NdisMCancelTimer(&Adapter->MediaDetectionTimer, &TimerCancelled);
/* stop the chip */ NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStop, Adapter);
/* deregister the interrupt */ NdisMDeregisterInterrupt(&Adapter->InterruptObject);
/* deregister i/o port range */ NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
/* deregister the shutdown routine */ NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle);
/* free shared memory */ MiFreeSharedMemory(Adapter);
/* free map registers */ NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
/* free the lock */ NdisFreeSpinLock(&Adapter->Lock);
/* free the adapter */ NdisFreeMemory(Adapter, 0, 0);}
static BOOLEANNTAPIMiSyncMediaDetection( IN PVOID SynchronizeContext)/* * FUNCTION: Stop the adapter * ARGUMENTS: * SynchronizeContext: Adapter context */{ PADAPTER Adapter = (PADAPTER)SynchronizeContext; NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter); UINT MediaSpeed = MiGetMediaSpeed(Adapter); BOOLEAN FullDuplex = MiGetMediaDuplex(Adapter);
DPRINT("Called\n"); DPRINT("MediaState: %d\n", MediaState); if (MediaState != Adapter->MediaState || MediaSpeed != Adapter->MediaSpeed || FullDuplex != Adapter->FullDuplex) { Adapter->MediaState = MediaState; Adapter->MediaSpeed = MediaSpeed; Adapter->FullDuplex = FullDuplex; return TRUE; } return FALSE;}
static VOIDNTAPIMiniportMediaDetectionTimer( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3)/* * FUNCTION: Periodically query media state * ARGUMENTS: * FunctionContext: Adapter context * NOTES: * - Called by NDIS at DISPATCH_LEVEL */{ PADAPTER Adapter = (PADAPTER)FunctionContext;
ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
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); }}
static VOIDMiInitChip( PADAPTER Adapter)/* * FUNCTION: Initialize and start the PCNET chip * ARGUMENTS: * Adapter: pointer to the miniport's adapter struct * NOTES: * - should be coded to detect failure and return an error * - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that. */{ USHORT Data = 0;
DPRINT("Called\n");
/* * first reset the chip - 32-bit reset followed by 16-bit reset. if it's in 32-bit mode, it'll reset * twice. if it's in 16-bit mode, the first read will be nonsense and the second will be a reset. the * card is reset by reading from the reset register. on reset it's in 16-bit i/o mode. */ NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data); NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
/* stop the chip */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
/* pause for 1ms so the chip will have time to reset */ NdisStallExecution(1);
DPRINT("chip stopped\n");
/* set the software style to 2 (32 bits) */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
Data |= SW_STYLE_2;
NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
/* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS; NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
/* set up bcr18: burst read/write enable */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18); NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
Data |= BCR18_BREADE | BCR18_BWRITE ; NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
/* set up csr1 and csr2 with init block */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1); NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart & 0xffff)); NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2); NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart >> 16) & 0xffff);
DPRINT("programmed with init block\n");
/* Set mode to 0 */ Data = 0; NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15); NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
/* load init block and start the card */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
/* Allow LED programming */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR2); NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR2_LEDPE);
/* LED0 is configured for link status (on = up, off = down) */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4); NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE | BCR4_PSE);
/* LED1 is configured for link duplex (on = full, off = half) */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5); NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR5_FDLSE | BCR5_PSE);
/* LED2 is configured for link speed (on = 100M, off = 10M) */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6); NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR6_E100 | BCR6_PSE);
/* LED3 is configured for trasmit/receive activity */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR7); NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR7_XMTE | BCR7_RCVE | BCR7_PSE);
Adapter->MediaState = MiGetMediaState(Adapter); Adapter->FullDuplex = MiGetMediaDuplex(Adapter); Adapter->MediaSpeed = MiGetMediaSpeed(Adapter);
DPRINT("card started\n");
Adapter->Flags &= ~RESET_IN_PROGRESS;}
#if DBGstatic BOOLEANMiTestCard( PADAPTER Adapter)/* * FUNCTION: Test the NIC * ARGUMENTS: * Adapter: pointer to the miniport's adapter struct * RETURNS: * TRUE if the test succeeds * FALSE otherwise * NOTES: * - this is where to add diagnostics. This is called * at the very end of initialization. */{ int i = 0; UCHAR address[6]; USHORT Data = 0;
/* see if we can read/write now */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("Port 0x%x RAP 0x%x CSR0 0x%x RDP 0x%x, Interrupt status register is 0x%x\n", Adapter->PortOffset, RAP, CSR0, RDP, Data);
/* read the BIA */ for(i = 0; i < 6; i++) NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
DPRINT("burned-in address: %02x:%02x:%02x:%02x:%02x:%02x\n", address[0], address[1], address[2], address[3], address[4], address[5]); /* Read status flags from CSR0 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR0: 0x%x\n", Data);
/* Read status flags from CSR3 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR3: 0x%x\n", Data);
/* Read status flags from CSR4 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR4: 0x%x\n", Data);
/* Read status flags from CSR5 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR5: 0x%x\n", Data);
/* Read status flags from CSR6 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6); NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data); DPRINT("CSR6: 0x%x\n", Data);
/* Read status flags from BCR4 */ NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4); NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data); DPRINT("BCR4: 0x%x\n", Data);
return TRUE;}#endif
VOIDNTAPIMiniportShutdown( PVOID Context ){ PADAPTER Adapter = Context;
DPRINT("Stopping the chip\n");
NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0); NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);}
static NDIS_STATUSNTAPIMiniportInitialize( OUT PNDIS_STATUS OpenErrorStatus, OUT PUINT SelectedMediumIndex, IN PNDIS_MEDIUM MediumArray, IN UINT MediumArraySize, IN NDIS_HANDLE MiniportAdapterHandle, IN NDIS_HANDLE WrapperConfigurationContext)/* * FUNCTION: Initialize a new miniport * ARGUMENTS: * OpenErrorStatus: pointer to a var to return status info in * SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3) * MediumArray: array of media that we can pick from * MediumArraySize: size of MediumArray * MiniportAdapterHandle: NDIS-assigned handle for this miniport instance * WrapperConfigurationContext: temporary NDIS-assigned handle for passing * to configuration APIs * RETURNS: * NDIS_STATUS_SUCCESS on success * NDIS_STATUS_FAILURE on general failure * NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray * NDIS_STATUS_RESOURCES on insufficient system resources * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter * NOTES: * - Called by NDIS at PASSIVE_LEVEL, once per detected card * - Will int 3 on failure of MiTestCard if DBG=1 */{ UINT i = 0; PADAPTER Adapter = 0; NDIS_STATUS Status = NDIS_STATUS_FAILURE; BOOLEAN InterruptRegistered = FALSE, MapRegistersAllocated = FALSE; NDIS_HANDLE ConfigurationHandle; UINT *RegNetworkAddress = 0; UINT RegNetworkAddressLength = 0;
ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
/* Pick a medium */ for(i = 0; i < MediumArraySize; i++) if(MediumArray[i] == NdisMedium802_3) break;
if(i == MediumArraySize) { Status = NDIS_STATUS_UNSUPPORTED_MEDIA; DPRINT1("unsupported media\n"); *OpenErrorStatus = Status; return Status; }
*SelectedMediumIndex = i;
/* allocate our adapter struct */ Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG); if(Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_RESOURCES; DPRINT1("Insufficient resources\n"); *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; 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); 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); break; }
MapRegistersAllocated = TRUE;
/* set up the interrupt */ Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector, Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive); if(Status != NDIS_STATUS_SUCCESS) { DPRINT1("NdisMRegisterInterrupt failed: 0x%x\n", Status); break; }
InterruptRegistered = TRUE;
/* Allocate and initialize shared data structures */ Status = MiAllocateSharedMemory(Adapter); if(Status != NDIS_STATUS_SUCCESS) { Status = NDIS_STATUS_RESOURCES; DPRINT1("MiAllocateSharedMemory failed\n", Status); break; }
/* set up the initialization block */ MiPrepareInitializationBlock(Adapter);
/* see if someone set a network address manually */ NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext); if (Status == NDIS_STATUS_SUCCESS) { NdisReadNetworkAddress(&Status, (PVOID *)&RegNetworkAddress, &RegNetworkAddressLength, ConfigurationHandle); if(Status == NDIS_STATUS_SUCCESS && RegNetworkAddressLength == 6) { int i; DPRINT("NdisReadNetworkAddress returned successfully, address %x:%x:%x:%x:%x:%x\n", RegNetworkAddress[0], RegNetworkAddress[1], RegNetworkAddress[2], RegNetworkAddress[3], RegNetworkAddress[4], RegNetworkAddress[5]);
for(i = 0; i < 6; i++) Adapter->InitializationBlockVirt->PADR[i] = RegNetworkAddress[i]; }
NdisCloseConfiguration(ConfigurationHandle); }
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");
MiFreeSharedMemory(Adapter);
if(MapRegistersAllocated) NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
if(Adapter->PortOffset) NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
if(InterruptRegistered) NdisMDeregisterInterrupt(&Adapter->InterruptObject);
NdisFreeMemory(Adapter, 0, 0); }
if(Status == NDIS_STATUS_SUCCESS) { NdisMInitializeTimer(&Adapter->MediaDetectionTimer, Adapter->MiniportAdapterHandle, MiniportMediaDetectionTimer, Adapter); NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer, MEDIA_DETECTION_INTERVAL); NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle, Adapter, MiniportShutdown); }
#if DBG if(!MiTestCard(Adapter)) ASSERT(0);#endif
DPRINT("returning 0x%x\n", Status); *OpenErrorStatus = Status; return Status;}
static VOIDNTAPIMiniportISR( 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_STATUSNTAPIMiniportReset( 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 BOOLEANNTAPIMiSyncStartTransmit( 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_STATUSNTAPIMiniportSend( 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");
ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
NdisDprAcquireSpinLock(&Adapter->Lock);
/* Check if we have free entry in our circular buffer. */ if ((Adapter->CurrentTransmitEndIndex + 1 == Adapter->CurrentTransmitStartIndex) || (Adapter->CurrentTransmitEndIndex == Adapter->BufferCount - 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 %= Adapter->BufferCount;
Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP; Desc->BCNT = 0xf000 | -(INT)TotalPacketLength;
NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
NdisDprReleaseSpinLock(&Adapter->Lock);
return NDIS_STATUS_SUCCESS;}
static ULONGNTAPIMiEthernetCrc(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_STATUSNTAPIMiSetMulticast( 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;}
BOOLEANNTAPIMiGetMediaDuplex(PADAPTER Adapter){ ULONG Data;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5); NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
return (Data & BCR5_LEDOUT) != 0;}
UINTNTAPIMiGetMediaSpeed(PADAPTER Adapter){ ULONG Data;
NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6); NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
return Data & BCR6_LEDOUT ? 100 : 10;}
NDIS_MEDIA_STATENTAPIMiGetMediaState(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;}
NTSTATUSNTAPIDriverEntry( 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); if (!WrapperHandle) return NDIS_STATUS_FAILURE;
Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics)); if(Status != NDIS_STATUS_SUCCESS) { NdisTerminateWrapper(WrapperHandle, 0); return NDIS_STATUS_FAILURE; }
return NDIS_STATUS_SUCCESS;}