diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/ndis/elnk3 | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
-rw-r--r-- | private/ntos/ndis/elnk3/card.c | 1321 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/config.c | 514 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/debug.h | 133 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/elnk3.c | 174 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/elnk3.h | 424 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/elnk3.rc | 39 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/elnk3hrd.h | 549 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/elnk3sft.h | 361 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/init.c | 897 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/interrup.c | 418 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/keywords.h | 56 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/makefile | 6 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/receive.c | 1722 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/request.c | 839 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/send.c | 292 | ||||
-rw-r--r-- | private/ntos/ndis/elnk3/sources | 51 |
16 files changed, 7796 insertions, 0 deletions
diff --git a/private/ntos/ndis/elnk3/card.c b/private/ntos/ndis/elnk3/card.c new file mode 100644 index 000000000..ba8e26d9f --- /dev/null +++ b/private/ntos/ndis/elnk3/card.c @@ -0,0 +1,1321 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + card.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + +Author: + + Brian Lieuallen BrianLie 09/22/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + + + +--*/ + + + +#include <ndis.h> +#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + +#include "keywords.h" + + +#pragma NDIS_INIT_FUNCTION(Elnk3FindIsaBoards) +#pragma NDIS_INIT_FUNCTION(Elnk3ActivateIsaBoard) +#pragma NDIS_INIT_FUNCTION(ReadStationAddress) +#pragma NDIS_INIT_FUNCTION(ELNK3WriteIDSequence) +#pragma NDIS_INIT_FUNCTION(ELNK3ContentionTest) +#pragma NDIS_INIT_FUNCTION(Elnk3GetEisaResources) +#pragma NDIS_INIT_FUNCTION(CardEnable) +#pragma NDIS_INIT_FUNCTION(CardTest) +#pragma NDIS_INIT_FUNCTION(ELNK3ReadEEProm) +#pragma NDIS_INIT_FUNCTION(Elnk3ProgramEEProm) +#pragma NDIS_INIT_FUNCTION(Elnk3WriteEEProm) +#pragma NDIS_INIT_FUNCTION(Elnk3WaitEEPromNotBusy) + + +BOOLEAN +CardTest ( + OUT PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + + + Arguments: + + + Return Value: + + +--*/ +{ + + IF_INIT_LOUD (DbgPrint("Elnk3: CardTest(): Entered\n");) + + + if (!ReadStationAddress(pAdapter)) { + return FALSE; + } + + + if (!CardEnable(pAdapter)) { + return FALSE; + } + + + return TRUE; +} + + +BOOLEAN +CardEnable( + IN PELNK3_ADAPTER pAdapter + ) +/*++ + +Routine Description: + + This routine enables the card hardware and sets the dma channel and + interrupts number by writing to the Cards option register + +Arguments: + +Return Value: + +Note: + + This should not be called before the registry is read and the Dma + and interrupt info is in place. + +--*/ + +{ + + USHORT Temp; + UINT i; + ULONG Limit; + USHORT AddressConfig; + USHORT RevisionLevel; + + + IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable\n");) + + + CardReset(pAdapter); + + ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO); + + ELNK3ReadAdapterUshort(pAdapter,PORT_FREE_RX_BYTES,&pAdapter->RxFifoSize); + + + // + // Set the station address + + ELNK3_SELECT_WINDOW(pAdapter,WNO_STATIONADDRESS); + + for (i=0;i<3;i++) { + Temp=pAdapter->StationAddress[i*2] | (((USHORT)pAdapter->StationAddress[i*2+1])<<8); + ELNK3WriteAdapterUshort(pAdapter,(i*2),Temp); + } + + // + // Read address config register to find out transceiver type + // + ELNK3_SELECT_WINDOW(pAdapter,WNO_SETUP); + + ELNK3ReadAdapterUshort(pAdapter,PORT_CfgAddress,&AddressConfig); + + ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS); + + IF_INIT_LOUD(DbgPrint("ELNK3: Address config register is %04x\n",AddressConfig);) + + if ((AddressConfig >> 14) == 0) { + // + // Enable link beat on TP + // + if (pAdapter->EEpromSoftwareInfo & LINK_BEAT_DISABLED) { + + IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: NOT Enabling link beat on 10 Base-T\n");) + + ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE, MEDIA_JABBER); + + } else { + + IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Enabling link beat on 10 Base-T\n");) + + ELNK3WriteAdapterUshort(pAdapter,PORT_MEDIA_TYPE,MEDIA_LINK_BEAT | MEDIA_JABBER); + + } + + } + + ELNK3ReadAdapterUshort(pAdapter,PORT_NET_DIAG,&RevisionLevel); + + RevisionLevel= ((RevisionLevel & 0x1e) >> 1); + + pAdapter->RevisionLevel=(UCHAR)RevisionLevel; + + ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING); + + // + // Test to see if the interrupt works or not + // + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff); + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,EC_INT_INTERRUPT_REQUESTED); + ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff); + + pAdapter->InitInterrupt=FALSE; + + pAdapter->AdapterInitializing=TRUE; + + ELNK3_COMMAND(pAdapter,EC_REQUEST_INTERRUPT,0); + + Limit=2000; + + while ((--Limit>0) && (!pAdapter->InitInterrupt)) { + NdisStallExecution(10); + } + + pAdapter->AdapterInitializing=FALSE; + + // + // Did it time out or did we get an interrupt + // + if (Limit==0) { + IF_INIT_LOUD(DbgPrint("ELNK3: Did not receive interrupt\n");) + return FALSE; + } + + ELNK3_COMMAND(pAdapter,EC_RX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + + +// ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0); +// ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0); + + if ((AddressConfig >> 14) == 3) { + // + // turn on 10base2 converter + // + IF_INIT_LOUD(DbgPrint("ELNK3: CardEnable: Turning on 10base2 converter\n");) + + ELNK3_COMMAND(pAdapter,EC_START_COAX_XCVR,0); + + NdisStallExecution(800); + } + + + + pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY | + EC_INT_TX_COMPLETE | + EC_INT_RX_COMPLETE | + EC_INT_TX_AVAILABLE | + EC_INT_ADAPTER_FAILURE | + EC_INT_INTERRUPT_REQUESTED; + + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask); + ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,pAdapter->CurrentInterruptMask); + + + IF_INIT_LOUD(DbgPrint("ELNK3: Adapter initialized correctly\n");) + return TRUE; +} + + + +BOOLEAN +CardReInit( + IN PELNK3_ADAPTER pAdapter + ) + +{ + USHORT FifoStatus; + USHORT FreeFifoBytes; + + ELNK3_SELECT_WINDOW(pAdapter,WNO_DIAGNOSTICS); + + ELNK3ReadAdapterUshort(pAdapter,PORT_FIFO_DIAG,&FifoStatus); + + ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING); + + if (FifoStatus & RX_UNDERRUN) { + IF_LOUD(DbgPrint("ELNK3: Receive Underrun\n");) + + ELNK3_COMMAND(pAdapter,EC_RX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0); + + ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter); + } + + if (FifoStatus & TX_OVERRUN) { + + ELNK3ReadAdapterUshort(pAdapter,PORT_TxFree,&FreeFifoBytes); + + IF_LOUD(DbgPrint("ELNK3: Transmit Overrun - Bytesfree=%d\n",FreeFifoBytes);) + + + ELNK3_COMMAND(pAdapter,EC_TX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0); + } + + + return TRUE; + +} + + +VOID +CardReStart( + IN PELNK3_ADAPTER pAdapter + ) + +{ + + IF_LOUD(DbgPrint("ELNK3: CardRestart\n");) + + // + // put the filter back + // + ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, 0); + + + ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0x00); + + pAdapter->CurrentInterruptMask=EC_INT_RX_EARLY | + EC_INT_TX_COMPLETE | + EC_INT_RX_COMPLETE | + EC_INT_TX_AVAILABLE | + EC_INT_ADAPTER_FAILURE | + EC_INT_INTERRUPT_REQUESTED; + + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask); + + + + // + // Reset and re-enable the receiver + // + ELNK3_COMMAND(pAdapter,EC_RX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0); + + + // + // reset and restart the transmitter + // + ELNK3_COMMAND(pAdapter,EC_TX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0); + + ELNK3_COMMAND(pAdapter,EC_SET_TX_START,pAdapter->TxStartThreshold & 0x7ff); + + // + // clear all pending interrupts + // + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff); + + // + // reset the receive buffer info + // + pAdapter->CurrentPacket=0; + + pAdapter->TransContext[0].BytesAlreadyRead=0; + pAdapter->TransContext[0].PacketLength=0; + + pAdapter->TransContext[1].BytesAlreadyRead=0; + pAdapter->TransContext[1].PacketLength=0; +} + + +VOID +CardReStartDone( + IN PELNK3_ADAPTER pAdapter + ) + +{ + + IF_LOUD(DbgPrint("ELNK3: CardRestartDone\n");) + + ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0xff); + // + // put the filter back + // + ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter); + + return; +} + + +VOID +CardReset( + IN PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + + + Arguments: + + + Return Value: + + +--*/ +{ + + IF_INIT_LOUD(DbgPrint("ELNK3: Reset Card\n");) + + // + // Mask everything + // + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,0); + + // + // Clear all interrupt reasons + // + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,0xff); + + + ELNK3_COMMAND(pAdapter,EC_RX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_TX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); +} + + + + +BOOLEAN +ReadStationAddress( + OUT PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + Read the station address from the PROM + + Arguments: + + + Return Value: + + +--*/ + +{ + + UINT i,Sum; + USHORT Temp; + + Sum=0; + + IF_INIT_LOUD( DbgPrint("Elnk3: The Station address is ");) + + ELNK3_SELECT_WINDOW(pAdapter,0); + + + // + // Read the eeprom software info to see if we need + // to enable link beat of not + // + pAdapter->EEpromSoftwareInfo=ELNK3ReadEEProm( + pAdapter, + (UCHAR)EEPROM_SOFTWARE_INFO + ); + + + + for (i=0;i<3;i++) { + Temp=ELNK3ReadEEProm( + pAdapter, + (UCHAR)i + ); + + + pAdapter->PermanentAddress[i*2] = Temp>>8; + pAdapter->PermanentAddress[i*2+1] = Temp & 0x00ff; + IF_INIT_LOUD( DbgPrint(" %04X",Temp);) + } + + // + // Put the product id value back in the eeprom data register + // + ELNK3ReadEEProm( + pAdapter, + (UCHAR)EEPROM_PRODUCT_ID + ); + + + + + // + // Copy in permanent address if necessary + // + + if (!(pAdapter->StationAddress[0] | + pAdapter->StationAddress[1] | + pAdapter->StationAddress[2] | + pAdapter->StationAddress[3] | + pAdapter->StationAddress[4] | + pAdapter->StationAddress[5])) { + + ETH_COPY_NETWORK_ADDRESS(pAdapter->StationAddress, + pAdapter->PermanentAddress + ); + } + + + IF_INIT_LOUD( DbgPrint("\n");) + + + return TRUE; +} + + + + + +UINT +Elnk3FindIsaBoards( + IN PMAC_BLOCK pMacBlock + ) + +{ + + PVOID IdPort=pMacBlock->TranslatedIdPort; + UINT i; + USHORT ProductId; + + + if (pMacBlock->IsaAdaptersFound != 0) { + + IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called again\n");) + + return pMacBlock->IsaAdaptersFound; + } + + IF_INIT_LOUD(DbgPrint("Elnk3: FindIsaBorads: called, first time\n");) + + // + // Untag all adapters + // + + ELNK3WriteIDSequence( IdPort ); + + NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0); + + // + // We find all the ISA boards in the system and tag them + // We note each ones configured I/O base, so that + // we can reset all of the ones not configured as EISA + // + + for (i=0; i<7 ; i++) { + + // + // Get the cards' attention + // + ELNK3WriteIDSequence( IdPort ); + + // + // See if there any cards out there + // + if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) { + // + // we found at least one + // + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 ); + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 ); + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 ); + + // + // This one won the contention battle + // Get it's i/o base and irq from the eeprom + // + + ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID ); + + ProductId&=0xf0ff; + + if (ProductId == 0x9050) { + // + // This one is a elnk3 adapter + // + pMacBlock->IsaCards[i].AddressConfigRegister= + ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION ); + + pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4); + + } else { + // + // We found a 3Com card that is not an elnk3. + // We will set the base address, to make it look like an EISA + // one so that code below will leave it alone + // + IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);) + + pMacBlock->IsaCards[i].IOPort=0x3f0; + } + + pMacBlock->IsaCards[i].Tagged=TRUE; + // + // Tag it so it don't bother us again + // + NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1)); + + + IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x\n", + i, + pMacBlock->IsaCards[i].IOPort + );) + + + } else { + // + // No more elnk3 cards + // + break; + } + } + + + // + // Now all of the ISA adapters have been found and tagged + // We now go through and reset all of the ones that are + // not configured as EISA. + // + + for (i=0; i<7 ; i++) { + + // + // Get the cards' attention + // + ELNK3WriteIDSequence( IdPort ); + + // + // If it is not configured as eisa reset it + // + if ((pMacBlock->IsaCards[i].IOPort != 0x03f0) && pMacBlock->IsaCards[i].Tagged) { + + IF_INIT_LOUD(DbgPrint("ELNK3: Reseting Elnk3 card #%d\n",i);) + + // + // Put the others back to sleep + // + NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1)); + + // + // Reset this one + // + NdisRawWritePortUchar(IdPort, IDCMD_RESET); + + NdisStallExecution(500); + + } else { +#if DBG + if (pMacBlock->IsaCards[i].Tagged) { + + IF_INIT_LOUD(DbgPrint("ELNK3: NOT Reseting EISA configured Elnk3 card #%d\n",i);) + } +#endif + } + + } + + // + // Now we go and find the adapters for real. + // + + // + // Untag all adapters + // + + ELNK3WriteIDSequence( IdPort ); + + NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+0); + + + for (i=0; i<7 ; i++) { + + // + // Get the cards' attention + // + ELNK3WriteIDSequence( IdPort ); + + // + // See if there any cards out there + // + if ( ELNK3ContentionTest( IdPort, EE_MANUFACTURER_CODE ) == EISA_MANUFACTURER_ID ) { + + // + // we found at least one + // + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD0 ); + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD1 ); + ELNK3ContentionTest( IdPort, EE_TCOM_NODE_ADDR_WORD2 ); + + // + // This one won the contention battle + // Get it's i/o base and irq from the eeprom + // + + ProductId=ELNK3ContentionTest( IdPort, EE_VULCAN_PROD_ID ); + + ProductId&=0xf0ff; + + if (ProductId == 0x9050) { + // + // This one is a elnk3 adapter + // + + pMacBlock->IsaCards[i].AddressConfigRegister= + ELNK3ContentionTest( IdPort, EE_ADDR_CONFIGURATION ); + + pMacBlock->IsaCards[i].ResourceConfigRegister= + ELNK3ContentionTest( IdPort, EE_RESOURCE_CONFIGURATION ); + + + pMacBlock->IsaCards[i].IOPort= 0x200 + ((pMacBlock->IsaCards[i].AddressConfigRegister & 0x1f)<<4); + pMacBlock->IsaCards[i].Irq=pMacBlock->IsaCards[i].ResourceConfigRegister >> 12; + + if (pMacBlock->IsaCards[i].IOPort == 0x03f0) { + // + // This one is configured as EISA. Mark it as active + // so it will be ignored + // + IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 ISA configed as EISA\n");) + + pMacBlock->IsaCards[i].Active=TRUE; + } + + } else { + // + // We found a 3Com card that is not an elnk3. + // We will set the base address, to make it look like an EISA + // one so that code below will leave it alone + // + IF_INIT_LOUD(DbgPrint("Elnk3: Found non-elnk3 during contention ProductId=%04x\n",ProductId);) + + pMacBlock->IsaCards[i].IOPort=0x3f0; + + pMacBlock->IsaCards[i].Active=TRUE; + } + + + // + // Tag it so it don't bother us again + // + NdisRawWritePortUchar(IdPort, IDCMD_SET_TAG+(i+1)); + + + IF_INIT_LOUD(DbgPrint("ELNK3: Found Elnk3 card #%d, io=%04x, irq=%d\n", + i, + pMacBlock->IsaCards[i].IOPort, + pMacBlock->IsaCards[i].Irq + );) + + // + // One more found + // + pMacBlock->IsaAdaptersFound++; + + } else { + // + // No more elnk3 cards + // + break; + } + } + + return pMacBlock->IsaAdaptersFound; + +} + + +BOOLEAN +Elnk3ActivateIsaBoard( + IN PMAC_BLOCK pMacBlock, + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE AdapterHandle, + IN PUCHAR TranslatedIoBase, + IN ULONG ConfigIoBase, + IN OUT PULONG Irq, + IN ULONG Transceiver, + IN NDIS_HANDLE ConfigurationHandle + ) + +{ + + PVOID IdPort=pMacBlock->TranslatedIdPort; + UINT i; + USHORT AddressConfig; + USHORT ResourceConfig; + + for (i=0; i<pMacBlock->IsaAdaptersFound; i++) { + // + // Search our table for a card that matches the I/O base passed + // in from the registry + // + + if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase) + && + (pMacBlock->IsaCards[i].Irq==*Irq) + && + ((pMacBlock->IsaCards[i].AddressConfigRegister>>14) == (USHORT)Transceiver) + && + (!pMacBlock->IsaCards[i].Active)) { + // + // Everything matched and it is not currently active + // + + IF_LOUD(DbgPrint("ELNK3: Found Match-Activating ISA card # %d at %04x\n",i,ConfigIoBase);) + // + // Found one, Now get the cards' attention + // + + ELNK3WriteIDSequence( IdPort ); + + // + // Put the others back to sleep + // + NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1)); + + // + // Activate it at the its configured base. + // + NdisRawWritePortUchar(IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4)); + + // + // this one is in use now + // + pMacBlock->IsaCards[i].Active=TRUE; + + // + // enable the IRQ drivers + // + NdisRawWritePortUchar( + TranslatedIoBase+PORT_CfgControl, + CCR_ENABLE + ); + + return TRUE; + } + } + + IF_LOUD(DbgPrint("ELNK3: Did not find an adapter that matched i/O base %04x\n",ConfigIoBase);) + + // + // Did not find a match, So now we activate the first unused + // card at the address supplied in the registry. + // + if ((*Irq != 0) && (Transceiver != 2)) { + // + // The irq and transceiver parameters are present, + // so we will reprogram the card to make them match + // + + for (i=0; i<pMacBlock->IsaAdaptersFound; i++) { + // + // Search our table for a card that has not been activated + // + + if ((!pMacBlock->IsaCards[i].Active)) { + + IF_LOUD(DbgPrint("ELNK3: Reconfiguring ISA card # %d to %04x, %d, %d\n",i,ConfigIoBase,*Irq,Transceiver);) + + // + // Found one, Now get the cards' attention + // + + ELNK3WriteIDSequence( IdPort ); + + // + // Put the others back to sleep + // + NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1)); + + // + // Activate where we want it + // + NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4)); + + // + // in use now + // + pMacBlock->IsaCards[i].Active=TRUE; + + // + // set the transceiver bits in the address config register + // + NdisRawReadPortUshort( + TranslatedIoBase+PORT_CfgAddress, + &AddressConfig + ); + + // + // only want the change the transceiver bits and io base + // + AddressConfig &= 0x3fc0; + + AddressConfig |= (Transceiver << 14) | ((ConfigIoBase - 0x200) >> 4); + + NdisRawWritePortUshort( + TranslatedIoBase+PORT_CfgAddress, + AddressConfig + ); + + // + // set the irq number in resources config register + // + ResourceConfig=((USHORT)*Irq << 12) | 0x0f00; + + + NdisRawWritePortUshort( + TranslatedIoBase+PORT_CfgResource, + ResourceConfig + ); + + // + // enable the IRQ drivers + // + NdisRawWritePortUchar( + TranslatedIoBase+PORT_CfgControl, + CCR_ENABLE + ); + + + // + // Program the eeprom to match the registry + // + Elnk3ProgramEEProm( + pAdapter, + AddressConfig, + ResourceConfig + ); + + return TRUE; + } + } + + // + // Did not find any un activated cards + // + IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");) + + return FALSE; + + } else { + // + // the irq and/or transceiver values were missing from the registry. + // Activate the card where the eeprom says it should be. + // + IF_LOUD(DbgPrint("Elnk3: irq and transceiver values missing\n");) + + for (i=0; i<pMacBlock->IsaAdaptersFound; i++) { + // + // Search our table for a card that has not been activated + // + if ((pMacBlock->IsaCards[i].IOPort == ConfigIoBase) + && + (!pMacBlock->IsaCards[i].Active)) { + + IF_LOUD(DbgPrint("ELNK3: Activating ISA card # %d at %04x\n",i,ConfigIoBase);) + + // + // Found one, Now get the cards' attention + // + + ELNK3WriteIDSequence( IdPort ); + + // + // Put the others back to sleep + // + NdisRawWritePortUchar(IdPort, IDCMD_TEST_TAG+(i+1)); + + // + // Activate where we want it + // + NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_ACTIVATE + ((ConfigIoBase-0x200) >> 4)); + + // + // enable the IRQ drivers + // + NdisRawWritePortUchar( + TranslatedIoBase+PORT_CfgControl, + CCR_ENABLE + ); + + // + // in use now + // + pMacBlock->IsaCards[i].Active=TRUE; + + *Irq=pMacBlock->IsaCards[i].Irq; + + IF_INIT_LOUD(DbgPrint("Elnk3: Missing IRQ is now %d\n",*Irq);) + + { + NDIS_CONFIGURATION_PARAMETER Value; + NDIS_STATUS Status; + NDIS_STRING IrqKeyword = INTERRUPT; + NDIS_STRING TransceiverKeyword = TRANSCEIVER; + NDIS_HANDLE ConfigHandle = NULL; + + // + // Open the configuration database. + // + NdisOpenConfiguration( + &Status, + &ConfigHandle, + ConfigurationHandle); + if (Status != NDIS_STATUS_SUCCESS) + { + return(FALSE); + } + + Value.ParameterType = NdisParameterInteger; + Value.ParameterData.IntegerData = *Irq; + NdisWriteConfiguration( + &Status, + ConfigHandle, + &IrqKeyword, + &Value); + + Value.ParameterType = NdisParameterInteger; + Value.ParameterData.IntegerData = + pMacBlock->IsaCards[i].AddressConfigRegister>>14; + NdisWriteConfiguration( + &Status, + ConfigHandle, + &TransceiverKeyword, + &Value); + + NdisCloseConfiguration(ConfigHandle); + } + + return TRUE; + } + } + + // + // Did not find any un activated cards + // + IF_LOUD(DbgPrint("ELNK3: Did not find an un activated adapter\n");) + + return FALSE; + } +} + + +VOID +Elnk3ProgramEEProm( + PELNK3_ADAPTER pAdapter, + USHORT AddressConfig, + USHORT ResourceConfig + ) + +{ + USHORT Temp; + USHORT CheckSum; + + Elnk3WriteEEProm( + pAdapter, + EE_ADDR_CONFIGURATION, + AddressConfig + ); + + Elnk3WriteEEProm( + pAdapter, + EE_RESOURCE_CONFIGURATION, + ResourceConfig + ); + + Temp=ELNK3ReadEEProm( + pAdapter, + EE_SOFTWARE_CONFIG_INFO + ); + + CheckSum=((AddressConfig>>8) ^ (AddressConfig & 0x00ff)); + + CheckSum= CheckSum ^ (ResourceConfig >> 8); + CheckSum= CheckSum ^ (ResourceConfig & 0x00ff); + + CheckSum= CheckSum ^ (Temp >> 8); + CheckSum= CheckSum ^ (Temp & 0x00ff); + + Temp=ELNK3ReadEEProm( + pAdapter, + EE_CHECK_SUM + ); + + Elnk3WriteEEProm( + pAdapter, + EE_CHECK_SUM, + (USHORT)((Temp & 0xff00) | (CheckSum & 0x00ff)) + ); + +} + + + + +VOID +ELNK3WriteIDSequence( + IN PVOID IdPort + ) +/*++ + +Routine Description: + + Writes the magic EtherLink III wake up sequence to a port. + + This puts all uninitialized EtherLink III cards on the bus in the ID_CMD + state. + + Must be called with exclusive access to all 1x0h ports, where x is any + hex digit. + + +Arguments: + + +Return Value: + + + +--*/ + + +{ + USHORT outval; + UINT i; + + NdisRawWritePortUchar(IdPort,0); + NdisRawWritePortUchar(IdPort,0); + + + for ( outval = 0xff, i = 255 ; i-- ; ) { + NdisRawWritePortUchar(IdPort,outval); + outval <<= 1; + if ( ( outval & 0x0100 ) != 0 ){ + outval ^= 0xCF; + } + } +} + + + + +USHORT +ELNK3ContentionTest( + IN PVOID IdPort, + IN UCHAR EEPromWord + ) +{ + + UCHAR data; + USHORT result; + UINT i; + + NdisRawWritePortUchar((PUCHAR)IdPort,IDCMD_READ_PROM + EEPromWord); + + + /* + 3COM's detection code has a 400 microsecond delay here. + */ + NdisStallExecution(400); + + for ( i = 16, result = 0 ; i-- ; ) { + result <<= 1; + NdisRawReadPortUchar(IdPort,&data); + result += (data & 1); + } + return (result); +} + + + + + + + + + + + +USHORT +ELNK3ReadEEProm( + IN PELNK3_ADAPTER Adapter, + IN UCHAR EEPromWord +) +{ + USHORT result; + ULONG Limit=10; + + // Issue an EEPROM read command. + + NdisRawWritePortUchar(Adapter->PortOffsets[PORT_EECmd],(UCHAR)(IDCMD_READ_PROM+EEPromWord)); + + // + // Spin until the EEPROM busy bit goes off. + // + Elnk3WaitEEPromNotBusy(Adapter); + + // + // Fetch the data from the EEPROM data register. + // + ELNK3ReadAdapterUshort(Adapter,PORT_EEData,&result); + + return ( result ); +} + +VOID +Elnk3WriteEEProm( + IN PELNK3_ADAPTER pAdapter, + IN UCHAR EEPromWord, + IN USHORT Value + ) + +{ + Elnk3WaitEEPromNotBusy(pAdapter); + + // + // put the data in the data register + // + ELNK3WriteAdapterUshort(pAdapter,PORT_EEData,Value); + + // + // enable erase and write + // + ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE); + + Elnk3WaitEEPromNotBusy(pAdapter); + + // + // erase the register + // + ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_ERASE+EEPromWord); + + Elnk3WaitEEPromNotBusy(pAdapter); + + // + // enable erase and write again + // + ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_EW_ENABLE); + + Elnk3WaitEEPromNotBusy(pAdapter); + + // + // Now write the data + // + ELNK3WriteAdapterUchar(pAdapter,PORT_EECmd,(UCHAR)EE_COMMAND_WRITE+EEPromWord); + + Elnk3WaitEEPromNotBusy(pAdapter); + +} + +VOID +Elnk3WaitEEPromNotBusy( + PELNK3_ADAPTER Adapter + ) + +{ + + USHORT result; + ULONG Limit; + // + // Spin until the EEPROM busy bit goes off. + // + Limit=100; + + ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result); + + while ((--Limit>0) && ( (result & EE_BUSY) != 0)) { + + NdisStallExecution(1000); + ELNK3ReadAdapterUshort(Adapter,PORT_EECmd,&result); + + } + +#if DBG + if (Limit == 0) { + + IF_LOUD(DbgPrint("Elnk3: time out waiting for eeprom to not be busy\n");) + + } +#endif + +} + + +VOID +Elnk3GetEisaResources( + IN PELNK3_ADAPTER pAdapter, + IN OUT PULONG Irq + ) + +{ + USHORT Config; + + ELNK3_SELECT_WINDOW(pAdapter, WNO_SETUP); + + ELNK3ReadAdapterUshort(pAdapter,PORT_CfgResource,&Config); + + IF_LOUD(DbgPrint("Elnk3: Eisa Irq is %d\n",Config>>12);) + + *Irq=Config>>12; + +} + + +#ifdef IO_DBG +USHORT ELNK3_READ_PORT_USHORT( PVOID Adapter, ULONG Offset ) +{ + USHORT data; + data = READ_PORT_USHORT((PUSHORT)((PELNK3_ADAPTER)Adapter)->PortOffsets[Offset]); + IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );) + return data; +} +USHORT ELNK3_READ_PORT_USHORT_DIRECT( PVOID Offset ) +{ + USHORT data; + data = READ_PORT_USHORT((PUSHORT)Offset); + IF_IO_LOUD(DbgPrint("read ushort %x from port %x\n", data, Offset );) + return data; +} +#endif + diff --git a/private/ntos/ndis/elnk3/config.c b/private/ntos/ndis/elnk3/config.c new file mode 100644 index 000000000..3b8744842 --- /dev/null +++ b/private/ntos/ndis/elnk3/config.c @@ -0,0 +1,514 @@ + /*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + config.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + +Author: + Brian Lieuallen (BrianLie) 07/02/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + + +--*/ + + + +#include <ndis.h> +//#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + +#include "keywords.h" + + +#pragma NDIS_INIT_FUNCTION(Elnk3ReadRegistry) + + + +NDIS_STATUS +Elnk3ReadRegistry( + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE ConfigurationHandle + ) + +{ + NDIS_HANDLE ConfigHandle = NULL; + PNDIS_CONFIGURATION_PARAMETER ReturnedValue; + NDIS_STRING MaxMulticastListStr = MAX_MULTICAST_LIST; + NDIS_STRING IOAddressStr = IOADDRESS; + NDIS_STRING BusTypeStr = BUS_TYPE; + NDIS_STRING InterruptStr = INTERRUPT; + NDIS_STRING TransceiverStr = TRANSCEIVER; + NDIS_STRING ReceiveMethodStr = NDIS_STRING_CONST("ReceiveMethod"); + NDIS_STRING ThresholdStr = NDIS_STRING_CONST("ThresholdTarget"); + NDIS_STRING IdPortAddressStr = NDIS_STRING_CONST("IdPortBaseAddress"); + NDIS_STRING TxThresholdStr = NDIS_STRING_CONST("EarlyTransmitThreshold"); + NDIS_STRING TxThresholdIncStr = NDIS_STRING_CONST("EarlyTransmitThresholdIncrement"); + NDIS_STRING CardTypeStr = NDIS_STRING_CONST("CardType"); + + BOOLEAN ConfigError = FALSE; + ULONG ConfigErrorValue = 0; + + NDIS_MCA_POS_DATA McaData; + + NDIS_STATUS Status; + + UINT i; + // + // These are used when calling Elnk3RegisterAdapter. + // + + ULONG TxThreshold = 384; + ULONG TxThresholdInc = 256; + + ULONG ThresholdTarget = 400; + ELNK3_ADAPTER_TYPE AdapterType = 0; + UINT IoBaseAddr = 0x300; + UINT BusNumber = 0; + NDIS_INTERFACE_TYPE BusType = Eisa; + UINT ChannelNumber = 0; + ULONG InterruptNumber = 0; + PUCHAR NetworkAddress; + UINT Length; + UINT IdPortBaseAddr = 0x110; + + NDIS_EISA_FUNCTION_INFORMATION EisaData; + + NDIS_INTERRUPT_MODE InterruptMode=NdisInterruptLatched; + + ULONG Transceiver = 2; + + TxThreshold = 128; + TxThresholdInc = 64; + + pAdapter->ReceiveMethod=0; + + pAdapter->EarlyReceiveHandler=Elnk3IndicatePackets2; + pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets2; + + NdisOpenConfiguration( + &Status, + &ConfigHandle, + ConfigurationHandle); + if (Status != NDIS_STATUS_SUCCESS) + { + return(Status); + } + + // + // Read Adapter Type (determine if this is a 3c589 PCMCIA card) + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &CardTypeStr, + NdisParameterInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + AdapterType = (UINT)(ReturnedValue->ParameterData.IntegerData); + pAdapter->CardType = AdapterType; + } + + // + // Read network address + // + NdisReadNetworkAddress( + &Status, + &NetworkAddress, + &Length, + ConfigHandle); + if (Status==NDIS_STATUS_SUCCESS) + { + for (i = 0; i < 6; i++) + { + pAdapter->StationAddress[i]=NetworkAddress[i]; + } + } + + // + // Read receive method + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &ReceiveMethodStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + pAdapter->ReceiveMethod=ReturnedValue->ParameterData.IntegerData; + + if ((ReturnedValue->ParameterData.IntegerData) == 1) + { + // + // Change to alternate + // + IF_LOUD(DbgPrint("ELNK3: Using alternate receive method\n");) + + pAdapter->EarlyReceiveHandler=Elnk3EarlyReceive; + pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets; + } + else + { + pAdapter->ReceiveMethod=0; + + pAdapter->EarlyReceiveHandler=Elnk3IndicatePackets2; + pAdapter->ReceiveCompleteHandler=Elnk3IndicatePackets2; + } + } + + // + // Read Threshold point + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &ThresholdStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + ThresholdTarget=ReturnedValue->ParameterData.IntegerData; + } + + + // + // Read TX Threshold start point + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &TxThresholdStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + TxThreshold=ReturnedValue->ParameterData.IntegerData; + } + + // + // Read TX Threshold start point increment + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &TxThresholdIncStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + TxThresholdInc=ReturnedValue->ParameterData.IntegerData; + } + + // + // Read Id port Address + // + if (AdapterType != ELNK3_3C589) + { + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &IdPortAddressStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + IdPortBaseAddr = (ReturnedValue->ParameterData.IntegerData); + + // + // Confirm value + // + if (IdPortBaseAddr < 0x100 || + IdPortBaseAddr > 0x1f0 || + ((IdPortBaseAddr & 0x0f) != 0)) + { + // + // Error + // + goto Fail00; + } + } + } + + // + // Read interrupt number + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &InterruptStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + InterruptNumber = (CCHAR)(ReturnedValue->ParameterData.IntegerData); + } + + // + // Read tranceiver type + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &TransceiverStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + Transceiver = (ReturnedValue->ParameterData.IntegerData); + } + + // + // Read BusType type + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &BusTypeStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + BusType = (ReturnedValue->ParameterData.IntegerData); + } + + if (BusType == Isa) + { + // + // Bus type ISA must be a 3c509. + // + if (AdapterType != ELNK3_3C589) + AdapterType=ELNK3_3C509; + + // + // Read I/O Address + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &IOAddressStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + IoBaseAddr = (ReturnedValue->ParameterData.IntegerData); + + // + // Confirm value + // + if (IoBaseAddr < 0x200 || + IoBaseAddr > 0x3e0 || + ((IoBaseAddr & 0x0f) != 0)) + { + // + // If the user is going to bother to give us a base address it + // had better be valid + // + goto Fail00; + } + } + else if (pAdapter->CardType == ELNK3_3C589) + { + // PCMCIA Adapter MUST get something for IRQ keyword + // otherwise there is I/O allocated to this adapter + // + goto Fail00; + } + } + else + { + if (BusType == MicroChannel) + { + // + // Bus type MCA must be a 3c529 + // + AdapterType=ELNK3_3C529; + + NdisReadMcaPosInformation( + &Status, + ConfigurationHandle, + &ChannelNumber, + &McaData); + if (Status != NDIS_STATUS_SUCCESS) + { + // + // Info read failed + // + IF_LOUD(DbgPrint("Elnk3: Failed to read POS information for card, slot# %d\n",ChannelNumber);) + goto Fail00; + } + + if ((McaData.AdapterId != ELNK3_3C529_TP_MCA_ID) && + (McaData.AdapterId != ELNK3_3C529_COMBO_MCA_ID) && + (McaData.AdapterId != ELNK3_3C529_BNC_MCA_ID) && + (McaData.AdapterId != ELNK3_3C529_TPCOAX_MCA_ID) && + (McaData.AdapterId != ELNK3_3C529_TPONLY_MCA_ID)) + { + // + // Not an Elnk3 adapter in this position + // + IF_LOUD(DbgPrint("Elnk3: The card found is not an ELNK3\n");) + goto Fail00; + } + + if (!(McaData.PosData1 & 0x01)) + { + // + // Bit 0 is set if the adapter is enabled + // + IF_LOUD(DbgPrint("Elnk3: The elnk3 is not enabled\n");) + goto Fail00; + } + + // + // We have found an 3c529 in the specified slot + // + InterruptNumber=McaData.PosData4 & 0x0f; + IoBaseAddr=((McaData.PosData3 & 0xfc) << 8) + 0x200; + + // + // The NIUps has a level triggered interrupt, as compared to + // the other two which do not + // + InterruptMode=NdisInterruptLevelSensitive; + } + else + { + if (BusType == Eisa) + { + // + // It's an eisa bus, Two possiblities, 3c579 or 3c509. + // + // Initialize the EisaData with garbage, in case the EISA + // config doesn't return any function information. + // + EisaData.CompressedId = 0xf00df00d; + EisaData.MinorRevision = 0xca; + EisaData.MajorRevision = 0xfe; + + NdisReadEisaSlotInformation( + &Status, + ConfigurationHandle, + &ChannelNumber, + &EisaData); + if (Status == NDIS_STATUS_SUCCESS) + { + // + // If the call worked, but the EisaData didn't change, + // we'll just assume that the card is a 3c579. If the + // EisaData did change, then we check to make sure it's + // an Elnk3. + // + if (((EisaData.CompressedId == 0xf00df00d) && + (EisaData.MinorRevision = 0xca) && + (EisaData.MajorRevision = 0xfe)) || + ((EisaData.CompressedId & 0xf0ffffff) == ELNK3_EISA_ID)) + { + AdapterType=ELNK3_3C579; + + IoBaseAddr=(ChannelNumber<<12); + + goto CloseConfig; + } + else + { + IF_LOUD(DbgPrint("ELNK3: The card found is not an ELNK3 id=%0lx\n",EisaData.CompressedId);) + } + } + else + { + // + // Info read failed + // + IF_LOUD(DbgPrint("ELNK3: Failed to get Eisa config information for card, bus# %d slot# %d\n",BusNumber,ChannelNumber);) + } + + // + // Does not seem to be an EISA card, try for an ISA + // + AdapterType=ELNK3_3C509; + + // + // Read I/O Address + // + NdisReadConfiguration( + &Status, + &ReturnedValue, + ConfigHandle, + &IOAddressStr, + NdisParameterHexInteger); + if (Status == NDIS_STATUS_SUCCESS) + { + IoBaseAddr = (ReturnedValue->ParameterData.IntegerData); + + // + // Confirm value + // + if (IoBaseAddr < 0x200 || + IoBaseAddr > 0x3e0 || + ((IoBaseAddr & 0x0f) != 0)) + { + // + // Error + // + goto Fail00; + } + } + } + } + } + +CloseConfig: + + + NdisCloseConfiguration(ConfigHandle); + + pAdapter->TxStartThreshold = (USHORT)TxThreshold; + pAdapter->TxStartThresholdInc = (USHORT)TxThresholdInc; + + pAdapter->IdPortBaseAddr = IdPortBaseAddr; + pAdapter->IoPortBaseAddr = IoBaseAddr; + + pAdapter->ThresholdTarget = ThresholdTarget; + pAdapter->IrqLevel = InterruptNumber; + pAdapter->InterruptMode = InterruptMode; + pAdapter->CardType = AdapterType; + + pAdapter->Transceiver = Transceiver; + + IF_LOUD( DbgPrint( "\n\nElnk3: Registering adapter \n" + "Elnk3: I/O base addr 0x%lx\n" + "Elnk3: Interrupt number %d\n\n", + IoBaseAddr, + InterruptNumber);) + + + return(NDIS_STATUS_SUCCESS); + +Fail00: + + NdisCloseConfiguration(ConfigHandle); + return(NDIS_STATUS_FAILURE); +} diff --git a/private/ntos/ndis/elnk3/debug.h b/private/ntos/ndis/elnk3/debug.h new file mode 100644 index 000000000..da849a12c --- /dev/null +++ b/private/ntos/ndis/elnk3/debug.h @@ -0,0 +1,133 @@ + +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + debug.h + +Abstract: + + It contains the various debug definitions and macros used in displaying + debugging information on the kernel debugger. + +Author: + + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + +--*/ + + +#if DBG + +typedef struct _DEBUG_STATS { + + ULONG TotalInterrupts; + ULONG TxCompIntCount; + ULONG TxAvailIntCount; + ULONG TxCompleted; + + ULONG RxCompIntCount; + ULONG RxEarlyIntCount; + ULONG PacketIndicated; + ULONG IndicationCompleted; + ULONG TransferDataCount; + ULONG IndicateWithDataReady; + ULONG BadReceives; + ULONG SecondEarlyReceive; + ULONG BroadcastsRejected; + + } DEBUG_STATS, *PDEBUG_STATUS; + +typedef struct _LOG_ENTRY { + UCHAR Letter1; + UCHAR Letter2; + USHORT Data; + } LOG_ENTRY, *PLOG_ENTRY; + + +#define ELNK3_MAX_LOG_SIZE 128 + +extern ULONG Elnk3LogArray[]; +extern ULONG ElnkLogPointer; + + +#define IF_ELNK3DEBUG(f) if (Elnk3DebugFlag & (f)) +extern ULONG Elnk3DebugFlag; + +#define ELNK3_DEBUG_LOUD 0x00000001 // debugging info +#define ELNK3_DEBUG_VERY_LOUD 0x00000002 // excessive debugging info +#define ELNK3_DEBUG_IO 0x00000004 // debug I/O port access + +#define ELNK3_DEBUG_INIT 0x00000100 // init debugging info +#define ELNK3_DEBUG_SEND 0x00000200 // init debugging info +#define ELNK3_DEBUG_RCV 0x00000400 +#define ELNK3_DEBUG_REQ 0x00000800 + +#define ELNK3_DEBUG_LOG 0x00001000 + +#define ELNK3_DEBUG_INIT_BREAK 0x80000000 // break at DriverEntry +#define ELNK3_DEBUG_INIT_FAIL 0x40000000 // fail driver load + +// +// Macro for deciding whether to dump lots of debugging information. +// + +#define IF_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_LOUD ) { A } +#define IF_VERY_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_VERY_LOUD ) { A } +#define IF_IO_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_IO ) { A } +#define IF_INIT_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_INIT ) { A } +#define IF_SEND_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_SEND ) { A } +#define IF_RCV_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_RCV ) { A } +#define IF_REQ_LOUD(A) IF_ELNK3DEBUG( ELNK3_DEBUG_REQ ) { A } + + +#define IF_LOG(c1,c2,data) { \ + if (Elnk3DebugFlag & ELNK3_DEBUG_LOG) { \ + Elnk3LogArray[ElnkLogPointer]=((ULONG)(data)<<16) | ((c1)<<8) | (c2); \ + ElnkLogPointer=(ElnkLogPointer+1)% ELNK3_MAX_LOG_SIZE; \ + Elnk3LogArray[ElnkLogPointer]=0; \ + } \ + } +#if 0 + +#define IF_LOG(c1,c2,data) { \ + \ + if (Elnk3DebugFlag & ELNK3_DEBUG_LOG) { \ + Elnk3LogArray[ElnkLogPointer].Letter1=(c2); \ + Elnk3LogArray[ElnkLogPointer].Letter2=(c1); \ + Elnk3LogArray[ElnkLogPointer].Data =(USHORT)(data); \ + ElnkLogPointer=(ElnkLogPointer+1)% ELNK3_MAX_LOG_SIZE; \ + \ + Elnk3LogArray[ElnkLogPointer].Letter1=0; \ + Elnk3LogArray[ElnkLogPointer].Letter2=0; \ + Elnk3LogArray[ElnkLogPointer].Data =0; \ + } \ + } +#endif + +#define DEBUG_STAT(x) ((x)++) + + +#else + +#define IF_LOUD(A) +#define IF_VERY_LOUD(A) +#define IF_IO_LOUD(A) +#define IF_INIT_LOUD(A) +#define IF_SEND_LOUD(A) +#define IF_RCV_LOUD(A) +#define IF_REQ_LOUD(A) + +#define DEBUG_STAT(x) + +#define IF_LOG(c1,c2,data) + +#endif diff --git a/private/ntos/ndis/elnk3/elnk3.c b/private/ntos/ndis/elnk3/elnk3.c new file mode 100644 index 000000000..3bb2caaf1 --- /dev/null +++ b/private/ntos/ndis/elnk3/elnk3.c @@ -0,0 +1,174 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + Elnk3.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + +Author: + + Brian Lieuallen BrianLie 07/21/92 + +Environment: + + Kernel Mode Operating Systems : NT, Chicago + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + +#include <ndis.h> +//#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + +VOID +Elnk3ResetCompleteOpens( + IN PELNK3_ADAPTER pAdapter + ); + + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1,-1); + + + + + + + + + + + + +BOOLEAN +Elnk3CheckForHang( + IN NDIS_HANDLE Context + ) +/*++ + +Routine Description: + + This routine is called to WakeUp the driver. It has to functions. + +Arguments: + + DeferredContext - will be a pointer to the adapter block + +Return Value: + + None. + +--*/ + +{ + PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context); + BOOLEAN Hung; + + + IF_VERY_LOUD(DbgPrint("WakeUpTimer: entered\n");) + + Hung=FALSE; + + + + return Hung; + +} + + + + + + +NDIS_STATUS +Elnk3Reset( + OUT PBOOLEAN AddressResetting, + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +Routine Description: + + NDIS function. + +Arguments: + + See NDIS 3.0 spec. + +--*/ + +{ + PELNK3_ADAPTER pAdapter = MacBindingHandle; + + IF_LOUD(DbgPrint("ELNK3: Reset() Called\n");) + + CardReStart(pAdapter); + CardReStartDone(pAdapter); + +#if 0 + + IF_LOUD( + DbgPrint("\nELNK3: Stats\n" + " Total Interrupts = %7d\n" + " EarlyReceiveInterrupts = %7d\n" + " RecieveCompInterrutps = %7d\n" + " TransmitCompInterrupts = %7d\n" + " TransmitAvailInterrupts = %7d\n" + " TransmitCompleted = %7d\n" + " Recevice Indications = %7d\n" + " Indication with data = %7d\n" + " Indications Complete = %7d\n" + " TransferData calls = %7d\n" + " SecondEarlyReceive = %7d\n" + " Broadcasts rejected = %7d\n" + " Bad receives = %7d\n\n", + pAdapter->Stats.TotalInterrupts, + pAdapter->Stats.RxEarlyIntCount, + pAdapter->Stats.RxCompIntCount, + pAdapter->Stats.TxCompIntCount, + pAdapter->Stats.TxAvailIntCount, + pAdapter->Stats.TxCompleted, + pAdapter->Stats.PacketIndicated, + pAdapter->Stats.IndicateWithDataReady, + pAdapter->Stats.IndicationCompleted, + pAdapter->Stats.TransferDataCount, + pAdapter->Stats.SecondEarlyReceive, + pAdapter->Stats.BroadcastsRejected, + pAdapter->Stats.BadReceives); + + NdisZeroMemory(&pAdapter->Stats,sizeof(DEBUG_STATS)); + ) + +#endif + + *AddressResetting=TRUE; + + return NDIS_STATUS_SUCCESS; + + +} diff --git a/private/ntos/ndis/elnk3/elnk3.h b/private/ntos/ndis/elnk3/elnk3.h new file mode 100644 index 000000000..5a2770edf --- /dev/null +++ b/private/ntos/ndis/elnk3/elnk3.h @@ -0,0 +1,424 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + Elnk3.h + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + +Author: + + Brian Lieuallen BrianLie 07/21/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + + + +#define STATIC static + + +// +// This constant is used for places where NdisAllocateMemory +// needs to be called and the HighestAcceptableAddress does +// not matter. +// + +extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax; + +// +// NDIS 3.0 entry functions +// + +BOOLEAN +Elnk3CheckForHang( + IN NDIS_HANDLE MiniportAdapterContext + ); + + + +NDIS_STATUS +Elnk3QueryInformation( + IN NDIS_HANDLE MiniportContext, + IN NDIS_OID Oid, + IN PVOID InfoBuffer, + IN ULONG BytesLeft, + OUT PULONG BytesNeeded, + OUT PULONG BytesWritten + ); + + + +NDIS_STATUS +Elnk3SetInformation( + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_OID Oid, + IN PVOID InformationBuffer, + IN ULONG InformationBufferLength, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ); + +NDIS_STATUS +Elnk3Initialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE MiniportAdapterHandle, + IN NDIS_HANDLE WrapperConfigurationContext + ); + +VOID +Elnk3Halt( + IN NDIS_HANDLE MiniportAdapterContext + ); + + +VOID +Elnk3Shutdown( + IN NDIS_HANDLE MiniportAdapterContext + ); + + +NDIS_STATUS +Elnk3Reset( + OUT PBOOLEAN AddressResetting, + IN NDIS_HANDLE MacBindingHandle + ); + + + + +NDIS_STATUS +Elnk3MacSend( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET pPacket, + IN UINT Flags + ); + +NDIS_STATUS +Elnk3TransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ); + + + +NDIS_STATUS +Elnk3Reconfigure( + OUT PNDIS_STATUS OpenErrorStatus, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE ConfigurationHanel + ); + + + + + + +VOID +Elnk3AdjustMaxLookAhead( + IN PELNK3_ADAPTER pAdapter + ); + + + + + +// +// Contained in Interrup.c +// + +VOID +Elnk3Isr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN NDIS_HANDLE Context + ); + + + +VOID +Elnk3IsrDpc( + IN NDIS_HANDLE DeferredContext // will be a pointer to the adapter block + ); + + + +VOID +Elnk3EnableInterrupts( + IN NDIS_HANDLE Context + ); + + +VOID +Elnk3DisableInterrupts( + IN NDIS_HANDLE Context + ); + + + + +// +// Contained in CARD.C +// + +BOOLEAN +CardTest ( + OUT PELNK3_ADAPTER pAdapter + ); + + + +// +// Contained in send.c +// + + +PNDIS_PACKET +RemovePacketFromQueue( + IN PPACKET_QUEUE pQueue + ); + + +BOOLEAN +MovePacketToCard( + IN PELNK3_ADAPTER pAdapter + ); + + +// +// Contained in receive.c +// + +BOOLEAN +CheckForReceives( + IN PELNK3_ADAPTER pAdapter + ); + + + +// +// Contained in config.c +// + +NDIS_STATUS +Elnk3ReadRegistry( + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE ConfigurationHandle + ); + + +BOOLEAN +CardEnable( + IN PELNK3_ADAPTER pAdapter + ); + + +BOOLEAN +CardReInit( + IN PELNK3_ADAPTER pAdapter + ); + +VOID +CardReset( + IN PELNK3_ADAPTER pAdapter + ); + + +// +// Elnk3 starts here +// + + + + + + +BOOLEAN +HandleXmtInterrupts( + PELNK3_ADAPTER pAdapter + ); + +BOOLEAN +Elnk3EarlyReceive( + PELNK3_ADAPTER pAdapter + ); + + +BOOLEAN +Elnk3IndicatePackets( + PELNK3_ADAPTER pAdapter + ); + +BOOLEAN +Elnk3IndicatePackets2( + PELNK3_ADAPTER pAdapter + ); + + + + +BOOLEAN +CardInit( + IN PELNK3_ADAPTER pAdapter + ); + + + + +UINT +Elnk3FindIsaBoards( + IN PMAC_BLOCK pMacBlock + ); + +BOOLEAN +Elnk3ActivateIsaBoard( + IN PMAC_BLOCK pMacBlock, + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE AdapterHandle, + IN PUCHAR TranslatedIoBase, + IN ULONG ConfigIoBase, + IN OUT PULONG Irq, + IN ULONG Transceiver, + IN NDIS_HANDLE ConfigurationHandle + ); + + +VOID +Elnk3EnableIsaBoard( + PVOID TranslatedIoBase + ); + + + +VOID +Elnk3GetEisaResources( + IN PELNK3_ADAPTER pAdapter, + IN OUT PULONG Irq + ); + + +VOID +CardReStart( + IN PELNK3_ADAPTER pAdapter + ); + +VOID +CardReStartDone( + IN PELNK3_ADAPTER pAdapter + ); + + +VOID +Elnk3AdjustMaxLookAhead( + IN PELNK3_ADAPTER Adapter + ); + +BOOLEAN +ReadStationAddress( + OUT PELNK3_ADAPTER pNewAdapt + ); + + +USHORT +CardSetMulticast( + PELNK3_ADAPTER pAdapter + ); + + +BOOLEAN +CardInit( + IN PELNK3_ADAPTER pAdapter + ); + +VOID +ELNK3WriteIDSequence( + IN PVOID IdPort + ); + +USHORT +ELNK3ContentionTest( + IN PVOID IdPort, + IN UCHAR EEPromWord + ); + +USHORT +ELNK3ReadEEProm( + IN PELNK3_ADAPTER Adapter, + IN UCHAR EEPromWord + ); + +VOID +Elnk3ProgramEEProm( + PELNK3_ADAPTER Adapter, + USHORT AddressConfig, + USHORT ResourceConfig + ); + +VOID +Elnk3WriteEEProm( + IN PELNK3_ADAPTER Adatper, + IN UCHAR EEPromWord, + IN USHORT Value + ); + +VOID +Elnk3WaitEEPromNotBusy( + PELNK3_ADAPTER pAdapter + ); + +NDIS_STATUS +Elnk3Init3C589( + IN OUT PELNK3_ADAPTER Adapter + ); + +NDIS_STATUS +Elnk3InitializeAdapter( + IN PMAC_BLOCK pMac, + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE ConfigurationHandle + ); + + +NDIS_STATUS +Elnk3AllocateBuffers( + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE NdisAdapterHandle, + BOOLEAN Allocate + ); + + +VOID +Elnk3InitAdapterBlock( + IN PELNK3_ADAPTER pAdapter + ); + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + + diff --git a/private/ntos/ndis/elnk3/elnk3.rc b/private/ntos/ndis/elnk3/elnk3.rc new file mode 100644 index 000000000..6c380821e --- /dev/null +++ b/private/ntos/ndis/elnk3/elnk3.rc @@ -0,0 +1,39 @@ +#include <windows.h> +#include <ntverp.h> + +/*-----------------------------------------------*/ +/* the following lines are specific to this file */ +/*-----------------------------------------------*/ + +/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR + * and VER_INTERNALNAME_STR must be defined before including COMMON.VER + * The strings don't need a '\0', since common.ver has them. + */ +#define VER_FILETYPE VFT_DRV +/* possible values: VFT_UNKNOWN + VFT_APP + VFT_DLL + VFT_DRV + VFT_FONT + VFT_VXD + VFT_STATIC_LIB +*/ +#define VER_FILESUBTYPE VFT2_DRV_NETWORK +/* possible values VFT2_UNKNOWN + VFT2_DRV_PRINTER + VFT2_DRV_KEYBOARD + VFT2_DRV_LANGUAGE + VFT2_DRV_DISPLAY + VFT2_DRV_MOUSE + VFT2_DRV_NETWORK + VFT2_DRV_SYSTEM + VFT2_DRV_INSTALLABLE + VFT2_DRV_SOUND + VFT2_DRV_COMM +*/ +#define VER_FILEDESCRIPTION_STR "3Com Etherlink III network driver" +#define VER_INTERNALNAME_STR "ELNK3.SYS" +#define VER_ORIGINALFILENAME_STR "ELNK3.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/elnk3/elnk3hrd.h b/private/ntos/ndis/elnk3/elnk3hrd.h new file mode 100644 index 000000000..d84c39841 --- /dev/null +++ b/private/ntos/ndis/elnk3/elnk3hrd.h @@ -0,0 +1,549 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + elnk3hrd.h + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + +Author: + + Brian Lieuallen BrianLie 08/21/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + +#define ELNK3_ETHERNET_HEADER_SIZE 14 +#define ELNK3_MAX_FRAME_SIZE 1514 + + +#define ELNK3_MAX_LOOKAHEAD_SIZE 1500 + + + +typedef struct _ETHERNET_HEADER { + UCHAR Destination[6]; + UCHAR Source[6]; + UCHAR EthLength[2]; + } ETHERNET_HEADER, *PETHERNET_HEADER; + + + +typedef struct _NIC_RCV_HEADER { + ETHERNET_HEADER EthHeader; + UCHAR LookAheadData[1500]; + } NIC_RCV_HEADER, *PNIC_RCV_HEADER; + +// +// EhterTypes +// + +#define XNS_FRAME_TYPE 0x0600 +#define IP_FRAME_TYPE 0x0800 +#define IPX_FRAME_TYPE 0x8137 + + +typedef struct _XNSHDR { + UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE]; + USHORT Checksum; + UCHAR Size[2]; + } XNSHDR, PXNSHDR; + +typedef struct _IPHRD { + UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE]; + USHORT Type; + UCHAR Size[2]; + } IPHDR, PIPHDR; + +typedef struct _IPXHDR { + UCHAR Ether[ELNK3_ETHERNET_HEADER_SIZE]; + USHORT Checksum; + UCHAR Size[2]; + } IPXHDR, PIPXHDR; + + + + +typedef struct _BUFFDESC { + ULONG CardOffset; + PNDIS_PACKET pPacket; + } BUFFDESC, *PBUFFDESC; + + + + +typedef enum _ELNK3_ADAPTER_TYPE { + ELNK3_3C509, + ELNK3_3C579, + ELNK3_3C529, + ELNK3_3C589 + } ELNK3_ADAPTER_TYPE, PELNK3_ADAPTER_TYPE; + + +#define ELNK3_3C529_TP_MCA_ID 0x627c +#define ELNK3_3C529_BNC_MCA_ID 0x627d +#define ELNK3_3C529_COMBO_MCA_ID 0x61db +#define ELNK3_3C529_TPCOAX_MCA_ID 0x62f6 +#define ELNK3_3C529_TPONLY_MCA_ID 0x62f7 + +#define ELNK3_EISA_ID 0x90506d50 + +#define ELNK3_3C579_EISA_ID 0x92506d50 +#define ELNK3_3C509_EISA_ID 0x90506d50 + + +/* :ts=4 this file uses 4 space tab stops */ + +/* + Hardware equates for the EtherLink III network adapter. + + Adapted from + + "3C509 and 3C509-TP Adapters Technical Reference Guide" + Manual Part No. 8369-00 + 3COM Corporation + + */ + +/* + When the adapter is in the ID_CMD state, the following writes to + the ID port are interpreted as commands. + */ + + + + + + +#define IDCMD_WAIT 0x00 /* Go to ID_WAIT state, actually 0 to 0x7f */ +#define IDCMD_READ_PROM 0x80 /* Read EEPROM word n, n is last six bits */ + /* of command */ +#define IDCMD_RESET 0xC0 /* Global reset, same as power on reset */ +#define IDCMD_SET_TAG 0xD0 /* Set Adapter tag to value in last 3 bits */ +#define IDCMD_TEST_TAG 0xD8 /* Test Adapter tag by value in last 3 bits */ +#define MAXTAG 7 +#define IDCMD_ACTIVATE 0xE0 /* Activate adapter, writing last 5 bits */ + /* into Address Configuration register */ +#define IDCMD_ACTIVATE_FF 0xFF /* Activate adapter using preconfigured */ + /* I/O base address */ +/* + Default configuration values for the EtherLink III adapter. + */ + +#define DEFAULT_ID_PORT 0x00000110 /* A port (maybe) not being used by */ + /* anything else in an ISA machine */ +/* + Card EEPROM configuration, as shipped. + */ +#define DEFAULT_IO_PORT (PVOID)0x300 +#define DEFAULT_IRQ 10 +#define DEFAULT_TRANSCEIVER TRANSCEIVER_BNC /* For the 3C509-TP, this will */ + /* be TRANSCEIVER_TP */ + +// AdaptP->MulticastListMax +// +// the maximum number of different multicast addresses that +// may be specified to this adapter (the list is global for +// all protocols). + +#define DEFAULT_MULTICASTLISTMAX 16 + + +/* + EEPROM data structure. + */ + +#define EEPROM_NODE_ADDRESS_0 0 +#define EEPROM_NODE_ADDRESS_1 1 +#define EEPROM_NODE_ADDRESS_2 2 + +#define EEPROM_PRODUCT_ID 3 + +#define EEPROM_MANUFACTURING_DATE 4 +#define EEPROM_MANUFACTURING_DATA1 5 +#define EEPROM_MANUFACTURING_DATA2 6 +#define EEPROM_MANUFACTURER_CODE 7 + +#define EEPROM_ADDRESS_CONFIGURATION 8 +#define EEPROM_RESOURCE_CONFIGURATION 9 + +#define EEPROM_OEM_NODE_0 10 +#define EEPROM_OEM_NODE_1 11 +#define EEPROM_OEM_NODE_2 12 + +#define EEPROM_SOFTWARE_INFO 13 + +#define EEPROM_RESERVED 14 + +#define EEPROM_CHECKSUM 15 + +#define EEPROM_NETWORK_MANAGEMENT_DATA_0 16 + +// +// eeprom software info bits +// +#define LINK_BEAT_DISABLED (1<<14) + + + +/* + Address configuration register. + */ + +typedef union ELNK3_Address_Configuration_Register{ + struct{ + USHORT eacf_iobase : 5; + USHORT eacf_reserved : 3; + USHORT eacf_ROMbase : 4; + USHORT eacf_ROMsize : 2; + USHORT eacf_XCVR : 2; + }; + USHORT eacf_contents; +}ELNK3_Address_Configuration_Register, *PELNK3_Address_Configuration_Register; + + +/* + EtherLink III configuration control register. + */ + +#define CCR_ENABLE_BIT 0 +#define CCR_RESET_BIT 2 + +#define CCR_ENABLE ( 1 << CCR_ENABLE_BIT ) +#define CCR_RESET ( 1 << CCR_RESET_BIT ) +/* + Transceiver configuration as stored in Address Configuration Register. + */ + +#define TRANSCEIVER_TP 0 /* Twisted pair transceiver enabled. */ +#define TRANSCEIVER_EXTERNAL 1 /* AUI port enabled, using ext. trans. */ +#define TRANSCEIVER_RESERVED 2 /* reserved - undefined */ +#define TRANSCEIVER_BNC 3 /* BNC transceiver enabled */ +#define TRANSCEIVER_UNDEFINED TRANSCEIVER_RESERVED + /* Handy dandy undefined transceiver value */ + +/* + Conversion from eacf_iobase to I/O port used. + */ +#define IOBASE_EISA 0x31 /* EISA mode slot-specific I/O address */ + +typedef union EISA_IO_Address { + struct{ + USHORT eia_port : 12; + USHORT eia_slot : 4; + }; + USHORT eia_contents; +}EISA_IO_Address, *PEISA_IO_Address; + +#define EISA_Window_0_Address 0xC80 /* Window zero is always mapped here */ + /* on an EISA machine configured */ + /* adapter */ + +/* + IOBaseAddress for an EtherLink III configured for EISA operation and installed + in an EISA slot is the slotnumber times 1000h. + */ +#define EISA_SlotNumber_To_IOBase(x) ((x) * 0x1000) + +#define EACF_IOBASE_TO_ISA_IOBASE(x) ( ( (x) << 4 ) + 0x200 ) +#define ISA_IOBASE_TO_EACF_IOBASE(x) ( ( (x) - 0x200 ) >> 4 ) + +/* + Elnk III resource configuration register. + */ + +typedef union ELNK3_Resource_Configuration_Register{ + struct{ + USHORT ercf_reserved : 8; + USHORT ercf_reserved_F : 4; + USHORT ercf_IRQ : 4; + }; + USHORT ercf_contents; +}ELNK3_Resource_Configuration_Register, *PELNK3_Resource_Configuration_Register; + +/* + Format of command word written to ELNK III command register. + */ + +typedef union ELNK3_Command{ + struct{ + USHORT ec_arg : 11; + USHORT ec_command : 5; + }; + USHORT ec_contents; +}ELNK3_Command,*PELNK3_Command; + +#define EC_GLOBAL_RESET 0 +#define EC_SELECT_WINDOW 1 +#define EC_START_COAX_XCVR 2 +#define EC_RX_DISABLE 3 +#define EC_RX_ENABLE 4 +#define EC_RX_RESET 5 + +#define EC_RX_DISCARD_TOP_PACKET 8 +#define EC_TX_ENABLE 9 +#define EC_TX_DISABLE 10 +#define EC_TX_RESET 11 + +#define EC_REQUEST_INTERRUPT 12 + +#define EC_INT_LATCH 0x01 +#define EC_INT_ADAPTER_FAILURE 0x02 +#define EC_INT_TX_COMPLETE 0x04 +#define EC_INT_TX_AVAILABLE 0x08 +#define EC_INT_RX_COMPLETE 0x10 +#define EC_INT_RX_EARLY 0x20 +#define EC_INT_INTERRUPT_REQUESTED 0x40 +#define EC_INT_UPDATE_STATISTICS 0x80 + +#define EC_ACKNOWLEDGE_INTERRUPT 13 +#define EC_SET_INTERRUPT_MASK 14 +#define EC_SET_READ_ZERO_MASK 15 + +#define EC_SET_RX_EARLY 17 +#define EC_SET_TX_AVAILIBLE 18 +#define EC_SET_TX_START 19 + +#define EC_SET_RX_FILTER 16 + +#define EC_FILTER_ADDRESS 1 +#define EC_FILTER_GROUP 2 +#define EC_FILTER_BROADCAST 4 +#define EC_FILTER_PROMISCUOUS 8 + +// +// Window Numbers +// +#define WNO_SETUP 0 // setup/configuration +#define WNO_OPERATING 1 // operating set +#define WNO_STATIONADDRESS 2 // station address setup/read +#define WNO_FIFO 3 // FIFO management +#define WNO_DIAGNOSTICS 4 // diagnostics +#define WNO_READABLE 5 // registers set by commands +#define WNO_STATISTICS 6 // statistics +// +// Port offsets, Window 1 +// +#define PORT_CmdStatus 0x0E // command/status +#define PORT_TxFree 0x0C // free transmit bytes +#define PORT_TxStatus 0x0B // transmit status (byte) +#define PORT_Timer 0x0A // latency timer (byte) +#define PORT_RxStatus 0x08 // receive status +#define PORT_RxFIFO 0x00 // RxFIFO read +#define PORT_TxFIFO 0x00 // TxFIFO write +// +// Port offsets, Window 0 +// +#define PORT_EEData 0x0C // EEProm data register +#define PORT_EECmd 0x0A // EEProm command register +#define PORT_CfgResource 0x08 // resource configuration +#define PORT_CfgAddress 0x06 // address configuration +#define PORT_CfgControl 0x04 // configuration control +#define PORT_ProductID 0x02 // product id (EISA) +#define PORT_Manufacturer 0x00 // Manufacturer code (EISA) +// +// Port offsets, Window 2 +// +#define PORT_SA0_1 0x00 // station address bytes 0,1 +#define PORT_SA2_3 0x02 // station address bytes 2,3 +#define PORT_SA4_5 0x04 // station address bytes 4,5 + +// +// port offsets, window 3 +// +#define PORT_FREE_RX_BYTES 0x0a + +// +// +// Port Offsets window 4 +// +#define PORT_FIFO_DIAG 0x04 + +#define RX_UNDERRUN 0x2000 +#define TX_OVERRUN 0x0400 + + +#define PORT_MEDIA_TYPE 0x0a + +#define MEDIA_LINK_BEAT 0x0080 +#define MEDIA_JABBER 0x0040 +#define MEDIA_SQE 0x0008 + + +#define PORT_NET_DIAG 0x06 + + + +// +// board identification codes +// +#define EISA_MANUFACTURER_ID 0x6D50 // EISA manufacturer code + +#define ISAID_BNC 0x9050 // Product ID for ISA TP board +#define ISAID_TP 0x9051 // Product ID for ISA coax board +#define EISAID 0x9052 // Product ID for EISA board +#define PCMCIAID 0x9058 // Product ID for PCMCIA board (3C589) + +//...so far the list is 5090=ISA 3C509-TP (TP/AUI), 5091h=ISA 3C509 (BNC/AUI), +// 5092h=EISA 3C579-TP (TP/AUI) and 5092h=EISA 3C579 (BNC/AUI). other +// bottom nibbles will likely be assigned to TP-only/combo/whatever +// else marketting thinks up... + +#define PRODUCT_ID_MASK 0xF0FF // Mask off revision nibble + +#define MCAID_BNC 0x627C // MCA Adapter ID: BNC/AUI +#define MCAID_TP 0x627D // MCA Adapter ID: TP/AUI +#define MCAID_COMBO 0x61DB // MCA Adapter ID: Combo (future) +#define MCAID_TPCOAX 0x62F6 // MCA Adapter ID: TP/COAX (future) +#define MCAID_TPONLY 0x62F7 // MCA Adapter ID: TP only (future) + +/* + Note: This is referred to as POS2 in 3COM's MCA Technical Reference Addendum + for the EtherLink III. + */ +#define POS1_CDEN 1 // Card enable bit in POS2 register + +/* + Note: This is referred to as POS4 in 3COM's MCA Technical Reference Addendum + for the EtherLink III. + */ +#define POS3_TO_IOBASE(x) ((((x) << 8) & 0xFC00) | 0x0200) +// +// EEProm access +// +#define EE_COMMAND_EW_ENABLE 0x30 +#define EE_COMMAND_ERASE 0xc0 +#define EE_COMMAND_WRITE 0x40 +#define EE_COMMAND_READ 0x80 + +#define EE_BUSY 0x8000 // EEProm busy bit in EECmd +#define EE_TCOM_NODE_ADDR_WORD0 0x00 +#define EE_TCOM_NODE_ADDR_WORD1 0x1 +#define EE_TCOM_NODE_ADDR_WORD2 0x2 +#define EE_VULCAN_PROD_ID 0x3 +#define EE_MANUFACTURING_DATA 0x4 +#define EE_SERIAL_NUMBER_WORD0 0x5 +#define EE_SERIAL_NUMBER_WORD1 0x6 +#define EE_MANUFACTURER_CODE 0x7 +#define EE_ADDR_CONFIGURATION 0x8 +#define EE_RESOURCE_CONFIGURATION 0x9 +#define EE_OEM_NODE_ADDR_WORD0 0xA +#define EE_OEM_NODE_ADDR_WORD1 0xB +#define EE_OEM_NODE_ADDR_WORD2 0xC +#define EE_SOFTWARE_CONFIG_INFO 0xD +#define EE_CHECK_SUM 0xF + +#define MIN_IO_BASE_ADDR 0x200 +#define MAX_IO_BASE_ADDR 0x3F0 +#define REGISTER_SET_SIZE 0x10 + + +#define RX_STATUS_INCOMPLETE 0x8000 +#define RX_STATUS_ERROR 0x4000 + +#define RX_STATUS_OVERRUN 0x08 +#define RX_STATUS_RUNT 0x0b + +#define TX_STATUS_COMPLETE 0x80 +#define TX_STATUS_INTERRUPT 0x40 +#define TX_STATUS_JABBER 0x20 +#define TX_STATUS_UNDERRUN 0x10 +#define TX_STATUS_MAX_COLLISION 0x08 +#define TX_STATUS_TX_OVERFLOW 0x04 + + +#define ELNK3_PACKET_COMPLETE(_RcvStatus) (!(((_RcvStatus) & RX_STATUS_INCOMPLETE))) + +#define DWORDS_FROM_BYTES(_status) ((_status) >> 2) + +#define BYTES_IN_FIFO(_status) ((ULONG)((_status) & 0x7ff)) + +#define BYTES_IN_FIFO_DW(_status) ((ULONG)((_status) & 0x7fc)) + +#define ELNK3_ROUND_TO_DWORD(x) (((x)+3) & 0xfffffffc) + +#ifdef NDIS_NT + +#ifndef IO_DBG +#define ELNK3_READ_PORT_USHORT(_pAdapt,offset) \ + READ_PORT_USHORT((PUSHORT)(_pAdapt)->PortOffsets[(offset)]); + +#define ELNK3_READ_PORT_USHORT_DIRECT(offset) \ + READ_PORT_USHORT((PUSHORT)(offset)); +#else +USHORT ELNK3_READ_PORT_USHORT( PVOID Adapter, ULONG Offset ); +USHORT ELNK3_READ_PORT_USHORT_DIRECT( PVOID Offset ); +#endif + +#else + +#define ELNK3_READ_PORT_USHORT(_pAdapt,offset) \ + inpw((_pAdapt)->PortOffsets[(offset)]); + +#define ELNK3_READ_PORT_USHORT_DIRECT(offset) \ + inpw((offset)); + +#endif + +#define ELNK3_COMMAND(_p,_c,_d) \ + IF_IO_LOUD(DbgPrint("Writing command %d.%d\n", (USHORT)(_c), (USHORT)(_d));) \ + NdisRawWritePortUshort((_p)->PortOffsets[PORT_CmdStatus], ((USHORT)(_c)<<11) | (_d)) + + +#define ELNK3_SELECT_WINDOW(_p,_w) \ + ELNK3_COMMAND(_p,(EC_SELECT_WINDOW),_w) + +#define ELNK3_READ_STATUS(_pAdapt,_pData) \ + NdisRawReadPortUshort((_pAdapt)->PortOffsets[PORT_CmdStatus],(_pData)); \ + IF_IO_LOUD(DbgPrint("Read status %x\n", *(PUSHORT)(_pData));) + +#define ELNK3_WAIT_NOT_BUSY(_pAdapt) { \ + \ + USHORT Status; \ + ULONG Limit=1000; \ + \ + Status=ELNK3_READ_PORT_USHORT((_pAdapt),PORT_CmdStatus); \ + \ + while ((Status & 0x1000) && (--Limit>0)) { \ + \ + Status=ELNK3_READ_PORT_USHORT((_pAdapt),PORT_CmdStatus); \ + } \ + \ + } + + +#define ELNK3WriteAdapterUchar(Adapter,PortOffset,UcharToWrite)\ + IF_IO_LOUD(DbgPrint("Writing uchar %x to port %x\n", (UCHAR)(UcharToWrite), (PortOffset));) \ + NdisRawWritePortUchar((Adapter)->PortOffsets[PortOffset],(UcharToWrite)) + + +#define ELNK3WriteAdapterUshort(Adapter,PortOffset,UshortToWrite)\ + IF_IO_LOUD(DbgPrint("Writing ushort %x to port %x\n", (USHORT)(UshortToWrite), (PortOffset));) \ + NdisRawWritePortUshort((Adapter)->PortOffsets[PortOffset],(UshortToWrite)) + + +#define ELNK3ReadAdapterUchar(Adapter,PortOffset,PUcharToRead)\ + NdisRawReadPortUchar((Adapter)->PortOffsets[PortOffset],(PUcharToRead)); \ + IF_IO_LOUD(DbgPrint("Read uchar %x from port %x\n", *(PUCHAR)(PUcharToRead), (PortOffset));) \ + + +#define ELNK3ReadAdapterUshort(Adapter,PortOffset,PUshortToRead)\ + NdisRawReadPortUshort((Adapter)->PortOffsets[PortOffset],(PUshortToRead)); \ + IF_IO_LOUD(DbgPrint("Read ushort %x from port %x\n", *(PUSHORT)(PUshortToRead), (PortOffset));) \ + + diff --git a/private/ntos/ndis/elnk3/elnk3sft.h b/private/ntos/ndis/elnk3/elnk3sft.h new file mode 100644 index 000000000..7f557a12a --- /dev/null +++ b/private/ntos/ndis/elnk3/elnk3sft.h @@ -0,0 +1,361 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + elnk3sft.h + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + +Author: + + Brian Lieuallen BrianLie 07/21/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + + + + + + +#define DEFAULT_MULTICAST_SIZE 16 +#define DEFAULT_RECEIVE_BUFFER_SIZE 238 + + +#define ELNK3_NDIS_MAJOR_VERSION 3 +#define ELNK3_NDIS_MINOR_VERSION 0 + +#define TIMER_ARRAY_SIZE 4 + +#define ELNK3_LENGTH_OF_ADDRESS 6 + + +// +// Macros +// +#define MACRO_ASSERTALL() { \ + ASSERT ( sizeof(CHAR) = 1 ); \ + ASSERT ( sizeof(UCHAR) = 1 ); \ + ASSERT ( sizeof(USHORT) = 2 ); \ + ASSERT ( sizeof(UINT) = 4 ); \ + ASSERT ( sizeof(ULONG) = 4 ); \ + } + +// +// The main MAC block structure allocated and initialized once +// + +typedef struct _ELNK3_ISA_DESCRIPTION { + USHORT AddressConfigRegister; + USHORT ResourceConfigRegister; + USHORT IOPort; + USHORT Irq; + BOOLEAN Tagged; + BOOLEAN Active; + } ELNK3_ISA_DESCRIPTION, *PELNK3_ISA_DESCRIPTION; + + + +typedef struct _MAC_BLOCK { + + // + // Translated ID port Address + // + + PUCHAR TranslatedIdPort; + + ELNK3_ISA_DESCRIPTION IsaCards[7]; + + UCHAR IsaAdaptersFound; + +} MAC_BLOCK, * PMAC_BLOCK; + + +typedef struct _PACKET_QUEUE { + PNDIS_PACKET QIn; + PNDIS_PACKET QOut; + } PACKET_QUEUE, *PPACKET_QUEUE; + + + +typedef struct _TRANSFERDATA_CONTEXT { + struct _ELNK3_ADAPTER *pAdapter; + ULONG PacketLength; + ULONG BytesAlreadyRead; + + PNIC_RCV_HEADER LookAhead; + + PNDIS_PACKET LoopBackPacket; + + PNDIS_PACKET Stack; + + ULONG pad[2]; + + } TRANSFERDATA_CONTEXT, *PTRANSFERDATA_CONTEXT; + + + + + +typedef +BOOLEAN +(*ELNK3_RECEIVE_HANDLER)( + struct _ELNK3_ADAPTER *pAdapter + ); + + + + +// +// One of these structures per adapter registered. +// + +typedef struct _ELNK3_ADAPTER { + + PVOID PortOffsets[16]; + + // + // Xmit queues stuff + // + + ELNK3_RECEIVE_HANDLER EarlyReceiveHandler; + ELNK3_RECEIVE_HANDLER ReceiveCompleteHandler; + + ULONG XmtCompleted; + + + // + // Recieve stuff + // + UINT CurrentPacket; + + UCHAR CurrentInterruptMask; + + TRANSFERDATA_CONTEXT TransContext[2]; + + + // + // Elnk3 stuff + // + + UCHAR AdapterStatus; + + UINT WakeUpErrorCount; + + BOOLEAN RejectBroadcast; + + BOOLEAN InitInterrupt; + + // + // NDIS Interrupt information + // + + NDIS_MINIPORT_INTERRUPT NdisInterrupt; + NDIS_INTERRUPT_MODE InterruptMode; + BOOLEAN AdapterInitializing; + + // + // NDIS wrapper information. + // + + NDIS_HANDLE NdisAdapterHandle; // returned from NdisRegisterAdapter + + // + // Registry information + // + ULONG Transceiver; + + UINT IoPortBaseAddr; + PVOID TranslatedIoBase; + + + ELNK3_ADAPTER_TYPE CardType; + ULONG IrqLevel; + ULONG ReceiveMethod; + + UCHAR StationAddress[ELNK3_LENGTH_OF_ADDRESS]; // filled in at init time + + UCHAR PermanentAddress[ELNK3_LENGTH_OF_ADDRESS]; // filled in at init time + + USHORT EEpromSoftwareInfo; + + ULONG FramesXmitGood; // Good Frames Transmitted + ULONG FramesRcvGood; // Good Frames Received + ULONG FramesXmitBad; // Bad Frames Transmitted + ULONG FramesXmitOneCollision; // Frames Transmitted with one collision + ULONG FramesXmitManyCollisions; // Frames Transmitted with > 1 collision + ULONG FrameAlignmentErrors; // FAE errors counted + ULONG CrcErrors; // CRC errors counted + ULONG MissedPackets; // missed packet counted + + + // + // Look Ahead information. + // + + ULONG MaxLookAhead; + ULONG EarlyReceiveThreshold; + ULONG LatencyAdjustment; + ULONG LookAheadLatencyAdjustment; + LONG FirstEarlyThreshold; + ULONG LowWaterMark; + ULONG ThresholdTarget; + + ULONG AverageLatency; + ULONG IdPortBaseAddr; + + USHORT TxStartThreshold; + USHORT TxStartThresholdInc; + + ULONG RxMinimumThreshold; + ULONG RxFifoSize; + UINT NdisRxFilter; + UCHAR RxFilter; + UCHAR RevisionLevel; + ULONG RxHiddenBytes; + + BOOLEAN IdPortOwner; + + // + // Adapter specific Infomation + // + + + UCHAR WakeUpState; + BOOLEAN AdapterFailed; + + + + ULONG TimerValues[TIMER_ARRAY_SIZE]; + ULONG CurrentTimerValue; + + +#if DBG + + DEBUG_STATS Stats; + +#endif + + + +} ELNK3_ADAPTER, * PELNK3_ADAPTER; + +#define STATUS_REINIT_REQUESTED 0x0001 +#define STATUS_RESET_INITIATED 0x0002 +#define STATUS_RESET_IN_PROGRESS 0x0004 +#define STATUS_MOVING_TO_CARD 0x0008 +#define STATUS_SEND_BLOCK_USED 0x0010 +#define STATUS_INITIALIZING 0x0020 +#define STATUS_SHUTDOWN 0x0040 + +// +// What we map into the reserved section of a packet. +// Cannot be more than 16 bytes (see ASSERT in send.c). +// + + +#define NdisRequestClose 1 +#define NdisRequestRequest 2 +#define NdisRequestReset1 3 +#define NdisRequestReset2 4 + + +#define SEND_STATUS_LOOPBACK 0x01 +#define SEND_STATUS_FAILED 0x02 +#define SEND_STATUS_BUFFER_USED 0x04 +#define SEND_STATUS_ABORTED 0x08 +#define SEND_STATUS_ONE_COLLISION 0x10 +#define SEND_STATUS_MANY_COLLISIONS 0x20 + +#define SEND_STATUS_SMALL_PACKET 0x40 + + +typedef struct _PACKET_RESERVED { + PNDIS_PACKET Next; // used to link in the queues (4 bytes) + union { + struct { + + USHORT PacketLength; + UCHAR Status; + + } Send; + + struct { + + USHORT ByteOffset; + USHORT BytesToTransfer; + + } TransData; + } u; + + } PACKET_RESERVED, * PPACKET_RESERVED; + + + +// +// These appear in the status field of MAC_RESERVED; they are +// used because there is not enough room for a full NDIS_HANDLE. +// + +#define RESERVED_SUCCESS ((USHORT)0) +#define RESERVED_FAILURE ((USHORT)1) + +// +// Retrieve the MAC_RESERVED structure from a packet. +// + +#define PACKET_RESERVED(Packet) ((PPACKET_RESERVED)((Packet)->MacReserved)) + +#define ADD_PACKET_TO_QUEUE(pQueue,pPacket) { \ + \ + PACKET_RESERVED(pPacket)->Next = NULL; \ + if ((pQueue)->QOut==NULL) { \ + \ + (pQueue)->QOut=pPacket; \ + \ + } else { \ + \ + PACKET_RESERVED((pQueue)->QIn)->Next=pPacket; \ + } \ + \ + (pQueue)->QIn=pPacket; \ + \ + } + +#define INIT_PACKET_QUEUE(pQueue) { \ + (pQueue)->QIn=NULL; \ + (pQueue)->QOut=NULL; \ + } + +#define QUEUE_EMPTY(pQueue) ((pQueue)->QOut==NULL) + +#define PEEK_QUEUE(pQueue) (pQueue)->QOut + +#define NEXT_PACKET(pQueue) (pQueue)->QOut=PACKET_RESERVED((pQueue)->QOut)->Next; + + + +#define DEFAULT_MULTICASTLISTMAX 16 + + + + +typedef struct _SYNC_CONTEXT { + ULONG Value; + PELNK3_ADAPTER pAdapter; + } SYNC_CONTEXT, *PSYNC_CONTEXT; diff --git a/private/ntos/ndis/elnk3/init.c b/private/ntos/ndis/elnk3/init.c new file mode 100644 index 000000000..a20c96a8d --- /dev/null +++ b/private/ntos/ndis/elnk3/init.c @@ -0,0 +1,897 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + init.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + +Author: + + Brian Lieuallen (BrianLie) 12/14/92 + + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + +#include <ndis.h> + +//#include <efilter.h> + +#include "debug.h" + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + +#if defined(ALLOC_PRAGMA) +#pragma NDIS_INIT_FUNCTION(DriverEntry) +#pragma NDIS_INIT_FUNCTION(Elnk3Initialize) +#pragma NDIS_INIT_FUNCTION(Elnk3InitializeAdapter) +#pragma NDIS_INIT_FUNCTION(Elnk3Init3C589) +#endif + + +#if DBG + +ULONG Elnk3DebugFlag; +ULONG Elnk3LogArray[ELNK3_MAX_LOG_SIZE+16]; +ULONG ElnkLogPointer; + +#endif + +MAC_BLOCK MacBlock = {0}; + + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + + +/*++ + +Routine Description: + + This is the transfer address of the driver. It initializes all the + appropriate variables used and calls NdisInitializeWrapper() and + NdisRegisterMac(). + + +Arguments: + +Return Value: + + Indicates the success or failure of the initialization. + +--*/ + +{ + NDIS_STATUS InitStatus; + NDIS_MINIPORT_CHARACTERISTICS Characteristics; + NDIS_HANDLE WrapperHandle; + + + +#if DBG + + Elnk3DebugFlag = 0; + Elnk3DebugFlag|= ELNK3_DEBUG_LOG; +// Elnk3DebugFlag|= ELNK3_DEBUG_LOUD; +// Elnk3DebugFlag|= ELNK3_DEBUG_VERY_LOUD; +// Elnk3DebugFlag|= ELNK3_DEBUG_INIT; +// Elnk3DebugFlag|= ELNK3_DEBUG_IO; +// Elnk3DebugFlag|= ELNK3_DEBUG_REQ; +// Elnk3DebugFlag|= ELNK3_DEBUG_RCV; +// Elnk3DebugFlag|= ELNK3_DEBUG_SEND; +// Elnk3DebugFlag|= ELNK3_DEBUG_INIT_BREAK; + + +#endif + + IF_INIT_LOUD(DbgPrint("Elnk3: DriverEntry\n");) +#if DBG + if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_BREAK) DbgBreakPoint(); + if (Elnk3DebugFlag & ELNK3_DEBUG_INIT_FAIL) return STATUS_UNSUCCESSFUL; +#endif + + NdisMInitializeWrapper( + &WrapperHandle, + DriverObject, + RegistryPath, + NULL + ); + + + + // + // Prepare to call NdisRegisterMac. + // + + Characteristics.MajorNdisVersion = ELNK3_NDIS_MAJOR_VERSION; + Characteristics.MinorNdisVersion = ELNK3_NDIS_MINOR_VERSION; + Characteristics.Reserved = 0; + Characteristics.CheckForHangHandler = Elnk3CheckForHang; + +// Characteristics.DisableInterruptHandler = Elnk3DisableInterrupts; +// Characteristics.EnableInterruptHandler = Elnk3EnableInterrupts; + Characteristics.DisableInterruptHandler = NULL; + Characteristics.EnableInterruptHandler = NULL; + + Characteristics.SendHandler = Elnk3MacSend; + Characteristics.TransferDataHandler = Elnk3TransferData; + Characteristics.ResetHandler = Elnk3Reset; + Characteristics.SetInformationHandler = Elnk3SetInformation; + Characteristics.QueryInformationHandler = Elnk3QueryInformation; + Characteristics.InitializeHandler = Elnk3Initialize; + Characteristics.HaltHandler = Elnk3Halt; + Characteristics.ISRHandler = Elnk3Isr; + Characteristics.HandleInterruptHandler = Elnk3IsrDpc; + Characteristics.ReconfigureHandler = Elnk3Reconfigure; + + InitStatus=NdisMRegisterMiniport( + WrapperHandle, + &Characteristics, + sizeof(Characteristics) + ); + + +#if DBG + + if (InitStatus != NDIS_STATUS_SUCCESS) { + + IF_LOUD(DbgPrint("Elnk3: NdisMRegisterMiniport failed with code 0x%x\n", InitStatus );) + + } else { + + IF_INIT_LOUD (DbgPrint("Elnk3: NdisMRegisterMiniport succeeded\n" );) + + + } + +#endif + + return InitStatus; + +} + + + + + + +NDIS_STATUS +Elnk3Initialize( + OUT PNDIS_STATUS OpenErrorStatus, + OUT PUINT SelectedMediumIndex, + IN PNDIS_MEDIUM MediumArray, + IN UINT MediumArraySize, + IN NDIS_HANDLE AdapterHandle, + IN NDIS_HANDLE ConfigurationHandle + ) +/*++ +Routine Description: + + This is the Elnk3 MacAddAdapter routine. The system calls this routine + to add support for particular UB adapter. This routine extracts + configuration information from the configuration data base and registers + the adapter with NDIS. + + +Arguments: + + +Return Value: + + NDIS_STATUS_SUCCESS - Adapter was successfully added. + NDIS_STATUS_FAILURE - Adapter was not added + +--*/ +{ + + PELNK3_ADAPTER pAdapter; + NDIS_STATUS status; + + + + + *OpenErrorStatus=NDIS_STATUS_SUCCESS; + + IF_LOUD (DbgPrint("ELNK3: Initialize\n");) + + // + // Scan the media list for our media type (802.3) + // + + *SelectedMediumIndex =(UINT) -1; + + while (MediumArraySize > 0) { + + if (MediumArray[--MediumArraySize] == NdisMedium802_3 ) { + + *SelectedMediumIndex = MediumArraySize; + + break; + } + } + + + if (*SelectedMediumIndex == -1) { + + return NDIS_STATUS_UNSUPPORTED_MEDIA; + + } + + + + status = NdisAllocateMemory( + (PVOID *)&pAdapter, + sizeof(ELNK3_ADAPTER), + 0, + HighestAcceptableMax + ); + + if (status != NDIS_STATUS_SUCCESS) { + + IF_LOUD (DbgPrint("Elnk3AddAdapter():NdisAllocateMemory() failed\n");) + + return NDIS_STATUS_RESOURCES; + + } + + NdisZeroMemory(pAdapter,sizeof(ELNK3_ADAPTER)); + + pAdapter->NdisAdapterHandle=AdapterHandle; + + // + // Read Registery information into Adapter structure + // + + if (Elnk3ReadRegistry(pAdapter,ConfigurationHandle)==NDIS_STATUS_SUCCESS) { + // + // We got the registry info try to register the adpater + // + + if (Elnk3InitializeAdapter( + &MacBlock, + pAdapter, + ConfigurationHandle)== NDIS_STATUS_SUCCESS) { + + + return NDIS_STATUS_SUCCESS; + + } + + } else { + + IF_LOUD(DbgPrint("Failed to get config info, probably bad Slot number\n");) + + } + + // + // We failed to register the adapter for some reason, so free the + // memory for the adapter block and return failure + + NdisFreeMemory(pAdapter, + sizeof(ELNK3_ADAPTER), + 0); + + return NDIS_STATUS_FAILURE; + +} + + + + +NDIS_STATUS +Elnk3InitializeAdapter( + IN PMAC_BLOCK pMac, + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE ConfigurationHandle + ) + +/*++ + +Routine Description: + + Called when a new adapter should be registered. + Initializes the adapter block, and calls NdisRegisterAdapter(). + +Arguments: + + AdapterName - The name that the system will refer to the adapter by. + Others - Adapter-specific parameters as defined in defaults.h. + +Return Value: + + Indicates the success or failure of the registration. + +--*/ + +{ + NDIS_STATUS Status; + NDIS_INTERFACE_TYPE InterfaceType; + UINT i; + PVOID TranslatedIdPort=NULL; + + + Elnk3InitAdapterBlock(pAdapter); + + // + // Initialize various elments in the Adapter Structure; + // + + if ((pAdapter->CardType==ELNK3_3C509) || + ((pAdapter->CardType==ELNK3_3C589))) { + + InterfaceType = NdisInterfaceIsa; + + } else { + + if (pAdapter->CardType==ELNK3_3C579) { + + InterfaceType = NdisInterfaceEisa; + + } else { + + InterfaceType = NdisInterfaceMca; + } + + } + + NdisMSetAttributes( + pAdapter->NdisAdapterHandle, + pAdapter, + FALSE, + InterfaceType + ); + + if ((pMac->TranslatedIdPort==0) && (pAdapter->CardType==ELNK3_3C509)) { + + IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port\n");) + + Status=NdisMRegisterIoPortRange( + &TranslatedIdPort, + pAdapter->NdisAdapterHandle, + pAdapter->IdPortBaseAddr, + 1 + ); + + if (Status != NDIS_STATUS_SUCCESS) { + + IF_INIT_LOUD(DbgPrint("Elnk3: First ISA card claiming Id port---FAILED\n");) + + goto fail0; + + } + + + pAdapter->IdPortOwner=TRUE; + + pMac->TranslatedIdPort=TranslatedIdPort; + + // + // See if there are any boards around + // + Elnk3FindIsaBoards(pMac); + } + + Status=NdisMRegisterIoPortRange( + &pAdapter->TranslatedIoBase, + pAdapter->NdisAdapterHandle, + pAdapter->IoPortBaseAddr, + 16 + ); + + + if (Status != NDIS_STATUS_SUCCESS) { + + IF_INIT_LOUD(DbgPrint("Elnk3: Failed to register i/o ports\n");) + + goto fail1; + + } + + // + // Compute the portaddresses now so we don't have to + // do it on each port access + // + for (i=0;i<16;i++) { + + pAdapter->PortOffsets[i]=(PUCHAR)pAdapter->TranslatedIoBase+i; + + } + + + + + + if (pAdapter->CardType==ELNK3_3C509) { + // + // Lets try to find a card at the address specified + // + // Note: this service may change the I/O base aquired + // from the registry. This will happen if we can't + // find a match. + // + + if (!Elnk3ActivateIsaBoard( + pMac, + pAdapter, + pAdapter->NdisAdapterHandle, + pAdapter->TranslatedIoBase, + pAdapter->IoPortBaseAddr, + &pAdapter->IrqLevel, + pAdapter->Transceiver, + ConfigurationHandle + )) { + + NdisWriteErrorLogEntry( + pAdapter->NdisAdapterHandle, + NDIS_ERROR_CODE_BAD_IO_BASE_ADDRESS, + 8, + pAdapter->IoPortBaseAddr, + pMac->IsaCards[0].IOPort, + pMac->IsaCards[1].IOPort, + pMac->IsaCards[2].IOPort, + pMac->IsaCards[3].IOPort, + pMac->IsaCards[4].IOPort, + pMac->IsaCards[5].IOPort, + pMac->IsaCards[6].IOPort + ); + + Status=NDIS_STATUS_ADAPTER_NOT_FOUND; + + goto fail2; + } + + } + + + + else if (pAdapter->CardType==ELNK3_3C579) { + // + // Get the Irq from the eisa adapter since the 3com + // CFG put the interrupt information in the second + // function of the EISA info instead of making it + // a sub function. + // + + Elnk3GetEisaResources( + pAdapter, + &pAdapter->IrqLevel + ); + } + + else if (pAdapter->CardType==ELNK3_3C589) + { + Status = Elnk3Init3C589( pAdapter); + if (Status != NDIS_STATUS_SUCCESS) { + + IF_INIT_LOUD(DbgPrint("Elnk3: Failed to initialize 3C589\n");) + + goto fail1; + } + } + + + // + // Allocate the Send, LookAhead and LoopBack buffers + // + Status=Elnk3AllocateBuffers( + pAdapter, + pAdapter->NdisAdapterHandle, + TRUE + ); + + + if (Status!=NDIS_STATUS_SUCCESS) { + + goto fail2; + } + + + // + // Make sure the card is inactive + // + CardReset(pAdapter); + + pAdapter->AdapterInitializing=TRUE; + + + + // + // Set up the interrupt handlers. + // + + NdisZeroMemory (&pAdapter->NdisInterrupt, sizeof(NDIS_MINIPORT_INTERRUPT) ); + + Status=NdisMRegisterInterrupt( + &pAdapter->NdisInterrupt, // interrupt info str + pAdapter->NdisAdapterHandle, // NDIS adapter handle + (UINT)pAdapter->IrqLevel, // vector or int number + (UINT)pAdapter->IrqLevel, // level or priority + TRUE, + FALSE, // NOT shared + pAdapter->InterruptMode + ); + + + if (Status != NDIS_STATUS_SUCCESS) { + + IF_LOUD (DbgPrint("ELNK3: NdisInitializeInterruptFailed\n");) + NdisWriteErrorLogEntry( + pAdapter->NdisAdapterHandle, + NDIS_ERROR_CODE_INTERRUPT_CONNECT, + 1, + (ULONG)pAdapter->IrqLevel + ); + + + goto fail3; + } + + + // + // Perform card tests. + // + if (!CardTest(pAdapter) ) { + + IF_LOUD ( DbgPrint("ELNK3: CardTest() failed, game over\n");) + + NdisWriteErrorLogEntry( + pAdapter->NdisAdapterHandle, + NDIS_ERROR_CODE_ADAPTER_NOT_FOUND, + 2, + (ULONG)pAdapter->IrqLevel, + (ULONG)pAdapter->IoPortBaseAddr + ); + + + Status = NDIS_STATUS_FAILURE; + goto fail4; + } + + // register a shutdown handler for this card + NdisMRegisterAdapterShutdownHandler( + pAdapter->NdisAdapterHandle, // miniport handle. + pAdapter, // shutdown context. + Elnk3Shutdown // shutdown handler. + ); + + CardReStart(pAdapter); + CardReStartDone(pAdapter); + + IF_LOUD (DbgPrint("Elnk3: Elnk3InitializeAdapter() Succeeded\n");) + + return NDIS_STATUS_SUCCESS; + + + // + // IF WE ARE HERE SOME INITIALIZATION FAILURE OCCURRED + // + + + // + // Code to unwind what has already been set up when a part of + // initialization fails, which is jumped into at various + // points based on where the failure occured. Jumping to + // a higher-numbered failure point will execute the code + // for that block and all lower-numbered ones. + // + + +fail4: + + NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt); + + +fail3: + + Elnk3AllocateBuffers( + pAdapter, + pAdapter->NdisAdapterHandle, + FALSE + ); + +fail2: + + NdisMDeregisterIoPortRange( + pAdapter->NdisAdapterHandle, + pAdapter->IoPortBaseAddr, + 16, + pAdapter->TranslatedIoBase + ); + + + +fail1: + + if (pAdapter->IdPortOwner) { + + IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");) + + NdisMDeregisterIoPortRange( + pAdapter->NdisAdapterHandle, + pAdapter->IdPortBaseAddr, + 1, + pMac->TranslatedIdPort + ); + + + + pMac->TranslatedIdPort=0; + } + +fail0: + + IF_LOUD (DbgPrint("Elnk3RegisterAdapter() Failed\n");) + return Status; +} + + + + + +NDIS_STATUS +Elnk3AllocateBuffers( + IN PELNK3_ADAPTER pAdapter, + IN NDIS_HANDLE NdisAdapterHandle, + BOOLEAN Allocate + ) + +{ + NDIS_STATUS Status; + + + if (Allocate) { + + // + // Allocate the memory to hold the loopback indication + // + + Status=NdisAllocateMemory( + (PVOID *)(&pAdapter->TransContext[0].LookAhead), + 4096, + 0, + HighestAcceptableMax + ); + + if (Status!=NDIS_STATUS_SUCCESS) { + goto Fail0000; + } + + pAdapter->TransContext[1].LookAhead= + (PNIC_RCV_HEADER)((PUCHAR)pAdapter->TransContext[0].LookAhead+2048); + + IF_INIT_LOUD(DbgPrint("ELNK3: Lookahead->%08lx\n",pAdapter->TransContext[0].LookAhead);) + + + + return NDIS_STATUS_SUCCESS; + + } + + + NdisFreeMemory( + pAdapter->TransContext[0].LookAhead, + 4096, + 0 + ); + + + +Fail0000: + + return NDIS_STATUS_RESOURCES; + +} + + + +VOID +Elnk3InitAdapterBlock( + IN PELNK3_ADAPTER pAdapter + ) + +{ + UINT i; + + + // + // BUGBUG: This could probably be smaller, but NBF doesn't currently set a + // lookahead size + // + + pAdapter->MaxLookAhead=60 ; //ELNK3_MAX_LOOKAHEAD_SIZE; + + Elnk3AdjustMaxLookAhead(pAdapter); + + for (i=0; i<TIMER_ARRAY_SIZE; i++) { + pAdapter->TimerValues[i]=25; + } + + pAdapter->TransContext[0].pAdapter = pAdapter; + pAdapter->TransContext[1].pAdapter = pAdapter; + + + if (pAdapter->CardType==ELNK3_3C529) { + // + // MCA card does not hide bytes + // + pAdapter->RxHiddenBytes=0; + + } else { + // + // ISA hides 16 + // + pAdapter->RxHiddenBytes=16; + } + + pAdapter->RxMinimumThreshold=8; + + // + // Set the minimum amount that needs to be in the fifo + // before we draw out some of an incomplete packet + // + pAdapter->LowWaterMark=64; + + + return; +} + + +VOID +Elnk3Shutdown( + IN NDIS_HANDLE MiniportHandle + ) +{ + PELNK3_ADAPTER pAdapter=MiniportHandle; + + IF_INIT_LOUD(DbgPrint("Elnk3: Shutdown\n");) + + // + // It's time to rock and roll + // + CardReStart(pAdapter); +} + +VOID +Elnk3Halt( + IN NDIS_HANDLE MiniportHandle + ) +{ + + PELNK3_ADAPTER pAdapter=MiniportHandle; + + IF_INIT_LOUD(DbgPrint("Elnk3: Halt\n");) + // + // It's time to rock and roll + // + CardReStart(pAdapter); + + NdisMDeregisterInterrupt(&pAdapter->NdisInterrupt); + + if (pAdapter->IdPortOwner) { + + IF_INIT_LOUD(DbgPrint("Elnk3: Id port owner going away\n");) + + NdisMDeregisterIoPortRange( + pAdapter->NdisAdapterHandle, + pAdapter->IdPortBaseAddr, + 1, + MacBlock.TranslatedIdPort + ); + + MacBlock.TranslatedIdPort=0; + } + + + NdisMDeregisterIoPortRange( + pAdapter->NdisAdapterHandle, + pAdapter->IoPortBaseAddr, + 16, + pAdapter->TranslatedIoBase + ); + + Elnk3AllocateBuffers( + pAdapter, + pAdapter->NdisAdapterHandle, + FALSE + ); + + + NdisFreeMemory( + pAdapter, + sizeof(ELNK3_ADAPTER), + 0 + ); +} + + +NDIS_STATUS +Elnk3Reconfigure( + OUT PNDIS_STATUS OpenErrorStatus, + IN NDIS_HANDLE MiniportAdapterContext, + IN NDIS_HANDLE ConfigurationHandle + ) + +{ + + IF_INIT_LOUD(DbgPrint("Elnk3: Reconfigure\n");) + + return NDIS_STATUS_NOT_SUPPORTED; + + +} + + +NDIS_STATUS +Elnk3Init3C589( + IN OUT PELNK3_ADAPTER pAdapter + ) + +{ + ELNK3_Address_Configuration_Register acr; + ELNK3_Resource_Configuration_Register rcr; + USHORT i, window; + NDIS_STATUS Status; + + Status = NDIS_STATUS_SUCCESS; + + ELNK3ReadAdapterUshort ( pAdapter , PORT_CmdStatus , &window ); + window &= 0xE000; // Current window - high 3 bits + + ELNK3_SELECT_WINDOW( pAdapter, WNO_SETUP ); + + // + // init address configuration + // + acr.eacf_contents = 0; + + if ( pAdapter->Transceiver == TRANSCEIVER_BNC ) { + acr.eacf_XCVR = TRANSCEIVER_BNC; + } + + ELNK3WriteAdapterUshort(pAdapter,PORT_CfgAddress,acr.eacf_contents); + + // Believe it or not, to make the 3C589 (not 3C589B) the IRQ have to be set + // to 3 (it can be anything - the card must be told 3). + rcr.ercf_contents = 0; + // rcr.ercf_IRQ = (USHORT)pAdapter->IrqLevel; + rcr.ercf_IRQ = 3; + rcr.ercf_reserved_F = 0xF; + ELNK3WriteAdapterUshort(pAdapter,PORT_CfgResource,rcr.ercf_contents); + + // read in product ID + i = ELNK3ReadEEProm( pAdapter, EEPROM_PRODUCT_ID ); + ELNK3WriteAdapterUshort( pAdapter, PORT_ProductID, i ); + + // Enable the adapter by setting the bit in the configuration control register + ELNK3WriteAdapterUchar(pAdapter,PORT_CfgControl,CCR_ENABLE); + + // restore to whatever it used to be + ELNK3_SELECT_WINDOW( pAdapter, window); + + return (Status); + +} + + diff --git a/private/ntos/ndis/elnk3/interrup.c b/private/ntos/ndis/elnk3/interrup.c new file mode 100644 index 000000000..d357eb7a1 --- /dev/null +++ b/private/ntos/ndis/elnk3/interrup.c @@ -0,0 +1,418 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + interrup.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + +Author: + + Brian Lieuallen (BrianLie) 07/02/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + + +--*/ + + + + +#include <ndis.h> +#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + + +VOID +CompleteRequests( + IN PELNK3_ADAPTER pAdapter + ); + +VOID +ELNK3MaskClearInterrupt( + IN PELNK3_ADAPTER pAdapter, + IN UCHAR Mask + ); + +VOID +ELNK3UnmaskInterrupt( + IN PELNK3_ADAPTER pAdapter, + IN UCHAR Mask + ); + + + +VOID +Elnk3Isr( + OUT PBOOLEAN InterruptRecognized, + OUT PBOOLEAN QueueDpc, + IN NDIS_HANDLE Context + ) + +/*++ + +Routine Description: + +Arguments: + + ServiceContext - pointer to the adapter object + +Return Value: + + TRUE, if the DPC is to be executed, otherwise FALSE. + +--*/ + +{ + PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context); + USHORT InterruptReason; + + *InterruptRecognized=TRUE; + *QueueDpc=TRUE; + + + InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + if ((InterruptReason & 0x01)==0) { + // + // The ISR has run with out an interrupt present on the card, Hmm + // + // This was added because the AST manhatton seems to run the ISR on + // muliple processors for a given interrupt + // + + IF_LOUD(DbgPrint("Elnk3: Isr bit 0 clear %04x adapter=%08lx\n",InterruptReason,pAdapter);) + + *InterruptRecognized=FALSE; + *QueueDpc=FALSE; + return; + } + + if (pAdapter->AdapterInitializing) { + IF_INIT_LOUD (DbgPrint("Elnk3: ISR called during init\n");) + pAdapter->InitInterrupt=TRUE; + + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_INTERRUPT_REQUESTED | 1); + + *QueueDpc=FALSE; + + return; + } + + + + // + // needed for level triggered MCA cards + // + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK, 0x00 ); + + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT, 1); + + return; +} + + + +VOID +Elnk3IsrDpc( + IN NDIS_HANDLE Context + ) +/*++ + +Routine Description: + +Arguments: + + +Return Value: + + +--*/ + +{ + PELNK3_ADAPTER pAdapter = ((PELNK3_ADAPTER)Context); + UCHAR InterruptReason; + USHORT TimerValue; + ULONG Latency; + UINT LoopLimit=10; + + + + DEBUG_STAT(pAdapter->Stats.TotalInterrupts); + + // + // Read the timer port to keep track of latencies + // + TimerValue=ELNK3_READ_PORT_USHORT(pAdapter,PORT_Timer); + + if ((UCHAR)TimerValue==0xff) { + // + // The timer has maxed out. We will just use the last + // average to hopefully keep things in line. + // + + TimerValue=(UCHAR)pAdapter->AverageLatency; + } + + pAdapter->TimerValues[pAdapter->CurrentTimerValue]=(UCHAR)TimerValue; + + pAdapter->CurrentTimerValue= (pAdapter->CurrentTimerValue+1) % TIMER_ARRAY_SIZE; + + IF_LOG(0x11,0x11,(TimerValue & 0xff)<<2); + + + InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + while (((InterruptReason & pAdapter->CurrentInterruptMask) != 0) + && + ((--LoopLimit) != 0)) { + + + IF_LOG(0x11,0x22,InterruptReason); + + if (InterruptReason & EC_INT_ADAPTER_FAILURE) { + + IF_LOUD( + DbgPrint("ELNK3: Adapter Failed\n"); + DbgBreakPoint(); + ) + + // + // No more interrupts + // + ELNK3_COMMAND(pAdapter,EC_SET_READ_ZERO_MASK,0x00); + + // + // Clear what ever is there now + // + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT, 0xff); + + // + // Something is messed up so no point in handling any thing + // + InterruptReason=0; + + // + // Get the reinit code to run + // + pAdapter->AdapterStatus |= STATUS_REINIT_REQUESTED; + } + + // + // Interrupts are basically grouped into two catagories + // Recieve and xmit + // + + if ((InterruptReason & (EC_INT_TX_COMPLETE)) ) { + + IF_VERY_LOUD (DbgPrint("Handle xmit int\n");) + + DEBUG_STAT(pAdapter->Stats.TxCompIntCount); + + + HandleXmtInterrupts(pAdapter); + + NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle); + + } else { + + if ((InterruptReason & (EC_INT_RX_EARLY | EC_INT_RX_COMPLETE)) ) { + + if (InterruptReason & (EC_INT_RX_COMPLETE) ) { + + // + // Rx complete will be clear when we handle the interrupt + // + DEBUG_STAT(pAdapter->Stats.RxCompIntCount); + + (*pAdapter->ReceiveCompleteHandler)(pAdapter); + + } else { + + DEBUG_STAT(pAdapter->Stats.RxEarlyIntCount); + + // + // dismiss the rx early int + // + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_RX_EARLY ); + + (*pAdapter->EarlyReceiveHandler)(pAdapter); + } + + + } else { + + if ((InterruptReason & (EC_INT_TX_AVAILABLE)) ) { + + ELNK3_COMMAND(pAdapter,EC_ACKNOWLEDGE_INTERRUPT,EC_INT_TX_AVAILABLE ); + + DEBUG_STAT(pAdapter->Stats.TxAvailIntCount); + + NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle); + + } else { + + if ((InterruptReason & (EC_INT_INTERRUPT_REQUESTED)) ) { + // + // Dismiss the user requested interrupt + // + IF_SEND_LOUD(DbgPrint("Elnk3: Requested interrupt\n");) + + ELNK3_COMMAND(pAdapter, EC_ACKNOWLEDGE_INTERRUPT, EC_INT_INTERRUPT_REQUESTED); + + } + } + } + } + + + InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + } // while (interrupt reasons) + + // + // Unmask interrupts + // + + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask); + + + // + // We calculate the latency average from the last four + // DPC latencies every four DPC runs + // + + if (pAdapter->CurrentTimerValue == 0) { + + Latency=((ULONG)pAdapter->TimerValues[0] + + pAdapter->TimerValues[1] + + pAdapter->TimerValues[2] + + pAdapter->TimerValues[3])/4; + + // + // The latency is dword times and we want byte times + // + + pAdapter->AverageLatency=Latency; + + Latency<<=2; + + if ((pAdapter->EarlyReceiveThreshold-pAdapter->RxMinimumThreshold) < Latency) { + + pAdapter->LookAheadLatencyAdjustment=pAdapter->RxMinimumThreshold & 0x7fc; + pAdapter->LatencyAdjustment=Latency+pAdapter->RxHiddenBytes; + } else { + + pAdapter->LookAheadLatencyAdjustment=pAdapter->EarlyReceiveThreshold-Latency & 0x7fc; + pAdapter->LatencyAdjustment=Latency+pAdapter->RxHiddenBytes; + } + + IF_LOG(0xcc,0xcc,Latency); + + } + + + + // + // See if the card needs to restarted + // + if (pAdapter->AdapterStatus & STATUS_REINIT_REQUESTED ) { + IF_LOUD(DbgPrint("Elnk3: Handling pending request\n");) + + // + // It's time to rock and roll + // + CardReStart(pAdapter); + + + CardReStartDone(pAdapter); + + // + // Done re-initializing + // + pAdapter->AdapterStatus &= ~STATUS_REINIT_REQUESTED; + + + } + + + +#if DBG + InterruptReason=(UCHAR)ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + IF_LOG(0x11,0x33,InterruptReason); +#endif +} + +#if 0 + +VOID +Elnk3EnableInterrupts( + IN NDIS_HANDLE Context + ) +/*++ + +Routine Description: + +Arguments: + + +Return Value: + + +--*/ + +{ + PELNK3_ADAPTER pAdapter=Context; + +// IF_INIT_LOUD(DbgPrint("Elnk3: EnableInterrupts\n");) + + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK,pAdapter->CurrentInterruptMask); + +} + + +VOID +Elnk3DisableInterrupts( + IN NDIS_HANDLE Context + ) +/*++ + +Routine Description: + +Arguments: + + +Return Value: + + +--*/ + +{ + PELNK3_ADAPTER pAdapter=Context; + +// IF_INIT_LOUD(DbgPrint("Elnk3: DisableInterrupts\n");) + + ELNK3_COMMAND(pAdapter,EC_SET_INTERRUPT_MASK, 0x00); + +} + +#endif diff --git a/private/ntos/ndis/elnk3/keywords.h b/private/ntos/ndis/elnk3/keywords.h new file mode 100644 index 000000000..f820aa5c6 --- /dev/null +++ b/private/ntos/ndis/elnk3/keywords.h @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + keywords.h + +Abstract: + + Contains all Ndis2 and Ndis3 mac-specific keywords. + +Author: + + Bob Noradki + +Environment: + + This driver is expected to work in DOS, OS2 and NT at the equivalent + of kernal mode. + + Architecturally, there is an assumption in this driver that we are + on a little endian machine. + +Notes: + + optional-notes + +Revision History: + + + +--*/ +#ifndef NDIS2 +#define NDIS2 0 +#endif + +#if NDIS2 + +#define IOADDRESS NDIS_STRING_CONST("IOBASE") +#define INTERRUPT NDIS_STRING_CONST("INTERRUPT") +#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MAXMULTICAST") +#define NETWORK_ADDRESS NDIS_STRING_CONST("NETADDRESS") +#define BUS_TYPE NDIS_STRING_CONST("BusType") +#define TRANSCEIVER NDIS_STRING_CONST("Transceiver") + +#else // NDIS3 + +#define IOADDRESS NDIS_STRING_CONST("IoBaseAddress") +#define INTERRUPT NDIS_STRING_CONST("InterruptNumber") +#define MAX_MULTICAST_LIST NDIS_STRING_CONST("MaximumMulticastList") +#define NETWORK_ADDRESS NDIS_STRING_CONST("NetworkAddress") +#define BUS_TYPE NDIS_STRING_CONST("BusType") +#define TRANSCEIVER NDIS_STRING_CONST("Transceiver") + +#endif diff --git a/private/ntos/ndis/elnk3/makefile b/private/ntos/ndis/elnk3/makefile new file mode 100644 index 000000000..677d610db --- /dev/null +++ b/private/ntos/ndis/elnk3/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/elnk3/receive.c b/private/ntos/ndis/elnk3/receive.c new file mode 100644 index 000000000..2acd4d6a9 --- /dev/null +++ b/private/ntos/ndis/elnk3/receive.c @@ -0,0 +1,1722 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + receive.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + + FYI: The ELNK III behaves maginally if it is overflowing. + + A note to the curious: + + This module supports two different methods of handling received frames. + + Method 0: the default method, basically tries to keep the stinking 2k + receive fifo as empty as possible. In order to do this, it needs to + port i/o the data into system memory and then copy from this system + memory to packets during transferdata. Obviously it would be best to + not have this memory copy. + + Method 1: tries to avoid the memory copy by port i/o'ing straigth + into the packet buffers during transfer data. The problem with method + is that by the time you indicate the frame up, their is going to be + about 1300 bytes sitting in fifo from this packet. This obviously + means that if the total latency to transfer data port i/o'ing is + more than ~700 byte times, you are going to under run the next packet. + The more protocol's bound, the more delay. + + Method zero is the best at avoiding underruns, but you pay a price in + the extra memory copy. An offsetting factor in addition to the fewer + overruns is that it appears that pending transferdata and later completing + it adds a fair amount of overhead to the code path. + + Another interesting thing is that on MP machines the speed that you + can port i/o is signifigantly reduced do to contention for the bus + from the other processor(s). This increases the danger of overflowing. + Also, depending on how RISC platforms, deal with ISA boards and ports, + I think there is also a risk here of slower port i/o'ing. + + As long as DPC latencies are fairly low and constant, either method will + work OK. The problem occures when the DPC latency increases. Like up around + a millisecond. In looking at this occurance it looks like the DPC is getting + stuck behind the HD DPC. If you get an 1ms latency you are almost assured of + overflowing if you are receiving full size frames back to back. + + + Bascially I believe that method 0 is the most solid and likely to + work on varied platforms. + + If only 3Com had not been so cheap and had put another 2k in the fifo. + + You should also take note that the asic on the isa and EISA cards have + a problem with loosing there place in the fifo. This is delt with in the + packet discard code. It also seems the these boards will also falsly detect + an adapter failure on the receive side. + + Also, according to the 3com specs it is not possible for the card to + have both the packet incomplete bit set and receive error bit set + at the same time, but I have seen this happen. I suspect that this + is related to the above asic problem + + Another neat feature of the card is that when it is overflowing it + has a tendancy to concatenate frames together to form really large + frames. When the frame completes it is marked with an error in the + receive status. + + + + + +Author: + + Brian Lieuallen (BrianLie) 12/14/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + +#include <ndis.h> +//#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + + +VOID +Elnk3DiscardIfBroadcast( + IN PELNK3_ADAPTER pAdapter, + IN PTRANSFERDATA_CONTEXT TransDataContext + ); + + + + +BOOLEAN +Elnk3QuickPacketTest( + IN PNIC_RCV_HEADER Frame, + IN UINT NdisFilter + ); + + + +ULONG +Elnk3GuessFrameSize( + IN PNIC_RCV_HEADER Frame, + IN ULONG BytesNow + ); + + +BOOLEAN +Elnk3IndicateLoopbackPacket( + IN PELNK3_ADAPTER pAdapter, + IN PNDIS_PACKET Packet + ); + + + +VOID +Elnk3TransferDataCompletion( + PTRANSFERDATA_CONTEXT TransDataContext + ); + + +VOID +Elnk3DiscardPacketSync( + IN PTRANSFERDATA_CONTEXT TransDataContext + ); + +BOOLEAN +Elnk3CheckFifoSync( + IN PTRANSFERDATA_CONTEXT TransDataContext + ); + + + + +BOOLEAN +Elnk3IndicatePackets2( + PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + This routine Indicates all of the packets in the ring one at a time + + Arguments: + + + Return Value: + +--*/ + +{ + + USHORT RcvStatus; + ULONG AdditionalData; + ULONG GoodReceives=0; + ULONG BadReceives=0; + + BOOLEAN Indicated=FALSE; + + UINT CurrentPacket; + UINT NextPacket; + USHORT InterruptReason; + ULONG PossibleLength; + + + PTRANSFERDATA_CONTEXT TransDataContext; + PTRANSFERDATA_CONTEXT AltTransDataContext; + + + CurrentPacket=pAdapter->CurrentPacket; + + TransDataContext= &pAdapter->TransContext[CurrentPacket]; + + if ((TransDataContext->BytesAlreadyRead == 0) && pAdapter->RejectBroadcast) { + // + // First interrupt for this packet + // + Elnk3DiscardIfBroadcast( + pAdapter, + TransDataContext + ); + } + + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + IF_LOG(0xdc,0xdc,TransDataContext->BytesAlreadyRead); + + IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets RX status=%04x\n",RcvStatus);) + + while ((BYTES_IN_FIFO(RcvStatus) > pAdapter->LowWaterMark ) || + !(RcvStatus & RX_STATUS_INCOMPLETE)) { + + // + // There is a completed packet or some data from a yet to be completed + // packet + // + if (ELNK3_PACKET_COMPLETE(RcvStatus) || (RcvStatus & RX_STATUS_ERROR)) { + // + // The packet has completed + // + if (!(RcvStatus & RX_STATUS_ERROR)) { + + // + // The packet completed with out error + // + + // + // Get the total packet length by adding the number of bytes still + // in the fifo to the number already taken out + // + TransDataContext->PacketLength=BYTES_IN_FIFO(RcvStatus); + + TransDataContext->PacketLength+=TransDataContext->BytesAlreadyRead; + + IF_LOG(0xdc,0x01,TransDataContext->PacketLength); + + // + // Have we read all of the packet in already? + // + if (TransDataContext->PacketLength <= 1514) { + // + // It is a valid length + // + if (TransDataContext->PacketLength > TransDataContext->BytesAlreadyRead) { + // + // No, Need this much more + // The data in the fifo is padded to a dword boundary + // + AdditionalData=ELNK3_ROUND_TO_DWORD(TransDataContext->PacketLength)-TransDataContext->BytesAlreadyRead; + + IF_LOG(0xad,0x01,AdditionalData); + + // + // Go and get the rest + // + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)(((PUCHAR)TransDataContext->LookAhead)+TransDataContext->BytesAlreadyRead), + (AdditionalData>>2) + ); + + IF_RCV_LOUD(DbgPrint("IP: Da=%d Ad=%d\n",TransDataContext->BytesAlreadyRead, AdditionalData);) + + // + // Now we have this much + // + TransDataContext->BytesAlreadyRead+=AdditionalData; + + } + } + + // + // Now discard the packet before indicating + // + + Elnk3DiscardPacketSync(TransDataContext); + + pAdapter->FramesRcvGood+=1; + + + // + // See if any data from the next packet is in the fifo + // + // If there is any data then it will go in the other unused buffer + // + NextPacket=(CurrentPacket+1) % 2; + + AltTransDataContext= &pAdapter->TransContext[NextPacket]; + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + AdditionalData=BYTES_IN_FIFO_DW(RcvStatus); + + + // + // Go and get the data + // + while ((AdditionalData >= (pAdapter->LowWaterMark*2)) + && + (AdditionalData+AltTransDataContext->BytesAlreadyRead<=1514) + && + !(RcvStatus & RX_STATUS_ERROR)) { + + + IF_LOG(0xaf,0x00,RcvStatus & 0xc7fc); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)AltTransDataContext->LookAhead+AltTransDataContext->BytesAlreadyRead), + (AdditionalData >> 2) + ); + + AltTransDataContext->BytesAlreadyRead += AdditionalData; + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + AdditionalData=BYTES_IN_FIFO_DW(RcvStatus); + + } + + + // + // It seems that some asic's will generate an adapter failure + // when there really isn't one. Just to be safe we will check + // now. Since we have port i/o the whole packet now we will + // check. Better to not indicate a bad packet than to loose a + // good one + // + InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + if ((TransDataContext->PacketLength <=1514) + && + (TransDataContext->PacketLength >= 14) + && + !(InterruptReason & EC_INT_ADAPTER_FAILURE)) { + + // + // The packet seems to be OK + // Subtract the header length(14) from the packet length + // + TransDataContext->PacketLength-=ELNK3_ETHERNET_HEADER_SIZE; + + GoodReceives++; + + NdisMEthIndicateReceive( + pAdapter->NdisAdapterHandle, + TransDataContext, + (PUCHAR)&TransDataContext->LookAhead->EthHeader, + ELNK3_ETHERNET_HEADER_SIZE, + TransDataContext->LookAhead->LookAheadData, + TransDataContext->PacketLength, + TransDataContext->PacketLength + ); + + DEBUG_STAT(pAdapter->Stats.PacketIndicated); + + Indicated=TRUE; + + } else { + + IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePacket: bad size or adapter failed -> not idicated\n");) + + } + + } else { + // + // The packet completed with some sort of error, just + // discard it + // + + IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets: error %04x\n", RcvStatus & 0xf800);) + IF_LOG(0xff,0xff,RcvStatus & 0xf800); + + Elnk3DiscardPacketSync(TransDataContext); + + pAdapter->MissedPackets++; + + + // + // This will be the next packet that we are using + // + NextPacket=(CurrentPacket+1) % 2; + + AltTransDataContext= &pAdapter->TransContext[NextPacket]; + + DEBUG_STAT(pAdapter->Stats.BadReceives); + + } // if (!(RcvStatus & RX_STATUS_ERROR)) + + // + // Re-initialize the info for this buffer + // + TransDataContext->BytesAlreadyRead=0; +// TransDataContext->PacketLength=0; + + + // + // Switch buffers now. The one we are switching to may already + // have data in it from above. + // +// pAdapter->CurrentPacket=NextPacket; + CurrentPacket=NextPacket; + + // + // Update the pointer + // + + TransDataContext=AltTransDataContext; + + + } // if (packet complete) + + // + // The packet in the fifo is not complete yet. + // If there is enough data in the fifo copy it out now + // to reduce the chance of overflow + // + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + if ((BYTES_IN_FIFO_DW(RcvStatus) >= pAdapter->LowWaterMark) + && + (BYTES_IN_FIFO_DW(RcvStatus)+TransDataContext->BytesAlreadyRead<=1514) + && + ((RcvStatus & RX_STATUS_INCOMPLETE)) + && + !(RcvStatus & RX_STATUS_ERROR)) { + + IF_LOG(0xdc,0xea,(RcvStatus & 0xc7fc)); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead), + ((RcvStatus & 0x7fc) >> 2) + ); + + TransDataContext->BytesAlreadyRead += BYTES_IN_FIFO_DW(RcvStatus); + + } + + + + + // + // if the receiver should happen to fail we might + // not ever exit this loop. The receiver should + // only fail if we read past our packet in the + // fifo + // + + InterruptReason=ELNK3_READ_PORT_USHORT(pAdapter,PORT_CmdStatus); + + if (InterruptReason & EC_INT_ADAPTER_FAILURE) { + + IF_LOUD( + DbgPrint("Elnk3: Adapter failed\n"); + DbgBreakPoint(); + ) + + break; + } + + // + // get a new receive for the logic up top + // + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + + } // While (!complete and > 64 bytes in fifo + + + + + + // + // Figure out where to set the early receive threshold depending + // how much of the packet we have so far + // + + if (TransDataContext->BytesAlreadyRead > 16) { + + PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead, + TransDataContext->BytesAlreadyRead); + + IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);) + + if (PossibleLength > pAdapter->LatencyAdjustment) { + // + // There is enough time to set the threshold before + // the packet passes the new threshold + // + + IF_LOG(0xef,0x02,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff); + ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7fc); + + } + + + } else { + // + // Set rx early to catch the front of the packet + // + IF_LOG(0xef,0x03,(pAdapter->LookAheadLatencyAdjustment)); + ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, (pAdapter->LookAheadLatencyAdjustment) ); + } + + // + // save this so we know where we are + // + pAdapter->CurrentPacket=CurrentPacket; + + if (Indicated) { + + DEBUG_STAT(pAdapter->Stats.IndicationCompleted); + + + NdisMEthIndicateReceiveComplete(pAdapter->NdisAdapterHandle); + } + +#if DBG + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + IF_LOG(0xdc,0xdd,RcvStatus & 0xc7ff); +#endif + + return TRUE; +} + + + + + + + + + + +VOID +Elnk3DiscardPacketSync( + IN PTRANSFERDATA_CONTEXT TransDataContext + ) +/*++ + +Routine Description: + + Discard tap packet in receive fifo + +Arguments: + + +Notes: + + We do this as a sync with interrupt routine because the discard + command does not complete with in the time it takes the I/O command + to complete. Since another command cannot be issued during the time + that one is in progress we must do this to protect our selves against + the mask command issued in the ISR. + +--*/ + +{ + + PELNK3_ADAPTER pAdapter=TransDataContext->pAdapter; + ULONG RcvStatus; + ULONG Sum; + ULONG FreeBytes; + + + ELNK3_COMMAND(pAdapter, EC_RX_DISCARD_TOP_PACKET, 0); + + // + // An interesting thing to do at raised IRQL. + // Unfortuanly I don't really see an alternative + // The wait appears to be very short any way + // + ELNK3_WAIT_NOT_BUSY(pAdapter); + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + if (RcvStatus & RX_STATUS_INCOMPLETE) { + // + // If the status is incomplete then we need to check + // to make sure that the fifo is not fucked up with a + // packet lost in it. To find out we read the + // the number of free bytes out of page 3 and add + // the number of bytes received from the RX status. + // If this value isn't with in 100 of the total + // fifo size then we conclude that is screwed up + // and we reset the receiver + // + + ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO); + + FreeBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_FREE_RX_BYTES); + + ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING); + + + Sum=(BYTES_IN_FIFO(RcvStatus) + FreeBytes); + + if ((Sum + 90 < pAdapter->RxFifoSize) + || + ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0))) { + + BOOLEAN FifoBad; + + IF_LOG(0xde,0xad,0xffff); + + IF_RCV_LOUD(DbgPrint("ELNK3: RX fifo problem used=%d free=%d size=%d\n",RcvStatus & 0x7ff,FreeBytes, pAdapter->RxFifoSize);) + + // + // Looks like the fifo is messed up, try it again + // syncronized with interrupts + // + FifoBad=NdisMSynchronizeWithInterrupt( + &pAdapter->NdisInterrupt, + Elnk3CheckFifoSync, + TransDataContext + ); + + if (FifoBad) { + // + // It's fucked up. Reset the receiver + // + ELNK3_COMMAND(pAdapter,EC_RX_RESET,0); + + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_RX_ENABLE,0); + + ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, pAdapter->RxFilter); + } + } + } +} + + +BOOLEAN +Elnk3CheckFifoSync( + IN PTRANSFERDATA_CONTEXT TransDataContext + ) +/*++ + +Routine Description: + + Check the fifo's state to try to determine if a packet + is lost in it. We do this syncronized with interrupts + to reduce the chance of interrupt occuring between the + port reads. + +Arguments: + + +Notes: + + +--*/ + +{ + + PELNK3_ADAPTER pAdapter=TransDataContext->pAdapter; + ULONG RcvStatus; + ULONG Sum; + ULONG FreeBytes; + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + if (!(RcvStatus & RX_STATUS_INCOMPLETE)) { + // + // It's completed now + // + return FALSE; + } + + ELNK3_SELECT_WINDOW(pAdapter,WNO_FIFO); + + FreeBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_FREE_RX_BYTES); + + ELNK3_SELECT_WINDOW(pAdapter,WNO_OPERATING); + + Sum=(BYTES_IN_FIFO(RcvStatus) + FreeBytes); + +#if DBG + if ((Sum + 90 < pAdapter->RxFifoSize) + || + ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0))) { + + IF_LOUD(DbgPrint("ELNK3: RX fifo problem used=%d free=%d size=%d\n",RcvStatus & 0x7ff,FreeBytes, pAdapter->RxFifoSize);) + } +#endif + + return ((Sum + 90 < pAdapter->RxFifoSize) + || + ((pAdapter->RxFifoSize==FreeBytes) && (BYTES_IN_FIFO(RcvStatus)!=0))); + + + + +} + + +NDIS_STATUS +Elnk3TransferData( + OUT PNDIS_PACKET Packet, + OUT PUINT BytesTransferred, + IN NDIS_HANDLE MacBindingHandle, + IN NDIS_HANDLE MacReceiveContext, + IN UINT ByteOffset, + IN UINT BytesToTransfer + ) + +/*++ + +Routine Description: + + NDIS function. + +Arguments: + + see NDIS 3.0 spec. + +Notes: + + The receive context is a pointer to a structure that describes the packet + +--*/ + +{ + UINT BytesLeft, BytesNow, BytesWanted; + PNDIS_BUFFER CurBuffer; + PUCHAR BufStart; + UINT BufLen; + ULONG DataAvailible; + + PUCHAR pBuffer; + + + PTRANSFERDATA_CONTEXT TransDataContext= ((PTRANSFERDATA_CONTEXT)MacReceiveContext); + PELNK3_ADAPTER pAdapter = MacBindingHandle; + + + + IF_LOG(0xDD,0xdd,TransDataContext->PacketLength); + + IF_RCV_LOUD(DbgPrint("Elnk3: Transferdata: bo=%d bt=%d\n",ByteOffset, BytesToTransfer);) + + DEBUG_STAT(pAdapter->Stats.TransferDataCount); + + + + if (ByteOffset+BytesToTransfer > TransDataContext->PacketLength) { + // + // Adjust the amount of data the protocol wants + // + + IF_LOUD(DbgPrint("Elnk3: TD() Protocol asked for too much data bo=%d btt=%d pl=%d Da=%d\n", + ByteOffset, + BytesToTransfer, + TransDataContext->PacketLength + );) + + if (TransDataContext->PacketLength > ByteOffset) { + + BytesToTransfer = TransDataContext->PacketLength - ByteOffset; + + } else { + // + // the offset is past the packet length, bad protocol bad + // + *BytesTransferred = 0; + + return NDIS_STATUS_SUCCESS; + + } + } + + DataAvailible=TransDataContext->BytesAlreadyRead; + + if (DataAvailible < (TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)) { + // + // We haven't read all of the data out of the fifo yet, so + // let our transfer data completetion handler do it + // + // See how much data there is to transfer. + // + + PACKET_RESERVED(Packet)->u.TransData.ByteOffset = ByteOffset; + PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer = BytesToTransfer; + + PACKET_RESERVED(Packet)->Next=TransDataContext->Stack; + + TransDataContext->Stack=Packet; + + return NDIS_STATUS_PENDING; + + } + + // + // The whole packet fit in the lookahead data, so copy it out + // right now + // + + + + + BytesWanted = BytesToTransfer; + + IF_RCV_LOUD(DbgPrint("TD: bo=%d bt=%d ps=%d\n",ByteOffset, BytesToTransfer, TransDataContext->PacketLength);) + + + + BytesLeft = BytesWanted; + + // + // Get a pointer to the begining of the data to be copied. + // The 14 byte header is handled by lookahead element + // + pBuffer=TransDataContext->LookAhead->LookAheadData+ByteOffset; + + NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL); + + if (BytesLeft > 0) { + + while (1) { + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufStart, &BufLen); + + // + // See how much data to read into this buffer. + // + + BytesNow= BufLen < BytesLeft ? BufLen : BytesLeft; + + NdisMoveMemory( + BufStart, + pBuffer, + BytesNow + ); + + + pBuffer += BytesNow; + + BytesLeft -= BytesNow; + + + // + // Is the transfer done now? + // + + if (BytesLeft == 0) { + + break; + } + + NdisGetNextBuffer(CurBuffer, &CurBuffer); + + if (CurBuffer == (PNDIS_BUFFER)NULL) { + + break; + } + } + } + + *BytesTransferred = BytesWanted - BytesLeft; + + return NDIS_STATUS_SUCCESS; + +} + + + + + + +BOOLEAN +Elnk3EarlyReceive( + PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + This routine Indicates all of the packets in the ring one at a time + + Arguments: + + + Return Value: + +--*/ + +{ + + ULONG PacketLength; + USHORT RcvStatus; + ULONG DataAvailible; + UINT PossibleLength; + + + PTRANSFERDATA_CONTEXT TransDataContext= &pAdapter->TransContext[0]; + + + DataAvailible=TransDataContext->BytesAlreadyRead; + + + if (DataAvailible == 0) { + + // + // First early receive get the lookahead and set the second early receive + // + // With any luck the packet will complete and the packet complete + // interrupt will mask the this early receive thus reducing the effective + // delay in processing the interrupt + // + // If not then this routine will run again and kill some time reading + // in data from the card. This should happen to often and when it + // does we should not have missed by much. The data that we do copy + // will most likely be used any way so not much will be lost. + // + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + PacketLength=BYTES_IN_FIFO_DW(RcvStatus); + + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+DataAvailible), + (PacketLength >> 2) + ); + + TransDataContext->BytesAlreadyRead += PacketLength; + + + + IF_LOG(0xee,0x01,PacketLength); + + + PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead, + TransDataContext->BytesAlreadyRead); + + + IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);) + + + + if (PossibleLength-pAdapter->RxMinimumThreshold > (UINT)pAdapter->LatencyAdjustment) { + + ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff); + IF_LOG(0xef,0x01,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff); + } + + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + if (!(RcvStatus & RX_STATUS_INCOMPLETE)) { + // + // The packet completed while we were reading it in + // + Elnk3IndicatePackets(pAdapter); + } + + } else { + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + IF_LOG(0xee,0x02,BYTES_IN_FIFO(RcvStatus)); + + // + // Second early receive, Copy data until it completes + // and then call indicatepackets + // + while ((RcvStatus & RX_STATUS_INCOMPLETE) && !(RcvStatus & RX_STATUS_ERROR)) { + + IF_LOG(0xee,0x03,RcvStatus & 0xc7fc); + + if (BYTES_IN_FIFO_DW(RcvStatus) >= 32) { + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead), + 32 >> 2 + ); + + TransDataContext->BytesAlreadyRead += 32; + } + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + } + + Elnk3IndicatePackets(pAdapter); + + + DEBUG_STAT(pAdapter->Stats.SecondEarlyReceive); + } + + return TRUE; + +} + + +BOOLEAN +Elnk3IndicatePackets( + PELNK3_ADAPTER pAdapter + ) +/*++ + + Routine Description: + This routine Indicates all of the packets in the ring one at a time + + Arguments: + + + Return Value: + +--*/ + +{ + + ULONG LookAheadSize; + USHORT RcvStatus; + ULONG DataAvailible; + ULONG AdditionalData; + ULONG GoodReceives=0; + ULONG BadReceives=0; + ULONG PossibleLength; + + + + PTRANSFERDATA_CONTEXT TransDataContext= &pAdapter->TransContext[0]; + + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + IF_LOG(0xdc,0xdc,RcvStatus & 0xc7ff); + + IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets RX status=%04x\n",RcvStatus);) + + + do { + + while (!(RcvStatus & RX_STATUS_INCOMPLETE)) { + + if (!(RcvStatus & RX_STATUS_ERROR)) { + + TransDataContext->PacketLength=BYTES_IN_FIFO(RcvStatus); + + DataAvailible=TransDataContext->BytesAlreadyRead; + + TransDataContext->PacketLength+=DataAvailible; + + IF_LOG(0xdc,0x01,TransDataContext->PacketLength); + + if ((TransDataContext->PacketLength<=1514) && + (TransDataContext->PacketLength >= 14)) { + + // + // The packet seems to be OK + // Subtract the header length(14) from the packet length + // + + TransDataContext->PacketLength-=ELNK3_ETHERNET_HEADER_SIZE; + + // + // Lookahead is the smaller of Packetsize and the current lookahead size + // + LookAheadSize=TransDataContext->PacketLength < pAdapter->MaxLookAhead ? + TransDataContext->PacketLength : pAdapter->MaxLookAhead; + + + if (LookAheadSize+ELNK3_ETHERNET_HEADER_SIZE > DataAvailible) { + // + // We did not get an early receive for this packet. + // Most likly it is a small packet that is less than our threshold. + // Or the latency is too great + // + AdditionalData=ELNK3_ROUND_TO_DWORD(LookAheadSize+ELNK3_ETHERNET_HEADER_SIZE)-DataAvailible; + + IF_LOG(0xad,0x01,AdditionalData); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)(((PUCHAR)TransDataContext->LookAhead)+DataAvailible), + (AdditionalData>>2) + ); + + IF_RCV_LOUD(DbgPrint("Elnk3: Indicate: Da=%d Ad=%d\n",DataAvailible, AdditionalData);) + + TransDataContext->BytesAlreadyRead+=AdditionalData; + + } else { + // + // The lookahead data is waiting for us, so just go ahead and indicate. + // + DEBUG_STAT(pAdapter->Stats.IndicateWithDataReady); + + } + + + GoodReceives++; + + IF_RCV_LOUD(DbgPrint("Elnk3: Indicate: ls=%d pl=%d\n", LookAheadSize, TransDataContext->PacketLength);) + + TransDataContext->Stack=NULL; + + NdisMEthIndicateReceive( + pAdapter->NdisAdapterHandle, + TransDataContext, + (PUCHAR)&TransDataContext->LookAhead->EthHeader, + ELNK3_ETHERNET_HEADER_SIZE, + TransDataContext->LookAhead->LookAheadData, + LookAheadSize, + TransDataContext->PacketLength + ); + + DEBUG_STAT(pAdapter->Stats.PacketIndicated); + + if (TransDataContext->Stack!=NULL) { + // + // at least one protocol called transferdata + // + Elnk3TransferDataCompletion( + TransDataContext + ); + + } + + + + } else { + + IF_RCV_LOUD(DbgPrint("ELNK3: (Packet>1514) || (error in packet) -> not idicated\n");) + + } + + } else { + + IF_RCV_LOUD(DbgPrint("ELNK3: IndicatePackets: error %04x\n", RcvStatus & 0xf800);) + IF_LOG(0xff,0xff,0xffff); + + DEBUG_STAT(pAdapter->Stats.BadReceives); + + } + + Elnk3DiscardPacketSync(TransDataContext); + + pAdapter->FramesRcvGood+=GoodReceives; + + + TransDataContext->BytesAlreadyRead=0; + + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + } // while complete + + + DEBUG_STAT(pAdapter->Stats.IndicationCompleted); + + NdisMEthIndicateReceiveComplete(pAdapter->NdisAdapterHandle); + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + // + // See if there is a lookahead's worth of data from the next yet + // + if ( BYTES_IN_FIFO_DW(RcvStatus) > pAdapter->EarlyReceiveThreshold) { + + if ( BYTES_IN_FIFO_DW(RcvStatus) > 1200 && (RcvStatus & RX_STATUS_INCOMPLETE)) { + // + // There is alot of data in the fifo, but the packet has not completed yet. + // In order to try to prevent an over flow, lets empty now + // + IF_LOG(0xdc,0xeb,RcvStatus & 0xc7fc); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead), + BYTES_IN_FIFO_DW(RcvStatus) >> 2 + ); + + TransDataContext->BytesAlreadyRead += BYTES_IN_FIFO_DW(RcvStatus); + + } else { + + IF_LOG(0xdc,0xea,RcvStatus & 0xc7fc); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead), + pAdapter->EarlyReceiveThreshold >> 2 + ); + + TransDataContext->BytesAlreadyRead += pAdapter->EarlyReceiveThreshold; + } + + } + + // + // In the time it took to port i/o in the lookahead data the packet may + // have completed + // + + } while (!(RcvStatus & RX_STATUS_INCOMPLETE)); + + + + // + // At this point there is either 0 or EarlyReceiveThreshold bytes in the buffer + // + + if (TransDataContext->BytesAlreadyRead > 16) { + + PossibleLength=Elnk3GuessFrameSize(TransDataContext->LookAhead, + TransDataContext->BytesAlreadyRead); + + IF_RCV_LOUD(DbgPrint("Elnk3: Possible length is %d\n",PossibleLength);) + + if (PossibleLength > pAdapter->LatencyAdjustment) { + // + // There is enough time to set the threshold before + // the packet passes the new threshold + // + + IF_LOG(0xef,0x02,((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7ff); + ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, ((PossibleLength)-pAdapter->LatencyAdjustment) & 0x7fc); + + } + + + } else { + // + // Set rx early to catch the front of the packet + // + IF_LOG(0xef,0x02,(pAdapter->LookAheadLatencyAdjustment)); + ELNK3_COMMAND(pAdapter,EC_SET_RX_EARLY, (pAdapter->LookAheadLatencyAdjustment) ); + } + + + + +#if DBG + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + IF_LOG(0xdc,0xdd,RcvStatus & 0xc7ff); +#endif + + + return TRUE; +} + + + + + + +ULONG +Elnk3GuessFrameSize( + IN PNIC_RCV_HEADER Frame, + IN ULONG BytesNow + ) +/*++ + + Routine Description: + + This rountine endevers to determine the size of the packet + from the packet header. + + This scheme was borrowed from 3com's ndis 2 driver + + Arguments: + + + Return Value: + +--*/ + +{ + + ULONG PossibleLength; + + + PossibleLength=(Frame->EthHeader.EthLength[0]<<8)+ + Frame->EthHeader.EthLength[1]; + + + // + // Is it 802.3 + // + if (PossibleLength < 0x600 ) { + // + // Looks to an 802.3 frame + // + return (PossibleLength+14); + } + + // + // Xns, IP, IPX ? + // + + if (PossibleLength==XNS_FRAME_TYPE || + PossibleLength==IP_FRAME_TYPE || + PossibleLength==IPX_FRAME_TYPE ) { + + PossibleLength=(Frame->LookAheadData[2]<<8)+ + Frame->LookAheadData[3]+14; + + } else { + // + // Not one we recognise + // + return 1514; + } + + + if (PossibleLength<=1514 && PossibleLength>=BytesNow) { + // + // Looks reasonable + // + return PossibleLength; + + } else { + // + // Don't look like we got the length, just go with max + // + return 1514; + } + + +} + + + +VOID +Elnk3DiscardIfBroadcast( + IN PELNK3_ADAPTER pAdapter, + IN PTRANSFERDATA_CONTEXT TransDataContext + ) + +{ + USHORT RcvStatus; + + + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + while (BYTES_IN_FIFO_DW(RcvStatus) > 8) { + + IF_LOG(0xaf,0xff,BYTES_IN_FIFO_DW(RcvStatus)); + +#if DBG + if (TransDataContext->BytesAlreadyRead != 0) { + DbgPrint("Elnk3: FindNextPacket called with BytesAlreadyRead != 0\n"); + DbgBreakPoint(); + } +#endif + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead), + (8 >> 2) + ); + + TransDataContext->BytesAlreadyRead = 8; + + if (ETH_IS_BROADCAST(&TransDataContext->LookAhead->EthHeader.Destination[0])) { + + // + // We don't want this one so, we discard it now + // + + Elnk3DiscardPacketSync(TransDataContext); + + + DEBUG_STAT(pAdapter->Stats.BroadcastsRejected); + + + // + // No bytes anymore + // + TransDataContext->BytesAlreadyRead = 0; + + // + // we chucked it, see what the next one holds in store for us + // + RcvStatus=ELNK3_READ_PORT_USHORT(pAdapter,PORT_RxStatus); + + continue; + + } + + + // + // We need to indicate it + // + + break; + + } +} + + + + + +VOID +Elnk3TransferDataCompletion( + PTRANSFERDATA_CONTEXT TransDataContext + ) + +{ + + PELNK3_ADAPTER pAdapter; + PNDIS_PACKET Packet; + PNDIS_BUFFER CurBuffer; + PUCHAR BufferAddress; + ULONG BufferLength; + ULONG DataAvailible; + ULONG OffsetInLookAhead; + ULONG BytesLeft; + ULONG BytesNow; + ULONG ByteOffset; + ULONG BytesToTransfer; + ULONG AdditionalData; + + + + pAdapter=TransDataContext->pAdapter; + // + // See if more than one binding called transferdata + // + if (PACKET_RESERVED(TransDataContext->Stack)->Next==NULL) { + // + // just one, just port io into the ndis buffer + // + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: One transferdata call\n");) + + Packet=TransDataContext->Stack; + + + // + // See just what this protocol wants + // + BytesToTransfer = PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer; + + ByteOffset = PACKET_RESERVED(Packet)->u.TransData.ByteOffset; + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bo=%d bt=%d\n",ByteOffset,BytesToTransfer);) + + + + + BytesLeft=BytesToTransfer; + + OffsetInLookAhead=ByteOffset+ELNK3_ETHERNET_HEADER_SIZE; + + NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL); + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength); + + DataAvailible=TransDataContext->BytesAlreadyRead; + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: DataAvailible=%d offset=%d\n",DataAvailible,OffsetInLookAhead);) + + // + // copy the data out of the lookahead buffer + // + // Note, that this loop assumes that whole packet does not fit + // in the lookahead data. If it does TransferData does not pend + // and this routine is not called. This is a problem because + // we read data out of the fifo in multiples of dwords and we + // get padding bytes in our data availible count + // + + if (OffsetInLookAhead > DataAvailible) { + // + // The byte offset is past the lookahead data. + // We need to port some more stuff out of the fifo + // to get to where the data is that we want + // + + NdisRawReadPortBufferUchar( + pAdapter->PortOffsets[PORT_RxFIFO], + (PUCHAR)((PUCHAR)TransDataContext->LookAhead+TransDataContext->BytesAlreadyRead), + OffsetInLookAhead - DataAvailible + ); + + TransDataContext->BytesAlreadyRead+=(OffsetInLookAhead - DataAvailible); + + } else { + // + // the byteoffset is with in the lookahead data + // copy it to the ndis buffer + // + + + while (OffsetInLookAhead < DataAvailible) { + // + // Need to copy some of lookeahead into protocol packet + // + + BytesNow= BufferLength < (DataAvailible-OffsetInLookAhead) ? + BufferLength : (DataAvailible-OffsetInLookAhead); + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: lookahead bn=%d offset=%d\n",BytesNow,OffsetInLookAhead);) + + + NdisMoveMemory( + BufferAddress, + (PUCHAR)TransDataContext->LookAhead+OffsetInLookAhead, + BytesNow + ); + + BytesLeft-=BytesNow; + + OffsetInLookAhead+=BytesNow; + + BufferAddress+=BytesNow; + + BufferLength-=BytesNow; + + if (BufferLength==0) { + + NdisGetNextBuffer(CurBuffer, &CurBuffer); + + if (CurBuffer==NULL) { + + break; + } + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength); + } + + } + } + + // + // port i/o in the rest of the packet into the protocols packet + // + + while (BytesLeft > 0) { + + BytesNow= BufferLength < BytesLeft ? + BufferLength : BytesLeft; + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bl=%d bn=%d\n",BytesLeft,BytesNow);) + IF_LOG(0xad,0xd1,BytesNow); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)BufferAddress, + BytesNow>>2 + ); + + if (BytesNow & 3) { + + NdisRawReadPortBufferUchar( + pAdapter->PortOffsets[PORT_RxFIFO], + (PUCHAR)((PUCHAR)BufferAddress+(BytesNow & 0xfffffffc)), + BytesNow & 3 + ); + } + + BytesLeft-=BytesNow; + + NdisGetNextBuffer(CurBuffer, &CurBuffer); + + if (CurBuffer == NULL) { + + break; + } + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength); + + } + + + NdisMTransferDataComplete( + pAdapter->NdisAdapterHandle, + Packet, + NDIS_STATUS_SUCCESS, + BytesToTransfer + ); + + + + + return ; + } + + + // + // More than one protocol wants the packet. + // We will port i/o the whole thing to one of our buffers + // and then copy the data into the protocols packets + // + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: Multiple transferdata calls\n");) + + while ((Packet=TransDataContext->Stack) != NULL) { + + TransDataContext->Stack=PACKET_RESERVED(Packet)->Next; + + // + // See just what this protocol wants + // + BytesToTransfer = PACKET_RESERVED(Packet)->u.TransData.BytesToTransfer; + + ByteOffset = PACKET_RESERVED(Packet)->u.TransData.ByteOffset; + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: bo=%d bt=%d\n",ByteOffset,BytesToTransfer);) + + + IF_RCV_LOUD(DbgPrint("TD: bo=%d bt=%d ps=%d\n",ByteOffset, BytesToTransfer, TransDataContext->PacketLength);) + + + // + // We got this much so far + // + DataAvailible=TransDataContext->BytesAlreadyRead; + + + // + // See if the whole thing has been removed from the fifo + // + if (DataAvailible < (TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)) { + // + // Get the rest of the data from the fifo + // + + AdditionalData=ELNK3_ROUND_TO_DWORD((TransDataContext->PacketLength+ELNK3_ETHERNET_HEADER_SIZE)-DataAvailible); + + NdisRawReadPortBufferUlong( + pAdapter->PortOffsets[PORT_RxFIFO], + (PULONG)((PUCHAR)TransDataContext->LookAhead+DataAvailible), + AdditionalData>>2 + ); + + IF_LOG(0xad,0x02,AdditionalData); + + IF_RCV_LOUD(DbgPrint("Elnk3: TransComp: Da=%d Ad=%d\n",DataAvailible, AdditionalData);) + + TransDataContext->BytesAlreadyRead+=AdditionalData; + + } + + + + BytesLeft = BytesToTransfer; + + + OffsetInLookAhead=ByteOffset; + + + NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL); + + while (BytesLeft > 0) { + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &BufferLength); + + // + // See how much data to read into this buffer. + // + + BytesNow= BufferLength < BytesLeft ? BufferLength : BytesLeft; + + // + // Note: the LookAheadData element of the structure handles the + // 14 byte header discrepency + // + NdisMoveMemory( + BufferAddress, + TransDataContext->LookAhead->LookAheadData+OffsetInLookAhead, + BytesNow + ); + + + OffsetInLookAhead += BytesNow; + + BytesLeft -= BytesNow; + + + // + // Is the transfer done now? + // + + if (BytesLeft == 0) { + + break; + } + + NdisGetNextBuffer(CurBuffer, &CurBuffer); + + if (CurBuffer == (PNDIS_BUFFER)NULL) { + + break; + } + + } + + + + NdisMTransferDataComplete( + pAdapter->NdisAdapterHandle, + Packet, + NDIS_STATUS_SUCCESS, + BytesToTransfer + ); + + + + + + } // while packets + + + + + return; + +} diff --git a/private/ntos/ndis/elnk3/request.c b/private/ntos/ndis/elnk3/request.c new file mode 100644 index 000000000..a267b3da9 --- /dev/null +++ b/private/ntos/ndis/elnk3/request.c @@ -0,0 +1,839 @@ +/*++ + +Copyright (c) 1992 Microsoft Corporation + +Module Name: + + request.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + This file handles NdisRequest. The module was for the most part extracted + from the elnkii driver + +Author: + + Brian Lieuallen (BrianLie) 07/02/92 + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + +--*/ + + + + + +#include <ndis.h> +//#include <efilter.h> + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + + + + + + +NDIS_STATUS +Elnk3FilterChangeAction( + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle + ); + + + + + +// +// If you add to this, make sure to add the +// a case in Elnk3FillInGlobalData() and in +// Elnk3QueryGlobalStatistics() if global +// information only or +// Elnk3QueryProtocolStatistics() if it is +// protocol queriable information. +// +STATIC UINT Elnk3GlobalSupportedOids[] = { + OID_GEN_SUPPORTED_LIST, + OID_GEN_HARDWARE_STATUS, + OID_GEN_MEDIA_SUPPORTED, + OID_GEN_MEDIA_IN_USE, + OID_GEN_MAXIMUM_LOOKAHEAD, + OID_GEN_MAXIMUM_FRAME_SIZE, + OID_GEN_MAXIMUM_TOTAL_SIZE, + OID_GEN_MAC_OPTIONS, + OID_GEN_PROTOCOL_OPTIONS, + OID_GEN_LINK_SPEED, + OID_GEN_TRANSMIT_BUFFER_SPACE, + OID_GEN_RECEIVE_BUFFER_SPACE, + OID_GEN_TRANSMIT_BLOCK_SIZE, + OID_GEN_RECEIVE_BLOCK_SIZE, + OID_GEN_VENDOR_ID, + OID_GEN_VENDOR_DESCRIPTION, + OID_GEN_DRIVER_VERSION, + OID_GEN_CURRENT_PACKET_FILTER, + OID_GEN_CURRENT_LOOKAHEAD, + OID_GEN_XMIT_OK, + OID_GEN_RCV_OK, + OID_GEN_XMIT_ERROR, + OID_GEN_RCV_ERROR, + OID_GEN_RCV_NO_BUFFER, + OID_802_3_PERMANENT_ADDRESS, + OID_802_3_CURRENT_ADDRESS, + OID_802_3_MULTICAST_LIST, + OID_802_3_MAXIMUM_LIST_SIZE, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS + }; + + + + + + +NDIS_STATUS +Elnk3QueryInformation( + IN NDIS_HANDLE MiniportContext, + IN NDIS_OID Oid, + IN PVOID InfoBuffer, + IN ULONG BytesLeft, + OUT PULONG BytesWritten, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + The Elnk3QueryProtocolInformation process a Query request for + NDIS_OIDs that are specific to a binding about the MAC. Note that + some of the OIDs that are specific to bindings are also queryable + on a global basis. Rather than recreate this code to handle the + global queries, I use a flag to indicate if this is a query for the + global data or the binding specific data. + +Arguments: + + Adapter - a pointer to the adapter. + + Oid - the NDIS_OID to process. + + PlaceInInfoBuffer - a pointer into the NdisRequest->InformationBuffer + into which store the result of the query. + + BytesLeft - the number of bytes left in the InformationBuffer. + + BytesNeeded - If there is not enough room in the information buffer + then this will contain the number of bytes needed to complete the + request. + + BytesWritten - a pointer to the number of bytes written into the + InformationBuffer. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + NDIS_MEDIUM Medium = NdisMedium802_3; + ULONG GenericULong = 0; + USHORT GenericUShort = 0; + UCHAR GenericArray[6]; + + PELNK3_ADAPTER pAdapter=MiniportContext; + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + // + // Common variables for pointing to result of query + // + + PVOID MoveSource; + ULONG MoveBytes; + + NDIS_HARDWARE_STATUS HardwareStatus = NdisHardwareStatusReady; + + // + // General Algorithm: + // + // Switch(Request) + // Get requested information + // Store results in a common variable. + // Copy result in common variable to result buffer. + // + + // + // Make sure that ulong is 4 bytes. Else GenericULong must change + // to something of size 4. + // + ASSERT(sizeof(ULONG) == 4); + + MoveSource = (PVOID)(&GenericULong); + MoveBytes = sizeof(GenericULong); + + + + IF_REQ_LOUD(DbgPrint("ELNK3: QueryProtocol %08lx\n",Oid);) + + + // + // Switch on request type + // + + switch (Oid) { + + case OID_GEN_MAC_OPTIONS: + + if (pAdapter->ReceiveMethod==1) { + + GenericULong = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_NO_LOOPBACK ; + + } else { + + GenericULong = ( NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | + NDIS_MAC_OPTION_TRANSFERS_NOT_PEND | + NDIS_MAC_OPTION_NO_LOOPBACK); + } + + + break; + + case OID_GEN_SUPPORTED_LIST: + + + MoveSource = (PVOID)(Elnk3GlobalSupportedOids); + MoveBytes = sizeof(Elnk3GlobalSupportedOids); + + break; + + case OID_GEN_HARDWARE_STATUS: + + HardwareStatus = NdisHardwareStatusReady; + + + MoveSource = (PVOID)(&HardwareStatus); + MoveBytes = sizeof(NDIS_HARDWARE_STATUS); + + break; + + case OID_GEN_MEDIA_SUPPORTED: + case OID_GEN_MEDIA_IN_USE: + + MoveSource = (PVOID) (&Medium); + MoveBytes = sizeof(NDIS_MEDIUM); + break; + + case OID_GEN_MAXIMUM_LOOKAHEAD: + + GenericULong = ELNK3_MAX_LOOKAHEAD_SIZE; + + break; + + + case OID_GEN_MAXIMUM_FRAME_SIZE: + + GenericULong = (ULONG)(1514 - 14); + + break; + + + case OID_GEN_MAXIMUM_TOTAL_SIZE: + + GenericULong = (ULONG)(1514); + break; + + + case OID_GEN_LINK_SPEED: + + GenericULong = (ULONG)(100000); + break; + + + case OID_GEN_TRANSMIT_BUFFER_SPACE: + + GenericULong = 2048; + break; + + case OID_GEN_RECEIVE_BUFFER_SPACE: + + GenericULong = 2048; + break; + + case OID_GEN_TRANSMIT_BLOCK_SIZE: + + GenericULong = 1514; + + break; + + case OID_GEN_RECEIVE_BLOCK_SIZE: + + GenericULong = 1514; + break; + + case OID_GEN_VENDOR_ID: + + NdisMoveMemory( + (PVOID)&GenericULong, + pAdapter->PermanentAddress, + 3 + ); + GenericULong &= 0xFFFFFF00; + break; + + case OID_GEN_VENDOR_DESCRIPTION: + + MoveSource = (PVOID)"ELNK3 Ethernet Adapter."; + MoveBytes = 24; + + break; + + case OID_GEN_DRIVER_VERSION: + + GenericUShort = ((USHORT)ELNK3_NDIS_MAJOR_VERSION << 8) | + ELNK3_NDIS_MINOR_VERSION; + + MoveSource = (PVOID)(&GenericUShort); + MoveBytes = sizeof(GenericUShort); + break; + + + + case OID_GEN_CURRENT_LOOKAHEAD: + + + GenericULong = (ULONG)(pAdapter->MaxLookAhead); + + + + IF_REQ_LOUD(DbgPrint("Querying LookAhead: %d\n,GenericULong");) + + break; + + case OID_802_3_PERMANENT_ADDRESS: + + IF_REQ_LOUD(DbgPrint("Querying Permanent address\n");) + + NdisMoveMemory((PCHAR)GenericArray, + pAdapter->PermanentAddress, + ELNK3_LENGTH_OF_ADDRESS); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(pAdapter->PermanentAddress); + break; + + + case OID_802_3_CURRENT_ADDRESS: + + IF_REQ_LOUD(DbgPrint("Querying Current address\n");) + + NdisMoveMemory( + (PCHAR)GenericArray, + pAdapter->StationAddress, + ELNK3_LENGTH_OF_ADDRESS + ); + + MoveSource = (PVOID)(GenericArray); + MoveBytes = sizeof(pAdapter->StationAddress); + break; + + + case OID_802_3_MAXIMUM_LIST_SIZE: + + GenericULong = (ULONG) DEFAULT_MULTICAST_SIZE; + + break; + + case OID_GEN_XMIT_OK: + + GenericULong = pAdapter->FramesXmitGood; + + break; + + case OID_GEN_RCV_OK: + + GenericULong = pAdapter->FramesRcvGood; + + break; + + case OID_GEN_XMIT_ERROR: + + GenericULong = pAdapter->FramesXmitBad; + + break; + + case OID_GEN_RCV_ERROR: + + GenericULong = pAdapter->CrcErrors; + + break; + + case OID_GEN_RCV_NO_BUFFER: + + GenericULong = (UINT)(pAdapter->MissedPackets); + + break; + + case OID_802_3_RCV_ERROR_ALIGNMENT: + + GenericULong = (UINT)pAdapter->FrameAlignmentErrors; + + break; + + case OID_802_3_XMIT_ONE_COLLISION: + + GenericULong = (UINT)pAdapter->FramesXmitOneCollision; + + break; + + case OID_802_3_XMIT_MORE_COLLISIONS: + + GenericULong = (UINT)pAdapter->FramesXmitManyCollisions; + + break; + + + + default: + + StatusToReturn = NDIS_STATUS_NOT_SUPPORTED; + break; + } + + if ((StatusToReturn == NDIS_STATUS_SUCCESS) && + (Oid != OID_802_3_MULTICAST_LIST)) { + + if (MoveBytes > BytesLeft) { + + // + // Not enough room in InformationBuffer. Punt + // + + *BytesNeeded = MoveBytes; + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + } else { + + // + // Store result. + // + + NdisMoveMemory(InfoBuffer, MoveSource, MoveBytes); + + (*BytesWritten) = MoveBytes; + + } + } + + +#if DBG + + if (StatusToReturn != NDIS_STATUS_SUCCESS) { + + IF_REQ_LOUD(DbgPrint("Out QueryInfo oid=%08lx failed\n",Oid);) + } +#endif + + + IF_VERY_LOUD( DbgPrint("Out QueryProtocol\n");) + + return StatusToReturn; + +} + + +NDIS_STATUS +Elnk3SetInformation( + IN NDIS_HANDLE MiniportContext, + IN NDIS_OID Oid, + IN PVOID InfoBuffer, + IN ULONG BytesLeft, + OUT PULONG BytesRead, + OUT PULONG BytesNeeded + ) + +/*++ + +Routine Description: + + The Elnk3SetInformation is used by Elnk3Request to set information + about the MAC. + +Arguments: + + Adapter - A pointer to the adapter. + + Open - A pointer to an open instance. + + NdisRequest - A structure which contains the request type (Set), + an array of operations to perform, and an array for holding + the results of the operations. + +Return Value: + + The function value is the status of the operation. + +--*/ + +{ + + // + // General Algorithm: + // + // Verify length + // Switch(Request) + // Process Request + // + + // + // Variables for a particular request + // + + PELNK3_ADAPTER pAdapter=MiniportContext; + + UINT OidLength; + + // + // Variables for holding the new values to be used. + // + + ULONG LookAhead; + ULONG Filter; + + NDIS_STATUS StatusToReturn = NDIS_STATUS_SUCCESS; + + + IF_REQ_LOUD( DbgPrint("ELNK3: SetInfo %08lx %0d\n",(UINT)Oid,BytesLeft);) + + // + // Get Oid and Length of request + // + + + OidLength = BytesLeft; + + switch (Oid) { + + + case OID_802_3_MULTICAST_LIST: + + // + // Verify length + // + + if ((OidLength % ELNK3_LENGTH_OF_ADDRESS) != 0){ + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + *BytesRead = 0; + *BytesNeeded = 0; + + break; + + } + +#if DBG + { + UINT j; + PUCHAR Address; + + Address=InfoBuffer; + + for (j=0; j<(OidLength / ELNK3_LENGTH_OF_ADDRESS); j++) { + + IF_REQ_LOUD(DbgPrint(" %02x-%02x-%02x-%02x-%02x-%02x\n", + Address[j*6], + Address[j*6+1], + Address[j*6+2], + Address[j*6+3], + Address[j*6+4], + Address[j*6+5]);) + } + } +#endif + + break; + + + case OID_GEN_CURRENT_PACKET_FILTER: + + // + // Verify length + // + + if (OidLength != 4 ) { + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + *BytesRead = 0; + *BytesNeeded = 0; + + break; + + } + + + + NdisMoveMemory(&Filter, InfoBuffer, 4); + + + StatusToReturn=Elnk3FilterChangeAction( + Filter, + pAdapter + ); + + + + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + + // + // Verify length + // + if (OidLength != 4) { + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + *BytesRead = 0; + *BytesNeeded = 0; + + break; + + } + + NdisMoveMemory( + &LookAhead, + InfoBuffer, + 4 + ); + + IF_REQ_LOUD(DbgPrint("Setting LookAhead: %d\n",LookAhead);) + + + if (LookAhead <= ELNK3_MAX_LOOKAHEAD_SIZE) { + + pAdapter->MaxLookAhead=LookAhead; + Elnk3AdjustMaxLookAhead(pAdapter); + + + } else { + + StatusToReturn = NDIS_STATUS_INVALID_LENGTH; + + } + + break; + + + case OID_GEN_PROTOCOL_OPTIONS: + + StatusToReturn = NDIS_STATUS_SUCCESS; + + break; + + + default: + + StatusToReturn = NDIS_STATUS_INVALID_OID; + + *BytesRead = 0; + *BytesNeeded = 0; + + break; + + } + + + if (StatusToReturn == NDIS_STATUS_SUCCESS) { + + *BytesRead = BytesLeft; + *BytesNeeded = 0; + + } + + +#if DBG + + if (StatusToReturn != NDIS_STATUS_SUCCESS) { + + IF_REQ_LOUD(DbgPrint("Out SetInfo oid=%08lx failed\n",Oid);) + } +#endif + + return StatusToReturn; + +} + + + + +VOID +Elnk3AdjustMaxLookAhead( + IN PELNK3_ADAPTER Adapter + ) +/*++ + +Routine Description: + + This routine finds the open with the maximum lookahead value and + stores that in the adapter block. + +Arguments: + + Adapter - A pointer to the adapter block. + +Returns: + + None. + +--*/ +{ + ULONG CurrentMax; + + if (Adapter->MaxLookAhead < 60 ) { + + Adapter->MaxLookAhead =60; + + } + + + CurrentMax=Adapter->MaxLookAhead; + + if (Adapter->ReceiveMethod==1) { + + Adapter->EarlyReceiveThreshold=ELNK3_ROUND_TO_DWORD((CurrentMax+ + ELNK3_ETHERNET_HEADER_SIZE) + & 0x7ff); + } else { + + Adapter->EarlyReceiveThreshold=Adapter->ThresholdTarget & 0x7fc; + } + + + IF_REQ_LOUD(DbgPrint("ELNK3: Setting LookAhead: %d Threshold: %d\n", CurrentMax, Adapter->EarlyReceiveThreshold);) + + +} + + +NDIS_STATUS +Elnk3FilterChangeAction( + IN UINT NewFilterClasses, + IN NDIS_HANDLE MacBindingHandle + ) + +/*++ + +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. + +Arguments: + + NewFilterClasses - A bit mask that should be put on the card telling + which packet types to accept. + + MacBindingHandle - The context value returned by the MAC when the + adapter was opened. + +Return Value: + + Status of the change (successful or pending). + + +--*/ + +{ + PELNK3_ADAPTER pAdapter = MacBindingHandle; + + UCHAR NewFilter=0; + + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction called %08lx\n",NewFilterClasses);) + + if (NewFilterClasses & ~(NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_MULTICAST | + NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_PROMISCUOUS )) { + + IF_REQ_LOUD(DbgPrint("ELNK3: protocol set bogus filter\n");) + return NDIS_STATUS_NOT_SUPPORTED; + } + + + if (NewFilterClasses & NDIS_PACKET_TYPE_DIRECTED) { + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: directed\n");) + NewFilter|=EC_FILTER_ADDRESS; + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_MULTICAST ) { + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: multicast\n");) + NewFilter|=EC_FILTER_GROUP; + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_ALL_MULTICAST) { + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: all multicast\n");) + NewFilter|=EC_FILTER_GROUP; + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_BROADCAST) { + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: broadcast\n");) + NewFilter|=EC_FILTER_BROADCAST; + } + + if (NewFilterClasses & NDIS_PACKET_TYPE_PROMISCUOUS) { + IF_REQ_LOUD(DbgPrint("ELNK3: FilterChangeAction: promiscuous\n");) + NewFilter|=EC_FILTER_PROMISCUOUS; + } + + + pAdapter->RejectBroadcast=FALSE; + + if (NewFilterClasses & NDIS_PACKET_TYPE_MULTICAST) { + // + // The multicast bit is set so the card receives every thing + // that is not directed + // + if ((NewFilterClasses & (NDIS_PACKET_TYPE_BROADCAST | + NDIS_PACKET_TYPE_PROMISCUOUS))==0) { + // + // We want multicast but not broadcast and we aren't + // in promiscuous mode + // + pAdapter->RejectBroadcast=TRUE; + } + } + + + + + pAdapter->NdisRxFilter=NewFilterClasses; + + pAdapter->RxFilter=NewFilter; + + ELNK3_COMMAND(pAdapter, EC_SET_RX_FILTER, NewFilter); + + return NDIS_STATUS_SUCCESS; + + +} diff --git a/private/ntos/ndis/elnk3/send.c b/private/ntos/ndis/elnk3/send.c new file mode 100644 index 000000000..b76cf8beb --- /dev/null +++ b/private/ntos/ndis/elnk3/send.c @@ -0,0 +1,292 @@ +/*++ + +Copyright (c) 1993 Microsoft Corporation + +Module Name: + + send.c + +Abstract: + + Ndis 3.0 MAC driver for the 3Com Etherlink III + + +Author: + + Brian Lieuallen (BrianLie) 12/14/92 + + +Environment: + + Kernel Mode Operating Systems : NT + +Revision History: + + Portions borrowed from ELNK3 driver by + Earle R. Horton (EarleH) + + + +--*/ + + + +#include <ndis.h> +#include <efilter.h> + + +#include "debug.h" + + +#include "elnk3hrd.h" +#include "elnk3sft.h" +#include "elnk3.h" + + + + + + + + + + +NDIS_STATUS +Elnk3MacSend( + IN NDIS_HANDLE MacBindingHandle, + IN PNDIS_PACKET Packet, + IN UINT Flags + ) +/*++ + +Routine Description: + MacSend + + +Arguments: + See NDIS 3.0 spec + +Return Value: + + +--*/ + + + { + PELNK3_ADAPTER pAdapter = MacBindingHandle; + UINT PacketLength; + BOOLEAN Retry=FALSE; + ULONG FreeFifoBytes; + ULONG PadBuffer=0; + + IF_SEND_LOUD(DbgPrint("MacSend called Packets\n");) + + NdisQueryPacket(Packet, NULL, NULL, NULL, &PacketLength); + + // + // Here we check to make sure the packet meets some size constraints + // + + if (PacketLength < 14 || PacketLength > 1514) { + + IF_LOUD(DbgPrint("MovePacketToCard: Packet too long or too short\n");) + + return NDIS_STATUS_FAILURE; + + } + + // + // See if there is enough room in the fifo to send it now. + // + FreeFifoBytes=ELNK3_READ_PORT_USHORT(pAdapter,PORT_TxFree); + + if ((FreeFifoBytes) < ELNK3_ROUND_TO_DWORD(PacketLength)+4) { + // + // Nope, Ask for a transmit availible interrupt when there is + // + ELNK3_COMMAND(pAdapter, EC_SET_TX_AVAILIBLE, ELNK3_ROUND_TO_DWORD(PacketLength)+4); + + return NDIS_STATUS_RESOURCES; + + } + + do { + + + UCHAR XmitStatus; + PNDIS_BUFFER CurBuffer; + PUCHAR BufferAddress; + UINT Len; + ULONG Pad; + PVOID Port=pAdapter->PortOffsets[PORT_TxFIFO]; + + + + NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, NULL); + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len); + + + // + // Write out the length and a pad word + // + + NdisRawWritePortUlong(Port,(PacketLength & 0x7ff)); + + while (1) { + + NdisRawWritePortBufferUlong( + (ULONG)Port, + (PULONG)BufferAddress, + Len >> 2 + ); + + + if ((Len & 3) != 0) { + + NdisRawWritePortBufferUchar( + Port, + BufferAddress+(Len & 0xfffffffc), + (Len & 3) + ); + + } + + + NdisGetNextBuffer(CurBuffer, &CurBuffer); + + if (CurBuffer==NULL) { + // + // done + // + break; + } + + NdisQueryBuffer(CurBuffer, (PVOID *)&BufferAddress, &Len); + + } + + Pad=(ELNK3_ROUND_TO_DWORD(PacketLength) - PacketLength); + + if (Pad != 0) { + + NdisRawWritePortBufferUchar( + (ULONG)Port, + (PUCHAR)&PadBuffer, + Pad + ); + + + } + + + Retry=FALSE; + + // + // Check the status, if it underan then it would be set now + // + ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus); + + if ((XmitStatus & TX_STATUS_COMPLETE) && (XmitStatus & TX_STATUS_UNDERRUN)) { + // + // The transmitter under-ran. Restart it and try again + // + + IF_LOG(0xaa,0xcc, PacketLength); + + HandleXmtInterrupts(pAdapter); + + Retry=TRUE; + + } + + + } while (Retry); + + // + // we sent something + // + NdisMSendResourcesAvailable(pAdapter->NdisAdapterHandle); + + return NDIS_STATUS_SUCCESS; + +} + + + +BOOLEAN +HandleXmtInterrupts( + PELNK3_ADAPTER pAdapter + ) +{ + UCHAR XmitStatus; + + + + ELNK3ReadAdapterUchar(pAdapter,PORT_TxStatus,&XmitStatus); + + IF_LOUD (DbgPrint("ELNK3: HandleXmitInts: Status=%02x\n",XmitStatus);) + + if (XmitStatus != 0) { + // + // pop the tx status + // + ELNK3WriteAdapterUchar(pAdapter,PORT_TxStatus,0); + + if ((XmitStatus & TX_STATUS_JABBER) + || + (XmitStatus & TX_STATUS_UNDERRUN)) { + // + // If it is one of these then it the xmiter needs to be reset + // + ELNK3_COMMAND(pAdapter,EC_TX_RESET,0); + ELNK3_WAIT_NOT_BUSY(pAdapter); + + ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0); + + // + // Could use a better message, But... + // +// +// Commented out so as not to alarm people with random events +// in the registry. +// +// NdisWriteErrorLogEntry( +// pAdapter->NdisAdapterHandle, +// NDIS_ERROR_CODE_TIMEOUT, +// 3, +// pAdapter->FramesXmitGood, +// pAdapter->TxStartThreshold, +// pAdapter->TxStartThresholdInc +// ); + + if ((XmitStatus & TX_STATUS_UNDERRUN)) { + // + // Underrun bump up the threshold + // + pAdapter->TxStartThreshold+=pAdapter->TxStartThresholdInc; + + if (pAdapter->TxStartThreshold > 2040) { + + pAdapter->TxStartThreshold=2040; + } + } + + ELNK3_COMMAND(pAdapter,EC_SET_TX_START,(USHORT)pAdapter->TxStartThreshold & 0x7ff); + + } else { + // + // Otherwise the xmitter just needs to be restarted + // + + ELNK3_COMMAND(pAdapter,EC_TX_ENABLE,0); + } + + pAdapter->FramesXmitBad++; + } + + + IF_SEND_LOUD (DbgPrint("HandleXmitInts: Exit\n");) + + return TRUE; +} diff --git a/private/ntos/ndis/elnk3/sources b/private/ntos/ndis/elnk3/sources new file mode 100644 index 000000000..eec91287c --- /dev/null +++ b/private/ntos/ndis/elnk3/sources @@ -0,0 +1,51 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=ntos +MINORCOMP=ndis + +TARGETNAME=elnk3 +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER + +INCLUDES=..\..\inc + +SOURCES= send.c\ + receive.c\ + interrup.c\ + config.c\ + init.c\ + elnk3.c\ + card.c\ + request.c \ + elnk3.rc + + + +RELATIVE_DEPTH=..\.. + +MSC_WARNING_LEVEL=/W3 /WX |