diff options
Diffstat (limited to 'private/ntos/ndis/ieepro')
-rw-r--r-- | private/ntos/ndis/ieepro/82595.h | 218 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/eeprom.c | 392 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/epro.c | 512 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/epro.h | 221 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/epro.rc | 39 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/eprodbg.c | 57 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/eprodbg.h | 129 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/eprohw.h | 202 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/eprosw.h | 254 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/init.c | 1418 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/makefile | 6 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/request.c | 989 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/sndrcv.c | 1178 | ||||
-rw-r--r-- | private/ntos/ndis/ieepro/sources | 48 |
14 files changed, 5663 insertions, 0 deletions
diff --git a/private/ntos/ndis/ieepro/82595.h b/private/ntos/ndis/ieepro/82595.h new file mode 100644 index 000000000..58b100ee6 --- /dev/null +++ b/private/ntos/ndis/ieepro/82595.h @@ -0,0 +1,218 @@ +#ifndef _I82595TX_ +#define _I82595TX_ + +////////////////////////////////////////////////////////////// +// General Parameters +////////////////////////////////////////////////////////////// +// There are 3 switchable banks of 16 IO ports +// Bank switching is done via register 0 +#define I82595_PORTS_WIDTH 0x10 +#define I82595_NUM_BANKS 0x3 + +// Number of usec to spin in various places before we give up... +#define I82595_SPIN_TIMEOUT 10000 + +////////////////////////////////////////////////////////////// +// Exec States +////////////////////////////////////////////////////////////// +#define I82595_EXEC_STATE_ACTIVE (2 << 4) +#define I82595_EXEC_STATE_IDLE 0 +#define I82595_EXEC_STATE_ABORTING (3 << 4) + +////////////////////////////////////////////////////////////// +// Receive States +////////////////////////////////////////////////////////////// +#define I82595_RCV_STATE_DISABLED 0 +#define I82595_RCV_STATE_READY (1<<6) +#define I82595_RCV_STATE_ACTIVE (2<<6) +#define I82595_RCV_STATE_STOPPING (3<<6) + +////////////////////////////////////////////////////////////// +// Command Constants +////////////////////////////////////////////////////////////// +// Bank switches... +#define I82595_CMD_BANK0 0x0 +#define I82595_CMD_BANK1 0x40 +#define I82595_CMD_BANK2 0x80 + +// Other command constants... +#define I82595_CMD_MC_SETUP 0x03 +#define I82595_XMT 0x04 +#define I82595_XMT_SHORT 0x0004 +#define I82595_CMD_DIAGNOSE 0x07 +#define I82595_FULL_RESET 0x0e +#define I82595_SEL_RESET 0x1e +#define I82595_PWR_DOWN 0x18 +#define I82595_STOP_RCV 0x0b +#define I82595_RCV_ENABLE 0x08 +#define I82595_XMT_RESUME 0x1c + +////////////////////////////////////////////////////////////// +// Return Values (valid after 0,1,3 goes high) +////////////////////////////////////////////////////////////// +#define I82595_DIAGNOSE_PASS 0x07 +#define I82595_DIAGNOSE_FAIL 0x0f +#define I82595_INIT_DONE 0x0e +#define I82595_POWERUP_DONE 0x19 + + +////////////////////////////////////////////////////////////// +// Register Defines +////////////////////////////////////////////////////////////// +#define I82595_CMD_REG 0x0 + +// These are in bank 0 +#define I82595_STATUS_REG 0x1 +#define I82595_ID_REG 0x2 +#define I82595_INTMASK_REG 0x3 +#define I82595_32IOSEL_REG 0x3 +#define I82595_RX_BAR_REG 0x4 +#define I82595_RX_STOP_REG 0x6 +#define I82595_TX_BAR_REG 0xa +#define I82595_HOST_ADDR_REG 0xc // LOW +#define I82595_32MEM_IO_REG 0xc +#define I82595_HOST_ADDR_HIGH_REG 0xd // HIGH +#define I82595_MEM_IO_REG 0xe // LOW +#define I82595_MEM_IO_HIGH_REG 0xf // HIGH + +// Bank 1 +#define I82595_ALT_RDY_REG 0x1 +#define I82595_INTENABLE_REG 0x1 +#define I82595_INT_SELECT_REG 0x2 +#define I82595_IOMAP_REG 0x3 + +#define I82595_RX_LOWER_LIMIT_REG 0x8 +#define I82595_RX_UPPER_LIMIT_REG 0x9 +#define I82595_TX_LOWER_LIMIT_REG 0xa +#define I82595_TX_UPPER_LIMIT_REG 0xb +#define I82595_IOCHRDY_TEST_REG 0xd + +// Bank 2 +#define I82595_CONFIG1_REG 0x1 +#define I82595_CONFIG2_REG 0x2 +#define I82595_CONFIG3_REG 0x3 +#define I82595_IA_REG_0 0x4 +#define I82595_IA_REG_1 0x5 +#define I82595_IA_REG_2 0x6 +#define I82595_IA_REG_3 0x7 +#define I82595_IA_REG_4 0x8 +#define I82595_IA_REG_5 0x9 +#define I82595_EEPROM_REG 0xa // eeprom access reg +#define I82595_STEPPING_REG 0xa + +////////////////////////////////////////////////////////////// +// Register Masks... +////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////// +// Command Register (ALL,0) +////////////////////////////////////////////////////////////// +#define I82595_CUR_BANK_MASK 0xC0 + +////////////////////////////////////////////////////////////// +// Status Register (0,1) bitmasks +////////////////////////////////////////////////////////////// +#define I82595_RX_STP_INT_RCVD 0x1 // bit 0 + +// Did we get a RX Interrupt +#define I82595_RX_INT_RCVD 0x2 // bit 1 + +// Mask the TX interupt? +#define I82595_TX_INT_RCVD 0x4 // bit 2 + +// This goes high when a command execution is complete. +#define I82595_EXEC_INT_RCVD 0x8 // bit 3 + +// status codes +#define I82595_EXEC_STATE 0x30 // bit 4,5 +#define I82595_RCV_STATE 0xC0 // bit 6,7 + +#define I82595_STATES_OFFSET 0x4 + +////////////////////////////////////////////////////////////// +// Reg 0,3 +////////////////////////////////////////////////////////////// +#define I82595_RX_STP_INT_MASK 0x1 // bit 0 + +// Mask the RX interrupt? +#define I82595_RX_INT_MASK 0x2 // bit 1 + +// Mask the TX interupt? +#define I82595_TX_INT_MASK 0x4 // bit 2 + +// This goes high when a command execution is complete. +#define I82595_EXEC_INT_MASK 0x8 // bit 3 + +#define I82595_32IOSEL 0x10 // bit 4 + +////////////////////////////////////////////////////////////// +// Reg 0,4 +////////////////////////////////////////////////////////////// +#define I82595_IOBASE_SELECT 0x3f // bits 0-5 +#define I82595_IOBASE_TO_SELECTION(a) (a>>4) + +////////////////////////////////////////////////////////////// +// Register 1,1 +////////////////////////////////////////////////////////////// +#define I82595_USE_8_BIT_FLAG 0x2 +#define I82595_ALT_IOCHRDY 0x40 +#define I82595_ENABLE_INTS_FLAG 0x80 + +////////////////////////////////////////////////////////////// +// Register 1,2 +////////////////////////////////////////////////////////////// +#define I82595_INTERRUPT_SELECT_MASK 0x3 // bits 0,1 +#define I82595_ALT_RDY_FLAG 0x40 // bit 6 + +////////////////////////////////////////////////////////////// +// Register 1,13 +////////////////////////////////////////////////////////////// +#define I82595_IOCHRDY_PASS_FLAG 0x1 +#define I82595_IOCHRDY_TEST_FLAG 0x2 + + +////////////////////////////////////////////////////////////// +// Register 2.2 - configuration +////////////////////////////////////////////////////////////// +#define I82595_PROMISCUOUS_FLAG 0x01 +#define I82595_NO_BROADCAST_FLAG 0x02 + +////////////////////////////////////////////////////////////// +// Register 2.10 -- eeprom access +////////////////////////////////////////////////////////////// +#define I82595_EESK_MASK 0x1 +#define I82595_EECS_MASK 0x2 +#define I82595_EEDI_MASK 0x4 +#define I82595_EEDO_MASK 0x8 +#define I82595_TURNOFF_ENABLE 0x10 + +#define I82595_EEDI_OFFSET 0x2 +#define I82595_EEDO_OFFSET 0x3 + +#define I82595_EEPROM_READ 0x6 // 110:b +#define I82595_EEPROM_WRITE 0x5 +#define I82595_EEPROM_ERASE 0x7 +#define I82595_EEPROM_EWEN 19 +#define I82595_EEPROM_EWDS 16 + +#define I82595_EEPROM_IOADDR_REG 0 +#define I82595_EEPROM_IOMASK ((0x3f) << 10) + +#define I82595_STEPPING_OFFSET 0x5 // bits 5-7 are 82595 stepping + +////////////////////////////////////////////////////////////////////// +// TX constants +////////////////////////////////////////////////////////////////////// +#define I82595_TX_FRM_HDR_SIZE 0x8 +#define I82595_TX_DN_BYTE_MASK 0x80 +#define I82595_CH_SHORT_MASK 0x8000 +#define I82595_TX_OK_SHORT_MASK 0x2000 +#define I82595_NO_COLLISIONS_MASK 0x0f + +////////////////////////////////////////////////////////////////////// +// RX Constants +////////////////////////////////////////////////////////////////////// +#define I82595_RX_EOF 0x08 +#define I82595_RX_OK 0x20 + +#endif // ifndef _i82595TX_ diff --git a/private/ntos/ndis/ieepro/eeprom.c b/private/ntos/ndis/ieepro/eeprom.c new file mode 100644 index 000000000..10b8fe9f0 --- /dev/null +++ b/private/ntos/ndis/ieepro/eeprom.c @@ -0,0 +1,392 @@ +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +VOID EProEERead( + PEPRO_ADAPTER adapter, + USHORT address, + PUSHORT data) +/*++ + + Routine Description: + + This function reads the 16-bit register at address (address % 64) + from the EPro's eeprom (there are only 64 words of registers + on the eeprom) + + IMPORTANT NOTE - for PnP accesses to the EPro's eeprom (registers + 0x10 and higher), you must use the EProEEReverseRead since for some + reason the EPro stores PnP data in the reverse bit-order (except for + the low byte of word 10, which is in the normal bit order) -- see + the 82595 docs and PnP docs for an explanation. + + Arguments: + + data - the where the result is written to + + Return Value: + + none + +--*/ +{ + UCHAR result; + UCHAR opcode; + +// siwtch to bank2 + EPRO_SWITCH_BANK_2(adapter); + +// Get the value from the register, so we can flip the eecs bit + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + +// turn the eecs bit on.. (1) + result |= I82595_EECS_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + +// Write the read opcode to the eeprom (2) + opcode = I82595_EEPROM_READ; + EProEEShiftOutBits(adapter, opcode, 3); + +// Write the address to read to the eeprom + EProEEShiftOutBits(adapter, address, 6); + +// Read the result + EProEEShiftInBits(adapter, data, 16); + + EProEECleanup(adapter); + + EPRO_SWITCH_BANK_0(adapter); +} + + +VOID EProEEWrite( + PEPRO_ADAPTER adapter, + USHORT address, + USHORT data) +{ + UCHAR result; + +// siwtch to bank2 + EPRO_SWITCH_BANK_2(adapter); + + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= ~(I82595_EEDI_MASK | I82595_EEDO_MASK | I82595_EESK_MASK); + result |= I82595_EECS_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + + // write the read opcode and register number + EProEEShiftOutBits(adapter, I82595_EEPROM_EWEN, 5); + EProEEShiftOutBits(adapter, address, 4); + + EProEEStandBy(adapter); + + EProEEShiftOutBits(adapter, I82595_EEPROM_ERASE, 3); + EProEEShiftOutBits(adapter, address, 6); + + if (EProEEWaitCmdDone(adapter) == FALSE) { + EPRO_DPRINTF_INIT(("Failed EEPROM erase!\n")); + return; + } + + EProEEStandBy(adapter); + + EProEEShiftOutBits(adapter, I82595_EEPROM_WRITE, 3); + EProEEShiftOutBits(adapter, address, 6); + EProEEShiftOutBits(adapter, data, 16); + + if (EProEEWaitCmdDone(adapter) == FALSE) { + EPRO_DPRINTF_INIT(("Failed EEPROM write!\n")); + return; + } + + EProEEStandBy(adapter); + + EProEEShiftOutBits(adapter, I82595_EEPROM_EWDS, 5); + EProEEShiftOutBits(adapter, address, 4); + + EProEECleanup(adapter); + +// siwtch to bank0 + EPRO_SWITCH_BANK_0(adapter); + +} + + +VOID EProEECleanup(PEPRO_ADAPTER adapter) +{ + UCHAR result; + + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= ~(I82595_EECS_MASK | I82595_EEDI_MASK); + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + EProEERaiseClock(adapter, &result); + EProEELowerClock(adapter, &result); +} + + +VOID EProEEUpdateChecksum(PEPRO_ADAPTER adapter) +{ + USHORT chkSum = 0, result, i; + + for (i=0;i<0x3f;i++) { + EProEERead(adapter, i, &result); + chkSum+=result; + } + + chkSum = (USHORT)0xBABA - chkSum; + EProEEWrite(adapter, 0x3f, chkSum); +} + + +VOID EProEEStandBy( + PEPRO_ADAPTER adapter) +{ + UCHAR result; + + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= ~(I82595_EECS_MASK | I82595_EESK_MASK); + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + NdisStallExecution(100); + result |= I82595_EECS_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); +} + + + +BOOLEAN EProEEWaitCmdDone( + PEPRO_ADAPTER adapter) +{ + USHORT i; + UCHAR result; + + EProEEStandBy(adapter); + + for (i=0; i<200;i++) { + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + if (result & I82595_EEDO_MASK) { + return(TRUE); + } + NdisStallExecution(100); + } + + return(FALSE); + +} + +VOID EProEEReverseRead( + PEPRO_ADAPTER adapter, + USHORT address, + PUSHORT data) +{ + UCHAR result, opcode; + UINT i; + +// siwtch to bank2 + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK2); + +// Get the value from the register, so we can flip the eecs bit + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + +// turn the eecs bit on.. (1) + result |= I82595_EECS_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + +// Write the read opcode to the eeprom (2) + opcode = I82595_EEPROM_READ; + EProEEShiftOutBits(adapter, opcode, 3); + +// Write the address to read to the eeprom + EProEEShiftOutBits(adapter, address, 6); + +// Read the result + EProEEReverseShiftInBits(adapter, data, 16); + +// Turn off EEPROM + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= (~I82595_EECS_MASK); + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + + EPRO_SWITCH_BANK_0(adapter); +} + +VOID EProEEShiftOutBits( + PEPRO_ADAPTER adapter, + USHORT data, + SHORT count) +/*++ + + Routine Description: + + This function shifts count bits OUT TO THE EEPROM through it's serial + interface + + Arguments: + + adapter - pointer to our adapter structure + + data - the word to shift out from (MSB first) + + count - the number of bits to shift out... + + Return Value: + + none + +--*/ +{ + UCHAR result; + USHORT mask; + + mask = 0x1 << (count - 1); + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK); + + do + { + result &= ~I82595_EEDI_MASK; + if (data & mask) + { + result |= I82595_EEDI_MASK; + } + + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + NdisStallExecution(100); + EProEERaiseClock(adapter, &result); + EProEELowerClock(adapter, &result); + mask = mask >> 1; + } while(mask); + + result &= ~I82595_EEDI_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); +} + +VOID EProEEShiftInBits( + PEPRO_ADAPTER adapter, + PUSHORT data, + SHORT count) +/*++ + + Routine Description: + + This routine is analagous to shift-out-bits, except reads bits from + the eeprom... Note that for PNP accesses to the EPro + (pnp for the EPro lives in registers 0x10 and higher) you must use + a different function since PnP data is written in reverse bit order + for some reason + + Arguments: + + adapter - pointer to our adapter structure + + data - the word to read into + + count - how many bits to read + + Return Value: + + none + +--*/ +{ + UCHAR result; + USHORT i; + + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); + result &= ~(I82595_EEDO_MASK | I82595_EEDI_MASK); + *data = 0; + + for (i=0;i<16;i++) + { + *data = *data << 1; + EProEERaiseClock(adapter, &result); // 4.1 + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2 + result &= ~I82595_EEDI_MASK; + if (result & I82595_EEDO_MASK) { + *data |= 1; + } + EProEELowerClock(adapter, &result); + } +} + +void EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count) +{ + UCHAR result; + SHORT count1; + + *data = 0; + + for (count1=0;count1<=count;count1++) { + + EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, &result); // 4.2 + + result &= I82595_EEDO_MASK; // turn off everything but the EEDO bit + + // according to docs we get MSB out first... + // this is a REVERSE read - get LSB first + *data |= ((result >> I82595_EEDO_OFFSET) << count1); + } +} + +VOID EProEERaiseClock( + PEPRO_ADAPTER adapter, + PUCHAR result) +/*++ + + Routine Description: + + This routine raises the "clock" bit in the eeprom access register -- + basically since the eeprom is a serial device you raise then lower the + clock between bits... + + Arguments: + + adapter - pointer to the adapter structure + + Return Value: + + none + +--*/ +{ +// UCHAR result; + +// turn EESK bit high + *result = *result | I82595_EESK_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result); + NdisStallExecution(EPRO_SK_STALL_TIME); +} + +VOID EProEELowerClock( + PEPRO_ADAPTER adapter, + PUCHAR result) +/*++ + + Routine Description: + + Analagous to EProEERaiseClock... + + Arguments: + + adapter - pointer to our adapter structure. + + Return Value: + + none + +--*/ +{ +// UCHAR result; + +// EPRO_RD_PORT_UCHAR(adapter, I82595_EEPROM_REG, result); + + // turn EESK bit low... + *result = *result & ~I82595_EESK_MASK; + EPRO_WR_PORT_UCHAR(adapter, I82595_EEPROM_REG, *result); + + NdisStallExecution(EPRO_SK_STALL_TIME); +} + + diff --git a/private/ntos/ndis/ieepro/epro.c b/private/ntos/ndis/ieepro/epro.c new file mode 100644 index 000000000..ca80d467f --- /dev/null +++ b/private/ntos/ndis/ieepro/epro.c @@ -0,0 +1,512 @@ +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +// Global data + +NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char; + +EPRO_DRIVER EProMiniportDriver={0}; + +NDIS_STATUS EProSelReset(PEPRO_ADAPTER adapter) +/*++ + + Routine Description: + + This does a SEL-RESET of the i82595 chip. Read the 82595 docs + for more info on what this does. + + Arguments: + + adapter - pointer to our adapter structure + + Return Values: + + always returns NDIS_STATUS_SUCCESS + +--*/ +{ + EPRO_ASSERT_BANK_0(adapter); + + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_SEL_RESET); + +// according to 82595 prelim doc: wait 2 us after sel reset before +// accessing the 82595 + NdisStallExecution(2); + + EProEnableInterrupts((NDIS_HANDLE)adapter); + + adapter->fHung = FALSE; + + return(NDIS_STATUS_SUCCESS); +} + +VOID +EProInitializeAdapterData( + IN PEPRO_ADAPTER adapter + ) +/*++ + + Routine Description: + + This routine initializes our adapter structure - setting default + values, zeroing fields, etc. This is called on adapter initialization + and adapter reset. + + Arguments: + + A pointer to the adapter structure to clear. + + Return Values: + + none + +--*/ +{ + UINT i; + + adapter->CurrentHardwareStatus = NdisHardwareStatusReady; + + adapter->vendorID[0] = EPRO_VENDOR_ID_L; + adapter->vendorID[1] = EPRO_VENDOR_ID_M; + adapter->vendorID[2] = EPRO_VENDOR_ID_H; + + adapter->CurrentPacketFilter = 0; + + // hack to get around wrapper bug: + // adapter->RXLookAheadSize = 0; + // + adapter->RXLookAheadSize = 256; + adapter->FramesXmitOK = 0; + adapter->FramesRcvOK = 0; + adapter->FramesXmitErr = 0; + adapter->FramesRcvErr = 0; + adapter->FramesMissed = 0; + + adapter->FrameAlignmentErrors = 0; + adapter->FramesXmitOneCollision = 0; + adapter->FramesXmitManyCollisions = 0; + + adapter->CurrentTXBuf = &adapter->TXBuf[0]; + adapter->TXChainStart = NULL; + + // Packet filter settings... + // + adapter->fPromiscuousEnable = FALSE; + adapter->fBroadcastEnable = FALSE; + adapter->fMulticastEnable = FALSE; + adapter->fReceiveEnabled = FALSE; + adapter->NumMCAddresses = 0; + + // Don't force 8-bit operation + // + adapter->Use8Bit = FALSE; + + adapter->IntPending = EPRO_INT_NONE_PENDING; + adapter->fHung = FALSE; + // adapter->fTransmitInProgress = FALSE; + + // Set up the TX buffers... + // + for (i = 0;i < EPRO_NUM_TX_BUFFERS; i++) + { + if (0 == i) + { + adapter->TXBuf[0].LastBuf = &adapter->TXBuf[EPRO_NUM_TX_BUFFERS - 1]; + } + else + { + adapter->TXBuf[i].LastBuf = &adapter->TXBuf[i-1]; + } + + if ((EPRO_NUM_TX_BUFFERS - 1) == i) + { + adapter->TXBuf[i].NextBuf = &adapter->TXBuf[0]; + } + else + { + adapter->TXBuf[i].NextBuf = &adapter->TXBuf[i + 1]; + } + + adapter->TXBuf[i].fEmpty = TRUE; + adapter->TXBuf[i].TXBaseAddr = 0; + adapter->TXBuf[i].TXSendAddr = 0xffff; + } +} + +VOID EProEnableInterrupts(IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + The MiniportEnableInterrupt Handler for the card. + + Arguments: + + miniportAdapterContext - really a PEPRO_ADAPTER to our adapter structure + + Return Value: none + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + +// If this isn't true, then NdisMSyncronizeWithInterrupt is broken +// or we've called a function which switches banks without syncronizing +// it... + EPRO_ASSERT_BANK_0(adapter); + + EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG, + adapter->CurrentInterruptMask); + +} + +VOID EProDisableInterrupts(IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + The MiniportDisableInterrupts handler for the driver + + Arguments: + + miniportAdapterContext - really a pointer to our adapter structure + + Return Values: none + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + +// If this isn't true, then NdisMSyncronizeWithInterrupt is broken +// or we've called a function which switches banks without syncronizing +// it... + EPRO_ASSERT_BANK_0(adapter); + +// mask all int's + EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG, + (adapter->CurrentInterruptMask | 0x0f)); +} + + +VOID EProHalt(IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + This is the function which halts the 82595 chip and disables the + adapter - frees hardware resources, etc. + + Arguments: + + miniportAdapterContext - pointer to our adapter structure + + Returns: nothing + +--*/ +{ + PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext; + +// Shut down the card - disable receives. + EProReceiveDisable(adapter); + +// There won't be any more interrupts + NdisMDeregisterInterrupt(&adapter->Interrupt); + +// Pause, wait for pending DPC stuff to clear... Random number stolen +// from the NE2000 driver... + NdisStallExecution(250000); + +// Unmap our IO ports + NdisMDeregisterIoPortRange(adapter->MiniportAdapterHandle, + (ULONG)adapter->IoBaseAddr, + 0x10, + (PVOID)adapter->IoPAddr); + +// Free up our adapter structure... + NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0); +} + +NDIS_STATUS EProReset(OUT PBOOLEAN fAddressingReset, + IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + This is the MiniportReset handler for the EPro driver + + Arguments: + + fAddressingReset - Do we need to be re-told our MC address list? + currently we say yes, although probably we don't + have to be told this (the driver saves it) + + Return Values: + + the return from EProSelReset (always NDIS_STATUS_SUCCESS) + +--*/ +{ + PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext; + +// Okay, we don't want to get any interrupts anymore. + EProDisableInterrupts(adapter); + EProReceiveDisable(adapter); + +// clear out TX structures... + EProInitializeAdapterData(adapter); + +// We probably can set this to false -- TODO + *fAddressingReset = TRUE; + + return(EProSelReset(adapter)); +} + +BOOLEAN EProCheckForHang(IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + This is the MiniportCheckForHang handler for the driver. + It does absolutely nothing right now. + + Arguments: + + miniportAdapterContext - right now a pointer to our adapter structure + + Return Value: + + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + + if (adapter->fHung) + { + return(TRUE); + } + + return(FALSE); +} + +VOID EProHandleInterrupt( + IN NDIS_HANDLE miniportAdapterContext) +/*++ + + Routine Description: + + This is the function that gets called at DPC level in response + to a hardware interrupt. It is queued by the wrapper's ISR routines. + Interrupts have been disabled when this routine is called. + + Arguments: + + miniportAdapterContext - really a pointer to our adapter structure + + Return Value: + + none + +--*/ +{ + PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext; + UCHAR whichInt; + BOOLEAN fFoundInts, fFoundRX = FALSE; + + // verify bank 0 + EPRO_ASSERT_BANK_0(adapter); + + do + { + fFoundInts = FALSE; + + // Read in the int mask + // + EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &whichInt); + + // quick out if there are no ints pending... + if (!(whichInt & 0x0f)) + { + break; + } + + // acknowlege interrupts - writing a 1 over the int flag clears it + EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, whichInt); + + if (whichInt & I82595_TX_INT_RCVD) + { + fFoundInts = TRUE; + if (adapter->TXChainStart != NULL) + { + EProCheckTransmitCompletion(adapter, adapter->TXChainStart); + } + } + +// if (whichInt & I82595_TX_INT_RCVD) +// { +// fFoundInts = TRUE; +// if (adapter->TXChainStart != NULL) +// { +// while (EProCheckTransmitCompletion(adapter, adapter->TXChainStart)) +// ; +// } +// } + + if (whichInt & I82595_RX_INT_RCVD) + { + fFoundInts = TRUE; + if (EProHandleReceive(adapter) > 0) + { + fFoundRX = TRUE; + } + } + + if (whichInt & I82595_EXEC_INT_RCVD) + { + fFoundInts = TRUE; + + EProSetInterruptMask(adapter, EPRO_DEFAULT_INTERRUPTS); + + switch(adapter->IntPending) + { + case EPRO_INT_MC_SET_PENDING: + + ((PEPRO_TRANSMIT_BUFFER)adapter->IntContext)->fEmpty = TRUE; + EPRO_DPRINTF_INTERRUPT(("Set COMPLETED!")); + + NdisMSetInformationComplete( + adapter->MiniportAdapterHandle, + NDIS_STATUS_SUCCESS); + + break; +// default: +// EPRO_ASSERT(FALSE); // we shouldn't hit this... + } + + // clear the pending interrupt... + // + adapter->IntPending = 0; + adapter->IntContext = NULL; + } + } while ((fFoundInts == TRUE) && !adapter->fHung); + + if (fFoundRX) + { + NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle); + } +} + +void +EProISR( + OUT PBOOLEAN interruptRecognized, + OUT PBOOLEAN queueMiniportHandleInterrupt, + IN NDIS_HANDLE miniportAdapterContext) +{ + EPRO_DPRINTF_INTERRUPT(("ISR")); + + *interruptRecognized = TRUE; + *queueMiniportHandleInterrupt = FALSE; +} + + +BOOLEAN EProSyncSetInterruptMask(PVOID context) +{ + PEPRO_ADAPTER adapter = ((PEPRO_SETINTERRUPT_CONTEXT)context)->Adapter; + UCHAR newMask = ((PEPRO_SETINTERRUPT_CONTEXT)context)->NewMask; + +// unmask everyone... + adapter->CurrentInterruptMask &= 0xf0; +// now mask the ones we don't want + adapter->CurrentInterruptMask |= newMask; + + EPRO_ASSERT_BANK_0(adapter); + + EPRO_WR_PORT_UCHAR(adapter, I82595_INTMASK_REG, + adapter->CurrentInterruptMask); + + return(TRUE); +} + +// Poll the exec-states reg (0,1), waiting for any execution to finish... +BOOLEAN EProWaitForExeDma(PEPRO_ADAPTER adapter) +{ + UINT i; + UCHAR result; + +// status reg is in bank 0 + EPRO_ASSERT_BANK_0(adapter); + + for (i=0;i<I82595_SPIN_TIMEOUT;i++) { + // make sure the dma is idle + EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result); + if (!(result&I82595_EXEC_STATE)) { + if (result & I82595_EXEC_INT_RCVD) { + // clear the exec int if it's high... + EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, + I82595_EXEC_INT_RCVD); + } + return(TRUE); + } + NdisStallExecution(1); + } + + return(FALSE); +} + +BOOLEAN EProReceiveEnable(PEPRO_ADAPTER adapter) +{ + UINT i = 0; + UCHAR result; + + adapter->RXCurrentAddress = 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8); + + // EPRO_ASSERT(!adapter->fReceiveEnabled); + + // don't enable if we're already enabled. + if (adapter->fReceiveEnabled) + { + return(TRUE); + } + + // bank0 + // EPRO_SWITCH_BANK_0(adapter); + // + EPRO_ASSERT_BANK_0(adapter); + EPRO_WR_PORT_USHORT(adapter, I82595_RX_STOP_REG, 0 | (((USHORT)EPRO_RX_UPPER_LIMIT) << 8)); + EPRO_WR_PORT_USHORT(adapter, I82595_RX_BAR_REG, 0 | (((USHORT)EPRO_RX_LOWER_LIMIT) << 8)); + + // + // validate registers... + // + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_RCV_ENABLE); + + adapter->fReceiveEnabled = TRUE; + + return(TRUE); +} + +BOOLEAN EProReceiveDisable(PEPRO_ADAPTER adapter) +{ + UINT i = 0; + UCHAR result; + +// bank0 +// EPRO_SWITCH_BANK_0(adapter); + EPRO_ASSERT_BANK_0(adapter); + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_STOP_RCV); + + adapter->fReceiveEnabled = FALSE; + + return(TRUE); +} + +//VOID EProTimerFunc(IN PVOID foo1, IN PVOID context, IN PVOID foo2, IN PVOID foo3) +//{ +// EProHandleInterrupt((NDIS_HANDLE)context); +// +// queue another timer... +// NdisMSetTimer(&(((PEPRO_ADAPTER)context)->MiniportTimer), 10); +//} diff --git a/private/ntos/ndis/ieepro/epro.h b/private/ntos/ndis/ieepro/epro.h new file mode 100644 index 000000000..f5f6ed7aa --- /dev/null +++ b/private/ntos/ndis/ieepro/epro.h @@ -0,0 +1,221 @@ +#ifndef _IEPRO_ +#define _IEPRO_ + +#define EPRO_DRIVER_VER_MAJOR 1 +#define EPRO_DRIVER_VER_MINOR 0 + +#include "eprosw.h" + +/////////////////////////////////////////////////////////////////// +//epro.c: +/////////////////////////////////////////////////////////////////// + +NDIS_STATUS EProSelReset(PEPRO_ADAPTER adapter); + +VOID EProInitializeAdapterData(PEPRO_ADAPTER adapter); + +VOID EProEnableInterrupts(IN NDIS_HANDLE miniportAdapterContext); + +VOID EProDisableInterrupts(IN NDIS_HANDLE miniportAdapterContext); + +BOOLEAN EProVerifyRoundRobin(UCHAR *buf); + +BOOLEAN EProPowerupBoard(PEPRO_ADAPTER adapter); + +extern VOID EProHalt(IN NDIS_HANDLE miniportAdapterContext); + +NDIS_STATUS EProReset(OUT PBOOLEAN fAddressingReset, + IN NDIS_HANDLE miniportAdapterContext); + +BOOLEAN EProCheckForHang(IN NDIS_HANDLE miniportAdapterContext); + +VOID EProHandleInterrupt(IN NDIS_HANDLE miniportAdapterContext); + +VOID EProISR(OUT PBOOLEAN interruptRecognized, + OUT PBOOLEAN queueMiniportHandleInterrupt, + IN NDIS_HANDLE miniportAdapterContext); + +BOOLEAN EProCardReadEthernetAddress(PEPRO_ADAPTER adapter); + +BOOLEAN EProAltIOCHRDYTest(PEPRO_ADAPTER adapter); + +BOOLEAN EProSyncSetInterruptMask(PVOID context); + +// This is implemented via a macro +//VOID EProSetInterruptMask(PEPRO_ADAPTER adapter, UCHAR newMask); + +#define EProSetInterruptMask(_adapter, _newMask) { \ + EPRO_SETINTERRUPT_CONTEXT _context; \ + _context.Adapter = _adapter; \ + _context.NewMask = _newMask; \ + NdisMSynchronizeWithInterrupt(&_adapter->Interrupt, \ + &EProSyncSetInterruptMask, \ + &_context); \ +} + +BOOLEAN EProWaitForExeDma(PEPRO_ADAPTER adapter); + +BOOLEAN EProReceiveEnable(PEPRO_ADAPTER adapter); + +BOOLEAN EProReceiveDisable(PEPRO_ADAPTER adapter); + +VOID EProMyLog(char *s); + +//VOID EProTimerFunc(IN PVOID foo1, IN PVOID context, IN PVOID foo2, IN PVOID foo3); + +#if DBG + +VOID EProLogStr(char *s); +VOID EProLogLong(ULONG l); +VOID EProLogBuffer(UCHAR *s, ULONG len); + +#else + +#define EProLogStr(a) +#define EProLogLong(a) +#define EProLogBuffer(a, b) + +#endif + +/////////////////////////////////////////////////////////////////// +// init.c +/////////////////////////////////////////////////////////////////// + +NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject_, + IN PUNICODE_STRING RegistryPath_); + +NDIS_STATUS EProInitialize(OUT PNDIS_STATUS openErrorStatus, + OUT PUINT selectedMedumIndex, + IN PNDIS_MEDIUM medumArray, + IN UINT mediumArraySize, + IN NDIS_HANDLE miniportAdapterHandle, + IN NDIS_HANDLE configurationHandle); + +NDIS_STATUS EProReadConfiguration(IN PEPRO_ADAPTER adapterxo, + IN NDIS_HANDLE configurationHandle); + +NDIS_STATUS EProRegisterAdapterHW(IN PEPRO_ADAPTER adapter); + +NDIS_STATUS EProInitialReset(IN PEPRO_ADAPTER adapter); + +NDIS_STATUS EProHWInitialize(IN PEPRO_ADAPTER adapter); + +VOID EProUpdateEEProm(IN PEPRO_ADAPTER adapter); + +NDIS_STATUS EProHWConfigure(IN PEPRO_ADAPTER adapter); + +////////////////////////////////////////////////////////////////////// +// request.c: +////////////////////////////////////////////////////////////////////// + +NDIS_STATUS EProSetInformation(IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_OID oid, + IN PVOID informationBuffer, + IN ULONG informationLength, + OUT PULONG bytesRead, + OUT PULONG bytesNeeded); + +NDIS_STATUS EProQueryInformation(IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_OID oid, + IN PVOID informationBuffer, + IN ULONG informationBuffrLength, + OUT PULONG bytesWritten, + OUT PULONG bytesNeeded); + +BOOLEAN EProSetEthernetAddress(PEPRO_ADAPTER adapter); + +NDIS_STATUS EProSetPacketFilter(PEPRO_ADAPTER adapter, ULONG newFilter); + +BOOLEAN EProSyncBroadcastPromiscuousChange(PVOID context); + +// Implemented via a macro +//VOID EProBroadcastPromiscuousChange(PEPRO_ADAPTER adapter, UCHAR reg2flags); +#define EProBroadcastPromiscuousChange(_adapter, _reg2Flags) { \ + EPRO_BRDPROM_CONTEXT _context; \ + _context.Adapter =_adapter; \ + _context.Reg2Flags = _reg2Flags; \ + NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \ + &EProSyncBroadcastPromiscuousChange, \ + (PVOID)&_context); \ +} + + +////////////////////////////////////////////////////////////////////// +// eeprom.c: +////////////////////////////////////////////////////////////////////// + +// EEProm Routines +VOID EProEECleanup(PEPRO_ADAPTER adapter); +VOID EProEEUpdateChecksum(PEPRO_ADAPTER adapter); +VOID EProEEStandBy(PEPRO_ADAPTER adapter); +VOID EProEERead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data); +VOID EProEEWrite(PEPRO_ADAPTER adapter, USHORT address, USHORT data); +VOID EProEEReverseRead(PEPRO_ADAPTER adapter, USHORT address, PUSHORT data); +VOID EProEEShiftOutBits(PEPRO_ADAPTER adapter, USHORT data, SHORT count); +VOID EProEEShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count); +VOID EProEEReverseShiftInBits(PEPRO_ADAPTER adapter, PUSHORT data, SHORT count); +VOID EProEERaiseClock(PEPRO_ADAPTER adapter, PUCHAR result); +VOID EProEELowerClock(PEPRO_ADAPTER adapter, PUCHAR result); +BOOLEAN EProEEWaitCmdDone(PEPRO_ADAPTER adapter); + + +////////////////////////////////////////////////////////////////////// +// sndrcv.c +////////////////////////////////////////////////////////////////////// + +BOOLEAN EProSyncReadBufferFromNicUlong(PVOID context); +BOOLEAN EProSyncWriteBufferToNicUlong(PVOID context); + +NDIS_STATUS EProSend(IN NDIS_HANDLE miniportAdapterContext, + IN PNDIS_PACKET packet, + IN UINT flags); + +VOID EProCopyPacketToCard(PEPRO_ADAPTER adapter, PNDIS_PACKET packet); + + +BOOLEAN EProCheckTransmitCompletion(PEPRO_ADAPTER adapter, + PEPRO_TRANSMIT_BUFFER txBuf); + +UINT EProHandleReceive(PEPRO_ADAPTER adapter); + +NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet, + OUT PUINT bytesTransferred, + IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_HANDLE miniportReceivedContext, + IN UINT byteOffset, + IN UINT bytesToTransfer); + +BOOLEAN EProChangeMulticastList(PEPRO_ADAPTER adapter, + UINT addressCount, + UCHAR addresses[][EPRO_LENGTH_OF_ADDRESS]); + +#define EPRO_SET_CARD_MC 0 +#define EPRO_CLEAR_CARD_MC 1 +BOOLEAN EProSetCardMulticastList(PEPRO_ADAPTER adapter, int operation); + +BOOLEAN EProSyncCopyBufferToNicUlong(PVOID context); + +#define EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter, buffer, len) \ + { \ + EPRO_COPYBUF_CONTEXT _context; \ + _context.Adapter = adapter; \ + _context.Buffer = buffer; \ + _context.Len = len; \ + NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \ + &EProSyncReadBufferFromNicUlong, \ + (PVOID)&_context); \ + } + +#define EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, buffer, len) \ + { \ + EPRO_COPYBUF_CONTEXT _context; \ + _context.Adapter = adapter; \ + _context.Buffer = buffer; \ + _context.Len = len; \ + NdisMSynchronizeWithInterrupt(&adapter->Interrupt, \ + &EProSyncCopyBufferToNicUlong, \ + (PVOID)&_context); \ + } + + +#endif _IEPRO_ diff --git a/private/ntos/ndis/ieepro/epro.rc b/private/ntos/ndis/ieepro/epro.rc new file mode 100644 index 000000000..254086031 --- /dev/null +++ b/private/ntos/ndis/ieepro/epro.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 "Intel EtherExpress Pro network driver" +#define VER_INTERNALNAME_STR "IEEPRO.SYS" +#define VER_ORIGINALFILENAME_STR "IEEPRO.SYS" + +#include "common.ver" + diff --git a/private/ntos/ndis/ieepro/eprodbg.c b/private/ntos/ndis/ieepro/eprodbg.c new file mode 100644 index 000000000..391349a73 --- /dev/null +++ b/private/ntos/ndis/ieepro/eprodbg.c @@ -0,0 +1,57 @@ +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +#if DBG + +// Flags to turn spew on or off from debugger... +BOOLEAN EPRO_TX_DBG_ON = FALSE; +BOOLEAN EPRO_RX_DBG_ON = FALSE; +// default INIT spew to ON in debug version for now... +BOOLEAN EPRO_INIT_DBG_ON = FALSE; +BOOLEAN EPRO_REQ_DBG_ON = FALSE; +BOOLEAN EPRO_INTERRUPT_DBG_ON = FALSE; + +#define EPRO_LOG_SIZE 10000 + +UCHAR EPro_Log[EPRO_LOG_SIZE]; +UINT EPro_Log_Offset = 0; + +VOID EProLogStr(char *s) +{ + UINT len = strlen(s); + + if ((EPro_Log_Offset + len) >= EPRO_LOG_SIZE) { + EPro_Log_Offset = 0; + } + + NdisMoveMemory((&EPro_Log[EPro_Log_Offset]), s, len); + EPro_Log_Offset+=len; +} + +VOID EProLogLong(ULONG l) +{ + if (EPro_Log_Offset + sizeof(ULONG) >= EPRO_LOG_SIZE) { + EPro_Log_Offset = 0; + } + + NdisMoveMemory((&EPro_Log[EPro_Log_Offset]), &l, sizeof(ULONG)); + EPro_Log_Offset+=sizeof(ULONG); +} + +VOID EProLogBuffer(UCHAR *s, ULONG len) +{ + if ((EPro_Log_Offset + len) >= EPRO_LOG_SIZE) { + EPro_Log_Offset = 0; + } + + NdisMoveMemory(&EPro_Log[EPro_Log_Offset], s, len); + EPro_Log_Offset+=len; +} + +#endif // IF DBG + + diff --git a/private/ntos/ndis/ieepro/eprodbg.h b/private/ntos/ndis/ieepro/eprodbg.h new file mode 100644 index 000000000..42d7fb721 --- /dev/null +++ b/private/ntos/ndis/ieepro/eprodbg.h @@ -0,0 +1,129 @@ +#ifndef _IEPRODBG_ +#define _IEPRODBG_ + +//////////////////////////////////////////////////////////// +// Debug +//////////////////////////////////////////////////////////// +#if DBG + +extern BOOLEAN EPRO_TX_DBG_ON; +extern BOOLEAN EPRO_RX_DBG_ON; +extern BOOLEAN EPRO_INIT_DBG_ON; +extern BOOLEAN EPRO_REQ_DBG_ON; +extern BOOLEAN EPRO_INTERRUPT_DBG_ON; + +// comment these out if you want don't want DbgPrint's compiling in at all +// or set the global variables in epro.c if you just want +// to turn them on or off... +#define EPRO_DEBUG_TX +#define EPRO_DEBUG_RX +#define EPRO_DEBUG_INIT +#define EPRO_DEBUG_REQ +#define EPRO_DEBUG_INTERRUPT + +// If you want a dump of the EPro's EEPROM for some reason +// uncomment the following line. The EEPROM will be dumped +// to the kernel debugger during driver initialization... +//#define EPRO_DUMP_EEPROM + +#define EPRO_ASSERT(expression) { \ + if ((!(expression))) { \ + DbgPrint("Assertion failed: %s, at line %d in file %s\n", \ + #expression, __LINE__, __FILE__); \ + DbgBreakPoint(); \ + } \ +} + +// TRANSMIT debugging +#ifdef EPRO_DEBUG_TX +# define EPRO_DPRINTF_TX(a) { \ + if (EPRO_TX_DBG_ON) \ + DbgPrint a; \ + } +#else +# define EPRO_DPRINTF_TX(a) +#endif + +// RECEIVE debugging +#ifdef EPRO_DEBUG_RX +# define EPRO_DPRINTF_RX(a) { \ + if (EPRO_RX_DBG_ON) \ + DbgPrint a; \ + } +#else +# define EPRO_DPRINTF_RX(a) +#endif + +// INIT debugging +#ifdef EPRO_DEBUG_INIT +# define EPRO_DPRINTF_INIT(a) { \ + if (EPRO_INIT_DBG_ON) \ + DbgPrint a; \ + } +#else +# define EPRO_DPRINTF_INIT(a) +#endif + +// REQUEST debugging +#ifdef EPRO_DEBUG_REQ +# define EPRO_DPRINTF_REQ(a) { \ + if (EPRO_REQ_DBG_ON) \ + DbgPrint a; \ + } + +#else +# define EPRO_DPRINTF_REQ(a) +#endif + +// INTERRUPT debugging +#ifdef EPRO_DEBUG_INTERRUPT +# define EPRO_DPRINTF_INTERRUPT(a) { \ + if (EPRO_INTERRUPT_DBG_ON) \ + DbgPrint a; \ + } +#else +# define EPRO_DPRINTF_INTERRUPT(a) +#endif + + +#define EPRO_ASSERT_BANK_0(_adapter) { \ + UCHAR _result; \ + EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \ + EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK0); \ +} + +#define EPRO_ASSERT_BANK_1(_adapter) { \ + UCHAR _result; \ + EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \ + EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK1); \ +} + +#define EPRO_ASSERT_BANK_2(_adapter) { \ + UCHAR _result; \ + EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &_result); \ + EPRO_ASSERT((_result & I82595_CUR_BANK_MASK) == I82595_CMD_BANK2); \ +} + +#else // ifdef DEBUG + +#define EPRO_ASSERT(expression) + +#define EPRO_ASSERT_BANK_0(_adapter) +#define EPRO_ASSERT_BANK_1(_adapter) +#define EPRO_ASSERT_BANK_2(_adapter) + +#define EPRO_DPRINTF_TX(a) +#define EPRO_DPRINTF_RX(a) +#define EPRO_DPRINTF_INIT(a) +#define EPRO_DPRINTF_REQ(a) +#define EPRO_DPRINTF_INTERRUPT(a) +#define EPRO_LOG_INIT(a) +#define EPRO_LOG_TX(a) +#define EPRO_LOG_RX(a) +#define EPRO_LOG_REQ(a) +#define EPRO_LOG_INTERRUPT(a) + +#endif // ifdef DEBUG + + +#endif diff --git a/private/ntos/ndis/ieepro/eprohw.h b/private/ntos/ndis/ieepro/eprohw.h new file mode 100644 index 000000000..fb1678e66 --- /dev/null +++ b/private/ntos/ndis/ieepro/eprohw.h @@ -0,0 +1,202 @@ +#ifndef _IEPROHW_ +#define _IEPROHW_ + +#define EPRO_LENGTH_OF_ADDRESS 6 + +//////////////////////////////////////////////////////////// +// Bank Switches +//////////////////////////////////////////////////////////// +#define EPRO_GOTO_B0 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK0) +#define EPRO_GOTO_B1 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK1) +#define EPRO_GOTO_B2 EPRO_WRITE_UCHAR(epro_cmd_reg, EPRO_CMD_BANK2) + +//////////////////////////////////////////////////////////// +// Port I/O +//////////////////////////////////////////////////////////// +#define EPRO_READ_UCHAR(_Port, _pValue) \ + NdisRawReadPortUchar( \ + (ULONG)(_Port), \ + (PUCHAR)(_pValue) \ + ) + +#define EPRO_READ_USHORT(_Port, _pValue) \ + NdisRawReadPortUshort( \ + (ULONG)(_Port), \ + (PUSHORT)(_pValue) \ + ) + +#define EPRO_WRITE_UCHAR(_Port, _Value) \ + NdisRawWritePortUchar( \ + (ULONG)(_Port), \ + (UCHAR) (_Value) \ + ) + +//////////////////////////////////////////////////////////// +// Command Macros +// Care must be taken to ensure you are in the right bank +//////////////////////////////////////////////////////////// + +// Memory I/O +#define EPRO_MEM_READADDR(_pValue) \ + EPRO_READ_USHORT(EPro_IOBaseAddress + EPRO_HOST_ADDR_REG, _pValue) + +#define EPRO_MEM_WRITEADDR(_Value) \ + EPRO_WRITE_USHORT(EPro_IOBaseAddress + EPRO_HOST_ADDR_REG, Value) + +#define EPRO_MEM_READSHORT(_pValue) \ + EPRO_READ_USHORT(EPro_IOBaseAddress + EPRO_MEM_IO_REG) + +#define EPRO_MEM_WRITESHORT(_Value) \ + EPRO_WRITE_USHORT(EPro_IOBaseAddress + EPRO_MEM_IO_REG) + +//BOOLEAN EProMemcpyW(void *pMainMemSrc_, void *OnBoardDest_, UINT count); +//BOOLEAN EProMemcpyR(void *OnBoardSrc_, void *pMainMemDest_, UINT count); + +//////////////////////////////////////////////////////////// +// TX Defines +//////////////////////////////////////////////////////////// +#define EPRO_NUM_TX_BUFFERS 30 +#define EPRO_TX_FIRST_BUF_START 0 + +// 1514 bytes ethernet frame +// 16 bytes epro header +// 2 bytes pad for word alignment +//#define EPRO_BUFFER_LEN 1532 + +#define EPRO_TRANSMIT_HEADER_SHORT1 (USHORT)I82595_XMT +#define EPRO_TRANSMIT_HEADER_SHORT2 (USHORT)0x0 + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// + +#define EPRO_REGISTRY_INTERRUPT_STRING NDIS_STRING_CONST("INTERRUPT") +#define EPRO_REGISTRY_IOADDRESS_STRING NDIS_STRING_CONST("IOADDRESS") +#define EPRO_REGISTRY_OLDIOADDRESS_STRING NDIS_STRING_CONST("OLDIOADDRESS") +#define EPRO_REGISTRY_BUSTYPE_STRING NDIS_STRING_CONST("BusType") +#define EPRO_REGISTRY_TRANSCEIVER_STRING NDIS_STRING_CONST("Transceiver") +#define EPRO_REGISTRY_IOCHRDY_STRING NDIS_STRING_CONST("IoChannelReady") + +#define EPRO_IOCHRDY_EARLY 0x01 +#define EPRO_IOCHRDY_LATE 0x02 +#define EPRO_IOCHRDY_NEVER 0x03 +#define EPRO_IOCHRDY_AUTO 0x04 + +//////////////////////////////////////////////////////////// +// Capabilities/Statistics about the EPRO card +//////////////////////////////////////////////////////////// + +#define EPRO_VENDOR_ID_L 0x00 +#define EPRO_VENDOR_ID_M 0xaa +#define EPRO_VENDOR_ID_H 0x00 + +#define EPRO_GEN_MEDIA_SUPPORTED NdisMedium802_3 +#define EPRO_GEN_MEDIA_IN_USE NdisMedium802_3 +#define EPRO_GEN_MAXIMUM_LOKAHEAD 256 +#define EPRO_GEN_MAXIMUM_FRAME_SIZE 1500 +#define EPRO_GEN_MAXIMUM_TOTAL_SIZE 1514 +#define EPRO_MAX_MULTICAST 64 +#define EPRO_GEN_MAC_OPTIONS (NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA | \ + NDIS_MAC_OPTION_RECEIVE_SERIALIZED | \ + NDIS_MAC_OPTION_NO_LOOPBACK) +#define EPRO_GEN_LINK_SPEED 100000 +#define EPRO_GEN_RECEIVE_BUFFER_SPACE (0x8000 - 0x3000) +#define EPRO_TX_BUF_SIZE 1514 +#define EPRO_RX_BUF_SIZE 0 +#define EPRO_GEN_TRANSMIT_BUFFER_SPACE EPRO_TX_BUF_SIZE * EPRO_NUM_TX_BUFFERS +#define EPRO_VENDOR_DESC "Intel EtherExpress PRO" + + +//////////////////////////////////////////////////////////// +// EPro EEPROM defines +//////////////////////////////////////////////////////////// +#define EPRO_SK_STALL_TIME 1000 // use 1000 microsecs + +#define EPRO_ETHERNET_ADDR_H 0x2 +#define EPRO_ETHERNET_ADDR_M 0x3 +#define EPRO_ETHERNET_ADDR_L 0x4 + +#define EPRO_EEPROM_CONFIG_OFFSET 0 +#define EPRO_EEPROM_CONFIG1_OFFSET 1 + +// word 0 on the eeprom +#define EPRO_EEPROM_IOADDR_BITPOS 0x0a // bits 10-15 +#define EPRO_EEPROM_IOADDR_MASK 0xfc00 +#define EPRO_EEPROM_AUTO_IO_ENABLE_MASK 0x0040 +#define EPRO_EEPROM_HOST_BUS_WD_MASK 0x0004 +#define EPRO_EEPROM_PNP_ENABLE_MASK 0x0001 + +// word 1 on the eeprom. RM: Due to chenges for eeprom stepping 4, we +// have additional masks. For simplicity's sake, stepping 4 masks +// are prefixed with the '4' (even if there is no other stepping +// equivalent INT for that IRQ). +#define EPRO_EEPROM_IRQ_MASK 0x000f +#define EPRO_EEPROM_IRQ_2_MASK 0x0 +#define EPRO_EEPROM_IRQ_3_MASK 0x1 +#define EPRO_EEPROM4_IRQ_3_MASK 0x0 +#define EPRO_EEPROM4_IRQ_4_MASK 0x1 +#define EPRO_EEPROM_IRQ_5_MASK 0x2 +#define EPRO_EEPROM4_IRQ_7_MASK 0x3 +#define EPRO_EEPROM4_IRQ_9_MASK 0x4 +#define EPRO_EEPROM_IRQ_10_MASK 0x3 +#define EPRO_EEPROM4_IRQ_10_MASK 0x5 +#define EPRO_EEPROM_IRQ_11_MASK 0x4 +#define EPRO_EEPROM4_IRQ_11_MASK 0x6 +#define EPRO_EEPROM4_IRQ_12_MASK 0x7 + + +//////////////////////////////////////////////////////////// +// TX/RX buffers +//////////////////////////////////////////////////////////// +#define EPRO_TX_LOWER_LIMIT 0x00 +#define EPRO_TX_UPPER_LIMIT 0x27 + +#define EPRO_TX_LOWER_LIMIT_SHORT 0x0000 +#define EPRO_TX_UPPER_LIMIT_SHORT 0x2800 + +#define EPRO_RX_LOWER_LIMIT 0x28 +#define EPRO_RX_UPPER_LIMIT 0x7f + +#define EPRO_RX_LOWER_LIMIT_SHORT 0x2800 +#define EPRO_RX_UPPER_LIMIT_SHORT 0x8000 + +//////////////////////////////////////////////////////////// +// Configuration Defaults +//////////////////////////////////////////////////////////// +//#define EPRO_CONFIG_1 0xa0 // a0 +#define EPRO_CONFIG_1 0xe0 // a0 +#define EPRO_CONFIG_2 0x16 // no broadcast + +// 4 different ones depending on the transceiver setting... +#define EPRO_CONFIG_3_AUI 0x10 +#define EPRO_CONFIG_3_BNC 0x34 +#define EPRO_CONFIG_3_TPE 0x14 +#define EPRO_CONFIG_3_AUTO 0x00 + +#define EPRO_NO_RX_STP_INTERRUPTS 0x01 +#define EPRO_NO_RX_INTERRUPTS 0x02 +#define EPRO_NO_TX_INTERRUPTS 0x04 +#define EPRO_NO_EXEC_INTERRUPTS 0x08 + +#define EPRO_DEFAULT_INTERRUPTS 0x09 // RX and TX +#define EPRO_ALL_INTERRUPTS 0x0f +#define EPRO_RX_TX_EXE_INTERRUPTS 0x01 + +//////////////////////////////////////////////////////////// +// Various states for our ISR +//////////////////////////////////////////////////////////// +#define EPRO_INT_NONE_PENDING 0 +//#define EPRO_INT_IN_SETUP 1 +//#define EPRO_INT_RESET_PENDING 2 +//#define EPRO_INT_SET_PENDING 3 +#define EPRO_INT_MC_SET_PENDING 4 + +//////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////// +// How long do we wait for a TX to free up before we +// consider ourselves hung? +#define EPRO_TX_TIMEOUT 10000 // 10000 usec right now + +#endif // _IEPROHW_ + diff --git a/private/ntos/ndis/ieepro/eprosw.h b/private/ntos/ndis/ieepro/eprosw.h new file mode 100644 index 000000000..421824dee --- /dev/null +++ b/private/ntos/ndis/ieepro/eprosw.h @@ -0,0 +1,254 @@ +#ifndef _IEPROSW_ +#define _IEPROSW_ + +#define EPRO_NDIS_MAJOR_VERSION 3 +#define EPRO_NDIS_MINOR_VERSION 0 +#define EPRO_USE_32_BIT_IO + +//////////////////////////////////////////////////////////// +// Internal data structures used by the driver... +//////////////////////////////////////////////////////////// +// do i really need this? +typedef struct EPRO_DRIVER { + NDIS_HANDLE EProWrapperHandle; +} EPRO_DRIVER, *PEPRO_DRIVER; + + +//////////////////////////////////////////////////////////// +typedef struct _EPRO_TRANSMIT_BUFFER { +// This is basically to make computing the next and last buffer +// faster... Maybe saves us a few instructions, but makes a +// lot of code a lot easier to read... + struct _EPRO_TRANSMIT_BUFFER *LastBuf; + struct _EPRO_TRANSMIT_BUFFER *NextBuf; + + BOOLEAN fEmpty; // TRUE if this is an empty buffer, + +// This is valid iff !fEmpty + PNDIS_PACKET TXPacket; + +// These are addresses ON THE NIC + USHORT TXBaseAddr; + USHORT TXSendAddr; +// USHORT TXBottomAddr; + USHORT TXSize; +} EPRO_TRANSMIT_BUFFER, *PEPRO_TRANSMIT_BUFFER; + +//////////////////////////////////////////////////////////// +// The header is supposed to be "compatible with the 8595tx' +// transmit buffer structure. Whatever. +typedef struct _EPRO_MC_HEADER { + UCHAR CommandField; + UCHAR NullBytes[5]; + +// do it this way for endian-safety + UCHAR ByteCountLo; + UCHAR ByteCountHi; +} EPRO_MC_HEADER, *PEPRO_MC_HEADER; + +//////////////////////////////////////////////////////////// +typedef struct _EPRO_MC_ADDRESS { + UCHAR AddrByte[EPRO_LENGTH_OF_ADDRESS]; +} EPRO_MC_ADDRESS, *PEPRO_MC_ADDRESS; + +//////////////////////////////////////////////////////////// +// These are the structures to be copied onto the NIC -- they +// are documented in the 82595 documentation +typedef struct _EPRO_TX_FRAME_HEADER { +// High dword + UCHAR XmitOp; + UCHAR NULLByte; + UCHAR Status0; + UCHAR Status1; +// Low dword + UCHAR XMTChainLo; + UCHAR XMTChainHi; +} EPRO_TX_FRAME_HEADER, *PEPRO_TX_FRAME_HEADER; + +//////////////////////////////////////////////////////////// +// Same as above... +typedef struct _EPRO_RCV_HEADER { + UCHAR Event; + UCHAR NullByte; + UCHAR Status0; + UCHAR Status1; + UCHAR NextFrmLo; + UCHAR NextFrmHi; + UCHAR ByteCountLo; + UCHAR ByteCountHi; +} EPRO_RCV_HEADER, *PEPRO_RCV_HEADER; + +//////////////////////////////////////////////////////////// +// This is an ETHERNET 802.3 frame header. +typedef struct _EPRO_ETH_HEADER { + UCHAR DestAddress[EPRO_LENGTH_OF_ADDRESS]; + UCHAR SourceAddress[EPRO_LENGTH_OF_ADDRESS]; + USHORT Length; +} EPRO_ETH_HEADER, *PEPRO_ETH_HEADER; + +//////////////////////////////////////////////////////////// +// This is the context that gets passed to EProTransferData +// through NdisMIndicateReceive +typedef struct _EPRO_RCV_CONTEXT { + USHORT RXCurrentAddress; + USHORT RXFrameSize; + USHORT LookAheadSize; +} EPRO_RCV_CONTEXT, *PEPRO_RCV_CONTEXT; + +//////////////////////////////////////////////////////////// +// The EPro adapter structure... +typedef struct EPRO_ADAPTER { + NDIS_HANDLE MiniportAdapterHandle; + NDIS_MINIPORT_INTERRUPT Interrupt; +// NDIS_MINIPORT_TIMER MiniportTimer; + PVOID IoBaseAddr; + ULONG TransceiverType; + ULONG IoPAddr; // Returned by NdisMRegisterIoPortRange - handle to mapped ports + ULONG IoChannelReady; + // What version of 82595 is this? + ULONG EProStepping; + // Can we use 32-bit IO? (ie is this a new enough version of the 82595 + // chip?) + BOOLEAN EProUse32BitIO; + + ULONG CurrentHardwareStatus; + // what is our current packet filter? + ULONG CurrentPacketFilter; + // are promiscuous receptions currently enabled? + BOOLEAN fPromiscuousEnable; + // are broadcast receptions currently enabled? + BOOLEAN fBroadcastEnable; + // are multicast receptions currently enabled? + BOOLEAN fMulticastEnable; + // are we hung? NOTUSED + BOOLEAN fHung; + // are receives currently enabled? + BOOLEAN fReceiveEnabled; + // do we really need this? +// BOOLEAN fTransmitInProgress; + +// statistics + ULONG FramesXmitOK; + ULONG FramesRcvOK; + ULONG FramesXmitErr; + ULONG FramesRcvErr; + ULONG FramesMissed; + ULONG FrameAlignmentErrors; + ULONG FramesXmitOneCollision; + ULONG FramesXmitManyCollisions; + +// transmit info + // these are our transmit buffers - structures which basically + // keep track of what frames are where in the NIC's memory. + EPRO_TRANSMIT_BUFFER TXBuf[EPRO_NUM_TX_BUFFERS]; + // this is the first free transmit buffer pointer. + PEPRO_TRANSMIT_BUFFER CurrentTXBuf; + // This is the frame that is currently in the process of + // being transmitted onto the wire. + PEPRO_TRANSMIT_BUFFER TXChainStart; + +// Multicast info + UCHAR MCAddress[EPRO_MAX_MULTICAST][EPRO_LENGTH_OF_ADDRESS]; + // how many mc addresses are currently set? + USHORT NumMCAddresses; + +// receive info + // how big is our lookahead buffer currently? + USHORT RXLookAheadSize; + // our lookahead buffer data + UCHAR RXLookAhead[EPRO_GEN_MAXIMUM_LOKAHEAD]; + // what address ON THE NIC are we currently receiveing at? + // ie where do we check when we get a receive interrupt. + USHORT RXCurrentAddress; + + // Is there an exec int pending? If so, why? + // right now only used to resolve pended set-mc calls... + ULONG IntPending; + // This is our context for a pended set-mc call + PVOID IntContext; + // set based on result of IOCHRDY test + BOOLEAN Use8Bit; + // set in ReadConfigInfo + BOOLEAN UseDefaultAddress; + // the MAC address burned into the eeprom + UCHAR PermanentIndividualAddress[EPRO_LENGTH_OF_ADDRESS]; + // the address we are currently receiving at + UCHAR CurrentIndividualAddress[EPRO_LENGTH_OF_ADDRESS]; + // always 00 aa 00 for intel + UCHAR vendorID[3]; + + UCHAR InterruptNumber; + UCHAR BusType; + + // This is only used at initialization time + BOOLEAN fUpdateIOAddress; + PVOID OldIOAddress; + + UCHAR CurrentInterruptMask; +} EPRO_ADAPTER, *PEPRO_ADAPTER; + + +//////////////////////////////////////////////////////////// +// Sync contexts +//////////////////////////////////////////////////////////// +typedef struct _EPRO_COPYBUF_CONTEXT { + PEPRO_ADAPTER Adapter; + PVOID Buffer; + UINT Len; +} EPRO_COPYBUF_CONTEXT, *PEPRO_COPYBUF_CONTEXT; + +typedef struct _EPRO_SETINTERRUPT_CONTEXT { + PEPRO_ADAPTER Adapter; + UCHAR NewMask; +} EPRO_SETINTERRUPT_CONTEXT, *PEPRO_SETINTERRUPT_CONTEXT; + +typedef struct _EPRO_BRDPROM_CONTEXT { + PEPRO_ADAPTER Adapter; + UCHAR Reg2Flags; +} EPRO_BRDPROM_CONTEXT, *PEPRO_BRDPROM_CONTEXT; + + +//////////////////////////////////////////////////////////// +// Some macros for commonly used stuff.... + +#define EPRO_WR_PORT_UCHAR(adapter, port, ch) \ + NdisRawWritePortUchar(adapter->IoPAddr + port, ch) + +#define EPRO_RD_PORT_UCHAR(adapter, port, ch) \ + NdisRawReadPortUchar(adapter->IoPAddr + port, ch) + +#define EPRO_WR_PORT_USHORT(adapter, port, us) \ + NdisRawWritePortUshort(adapter->IoPAddr + port, us) + +#define EPRO_RD_PORT_USHORT(adapter, port, us) \ + NdisRawReadPortUshort(adapter->IoPAddr + port, us) + + +//////////////////////////////////////////////////////////// +// The EPro is a bank-switching card. These macros switch between the banks... +#define EPRO_SWITCH_BANK_0(adapter) \ + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK0) + +#define EPRO_SWITCH_BANK_1(adapter) \ + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK1) + +#define EPRO_SWITCH_BANK_2(adapter) \ + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_BANK2) + +// Set the Host Address Register (0,c) -- use this to set up the NIC address +// for PIO through the register via COPY_BUFFER macros. +#define EPRO_SET_HOST_ADDR(adapter, addr) \ + EPRO_WR_PORT_USHORT(adapter, I82595_HOST_ADDR_REG, addr); + +#define EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, buffer, len) \ + NdisRawWritePortBufferUshort((adapter->IoPAddr + I82595_MEM_IO_REG), \ + (buffer), \ + (len)) + +#define EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, buffer, len) \ + NdisRawReadPortBufferUshort((adapter->IoPAddr + I82595_MEM_IO_REG), \ + (buffer), \ + len) + + +#endif _IEPROSW_ diff --git a/private/ntos/ndis/ieepro/init.c b/private/ntos/ndis/ieepro/init.c new file mode 100644 index 000000000..b94ae0e02 --- /dev/null +++ b/private/ntos/ndis/ieepro/init.c @@ -0,0 +1,1418 @@ +#include <stdio.h> +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +NDIS_PHYSICAL_ADDRESS HighestAcceptableMax = + NDIS_PHYSICAL_ADDRESS_CONST(-1, -1); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT pDriverObject_, + IN PUNICODE_STRING RegistryPath_) +/*++ + Routine Description: + + This is the primary initialization routine for the EPRO driver. + It is simply responsible for the intializing the wrapper and registering + the Miniport driver. It then calls a system and architecture specific + routine that will initialize and register each adapter. + + Arguments: + + DriverObject - Pointer to driver object created by the system. + + RegistryPath - Path to the parameters for this driver in the registry. + + Return Value: + + The status of the operation. +--*/ +{ + // + // Receives the status of the NdisMRegisterMiniport operation. + // + NDIS_STATUS status; + + // + // Characteristics table for this driver. + // + NDIS_MINIPORT_CHARACTERISTICS EPro_Miniport_Char; + + // + // Handle for referring to the wrapper about this driver. + // + NDIS_HANDLE ndisWrapperHandle; + + // + // Initialize the wrapper. + // + NdisMInitializeWrapper( + &ndisWrapperHandle, + pDriverObject_, + RegistryPath_, + NULL); + + // + // Initialize the Miniport characteristics for the call to + // NdisMRegisterMiniport. + // + + // The major and minor version of the driver + EPro_Miniport_Char.MajorNdisVersion = EPRO_NDIS_MAJOR_VERSION; + EPro_Miniport_Char.MinorNdisVersion = EPRO_NDIS_MINOR_VERSION; + + // our various Miniport handlers + EPro_Miniport_Char.CheckForHangHandler = EProCheckForHang; + EPro_Miniport_Char.DisableInterruptHandler = EProDisableInterrupts; + EPro_Miniport_Char.EnableInterruptHandler = EProEnableInterrupts; + EPro_Miniport_Char.HaltHandler = EProHalt; + EPro_Miniport_Char.HandleInterruptHandler = EProHandleInterrupt; + EPro_Miniport_Char.InitializeHandler = EProInitialize; + EPro_Miniport_Char.ISRHandler = EProISR; + EPro_Miniport_Char.QueryInformationHandler = EProQueryInformation; + EPro_Miniport_Char.ReconfigureHandler = NULL; + EPro_Miniport_Char.ResetHandler = EProReset; + EPro_Miniport_Char.SendHandler = EProSend; + EPro_Miniport_Char.SetInformationHandler = EProSetInformation; + EPro_Miniport_Char.TransferDataHandler = EProTransferData; + + // register us as a miniport... + status = NdisMRegisterMiniport( + ndisWrapperHandle, + &EPro_Miniport_Char, + sizeof(EPro_Miniport_Char)); + + if (status != NDIS_STATUS_SUCCESS) + { + NdisTerminateWrapper(ndisWrapperHandle, NULL); + EPRO_DPRINTF_INIT(("DriverEntry UNSUCCESSFUL!\n")); + return STATUS_UNSUCCESSFUL; + } + + EPRO_DPRINTF_INIT(("EPro DriverEntry Successful!\n")); + + return(STATUS_SUCCESS); +} + +NDIS_STATUS EProInitialize( + OUT PNDIS_STATUS openErrorStatus, + OUT PUINT selectedMediumIndex, + IN PNDIS_MEDIUM mediumArray, + IN UINT mediumArraySize, + IN NDIS_HANDLE miniportAdapterHandle, + IN NDIS_HANDLE configurationHandle) +/*++ + + Routine Description: + + EProInitialize starts an adapter and registers resources with the + wrapper. + + Arguments: + + OpenErrorStatus - Extra status bytes for opening token ring adapters. + + SelectedMediumIndex - Index of the media type chosen by the driver. + + MediumArray - Array of media types for the driver to chose from. + + MediumArraySize - Number of entries in the array. + + MiniportAdapterHandle - Handle for passing to the wrapper when + referring to this adapter. + + ConfigurationHandle - A handle to pass to NdisOpenConfiguration. + + Return Values: + NDIS_STATUS_UNSUPPORTED_MEDIA - the wrapper tried to set a media + type we couldn't do + + NDIS_STATUS_SUCCESS - operation succeeded ok + + perhaps other error status returned from the NdisM calls.. + +--*/ +{ + PEPRO_ADAPTER adapter = NULL; + UINT i; + NDIS_STATUS status; + BOOLEAN fAllocatedAdapterMemory; + BOOLEAN fRegisteredIoPortRange; + + // + // Find the 802.3 medium type and return it to the wrapper... + // + for (i = 0; i < mediumArraySize; i++) + { + if (mediumArray[i] == NdisMedium802_3) + { + break; + } + } + + if (i == mediumArraySize) + { + return(NDIS_STATUS_UNSUPPORTED_MEDIA); + } + + // Return the correct medium to the wrapper + // + *selectedMediumIndex = i; + + fAllocatedAdapterMemory = FALSE; + fRegisteredIoPortRange = FALSE; + + do + { + // + // Allocate Memory for the Adapter Structure + // + status = NdisAllocateMemory( + (PVOID *)&adapter, + sizeof(EPRO_ADAPTER), + 0, + HighestAcceptableMax); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Failed to allocate memory for the EPRO adapter stucture\n")); + break; + } + + fAllocatedAdapterMemory = TRUE; + + // + // Zero the adapter structure. + // + NdisZeroMemory(adapter, sizeof(EPRO_ADAPTER)); + + // + // Set some initial values in the adapter structure... + // + EProInitializeAdapterData(adapter); + + // + // Save the miniport adapter handle for later + // + adapter->MiniportAdapterHandle = miniportAdapterHandle; + + // + // Read configuration information for this adapter + // + status = EProReadConfiguration(adapter, configurationHandle); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("EProReadConfiguration FAILED!\n")); + + break; + } + + // + // Register our adapter handler with the wrapper. + // + NdisMSetAttributes( + adapter->MiniportAdapterHandle, + (NDIS_HANDLE)adapter, + FALSE, + adapter->BusType); + + // + // Register the IO port range needed. + // + status = NdisMRegisterIoPortRange( + (PVOID *)(&adapter->IoPAddr), + adapter->MiniportAdapterHandle, + (ULONG)adapter->IoBaseAddr, + 0x10); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Could not register IO ports.\n")); + + break; + } + + fRegisteredIoPortRange = TRUE; + + // + // Initialize the hardware and enable the card... + // + status = EProInitialReset(adapter); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Failed Initial Reset\n")); + + break; + } + + // + // Now, the resetting is done - configure the hardware... + // + status = EProHWConfigure(adapter); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Failed to configure EPRO hardware\n")); + + break; + } + + // + // If we are a step 2 or 3 adapter then update the eeprom if + // necessary. RM: add stepping 4. + // + if ((adapter->EProStepping == 2) || (adapter->EProStepping == 3) || (adapter->EProStepping == 4)) + { + EProUpdateEEProm(adapter); + } + + // + // Make sure that we do not free resources. + // + fAllocatedAdapterMemory = FALSE; + fRegisteredIoPortRange = FALSE; + + } while (FALSE); + + if (fRegisteredIoPortRange) + { + NdisMDeregisterIoPortRange( + adapter->MiniportAdapterHandle, + (ULONG)adapter->IoBaseAddr, + 0x10, + (PVOID)adapter->IoPAddr); + } + + if (fAllocatedAdapterMemory) + { + NdisFreeMemory(adapter, sizeof(EPRO_ADAPTER), 0); + } + + return(status); +} + +VOID EProUpdateEEProm(IN PEPRO_ADAPTER adapter) +/*++ + + Routine Description: + + This routine is called after the card's configuration has been + read from the registry and after the card's IO ports have been + registered. Now we check the card's EEPROM and verify that the + configuration information in the registry matches that saved + in the EEPROM. If they DON'T match, we update the card's EEPROM + with the new info. Note that the registry always overrides the + info that is saved -- in fact the info saved on the card is never + used at all right now, except the IO address - it is always overriden + by defaults or the registry values. We just save it in case the user + boots to another OS or moves and re-installs the card (the detection + code DOES read the EEPROM-configured defaults, so a new install will + be interested in what we have set.) + + Arguments: + + adapter - pointer to our EPRO_ADAPTER structure + + Return Values: + + none + +--*/ +{ + USHORT reg0, reg1; + BOOLEAN fCardUse8Bit; + BOOLEAN fUpdateEEPROM = FALSE; + USHORT cardIrq; + + EProEERead(adapter, EPRO_EEPROM_CONFIG_OFFSET, ®0); + EProEERead(adapter, EPRO_EEPROM_CONFIG1_OFFSET, ®1); + + // + // check the force 8-bit setting... + // + fCardUse8Bit = !(reg0 & EPRO_EEPROM_HOST_BUS_WD_MASK); + if (fCardUse8Bit != adapter->Use8Bit) + { + fUpdateEEPROM = TRUE; + if (adapter->Use8Bit) + { + reg0 &= ~EPRO_EEPROM_HOST_BUS_WD_MASK; + } + else + { + reg0 |= EPRO_EEPROM_HOST_BUS_WD_MASK; + } + } + // + // check the IRQ + // + switch(reg1 & EPRO_EEPROM_IRQ_MASK) + { + case 0: + cardIrq = (adapter->EProStepping == 4)? 3 : 9; + break; + + case 1: + cardIrq = (adapter->EProStepping == 4)? 4 : 3; + break; + + case 2: + cardIrq = 5; + break; + + case 3: + cardIrq = (adapter->EProStepping == 4)? 7 : 10; + break; + + case 4: + cardIrq = (adapter->EProStepping == 4)? 9 : 11; + break; + + case 5: + cardIrq = (adapter->EProStepping == 4)? 10 : 5; + break; + + + case 6: + cardIrq = (adapter->EProStepping == 4)? 11 : 5; + break; + + case 7: + cardIrq = (adapter->EProStepping == 4)? 12 : 5; + break; + + + default: + cardIrq = 0xff; + break; + } + + EPRO_DPRINTF_INIT(("EEPROM Interrupt Number: 0x%x\n", cardIrq)); + + if (cardIrq != adapter->InterruptNumber) + { + EPRO_DPRINTF_INIT(("Changing EEPROM to interrupt number 0x%x\n", adapter->InterruptNumber)); + fUpdateEEPROM = TRUE; + reg1 &= ~EPRO_EEPROM_IRQ_MASK; + // + // RM: in the following, some INTs are different for stepping 4. + // Unsupported ints default to IRQ 5. IRQ 2 and 9 are INT 0 for stepping 2/3. + // + switch(adapter->InterruptNumber) + { + case 2: + case 9: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_9_MASK : EPRO_EEPROM_IRQ_2_MASK; + break; + + case 3: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_3_MASK : EPRO_EEPROM_IRQ_3_MASK; + break; + + case 4: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_4_MASK : EPRO_EEPROM_IRQ_5_MASK; + break; + + case 5: + reg1 |= EPRO_EEPROM_IRQ_5_MASK; + break; + + case 7: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_7_MASK : EPRO_EEPROM_IRQ_5_MASK; + break; + + case 10: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_10_MASK : EPRO_EEPROM_IRQ_10_MASK; + break; + + case 11: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_11_MASK : EPRO_EEPROM_IRQ_11_MASK; + break; + + case 12: + reg1 |= (adapter->EProStepping == 4)? EPRO_EEPROM4_IRQ_12_MASK : EPRO_EEPROM_IRQ_5_MASK; + break; + + default: + reg1 |= EPRO_EEPROM_IRQ_5_MASK; + break; + } + + EPRO_DPRINTF_INIT(("EEPROM interrupt mask 0x%x\n", reg1 & EPRO_EEPROM_IRQ_MASK)); + } + + if (fUpdateEEPROM) + { + EProEEWrite(adapter, EPRO_EEPROM_CONFIG_OFFSET, reg0); + EProEEWrite(adapter, EPRO_EEPROM_CONFIG1_OFFSET, reg1); + EProEEUpdateChecksum(adapter); + } +} + +NDIS_STATUS +EProReadConfiguration( + IN PEPRO_ADAPTER adapter, + IN NDIS_HANDLE configurationHandle + ) +/*++ + + Routine Description: + + Read card config info from the registry and set the values + in the adapter structure + + Arguments: + + adapter - pointer to our adapter structure + + configurationHandle - a handle to a place in the registry we can + read our settings from + + Return Values: + +--*/ +{ + NDIS_STATUS status; + NDIS_HANDLE configHandle; + PNDIS_CONFIGURATION_PARAMETER returnedValue; + + // These are the keys we read from the registry.. + // + NDIS_STRING interruptNumberString = EPRO_REGISTRY_INTERRUPT_STRING; + + // I/O Port Base Address + // + NDIS_STRING ioAddressString = EPRO_REGISTRY_IOADDRESS_STRING; + + // OLD I/O Base Address + // + NDIS_STRING oldIOAddressString = EPRO_REGISTRY_OLDIOADDRESS_STRING; + + // bus type + // + NDIS_STRING busTypeString = EPRO_REGISTRY_BUSTYPE_STRING; + + // Transceiver Type + // + NDIS_STRING transceiverString = EPRO_REGISTRY_TRANSCEIVER_STRING; + + // Io Channel Ready + // + NDIS_STRING IoChannelReadyString = EPRO_REGISTRY_IOCHRDY_STRING; + + // Open the configuration file... + // + NdisOpenConfiguration( + &status, + &configHandle, + configurationHandle); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("EProReadConfiguration - failed in NdisOpenConfiguration\n")); + NdisFreeMemory(adapter, sizeof(adapter),0); + return(status); + } + + // right now we'll just assume it's an isa card... + // + adapter->BusType = NdisInterfaceIsa; + + // Do we need to update the IO base address? + // + adapter->fUpdateIOAddress = FALSE; + + // Read "Real" IO Base Address (the one we want to use) + // + NdisReadConfiguration(&status, + &returnedValue, + configHandle, + &ioAddressString, + NdisParameterHexInteger); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Error, can't find io address in registry...using default 0x300\n")); + adapter->IoBaseAddr = (PVOID)0x300; + } + else + { + adapter->IoBaseAddr = (PVOID)(returnedValue->ParameterData.IntegerData); + } + + if ((adapter->IoBaseAddr > (PVOID)0x3f0) || (adapter->IoBaseAddr < (PVOID)0x200)) + { + EPRO_DPRINTF_INIT(("Bad io address set in registry. Using 0x300.\n")); + adapter->IoBaseAddr = (PVOID)0x300; + } + + // + // Read the InterruptNumber + // + NdisReadConfiguration( + &status, + &returnedValue, + configHandle, + &interruptNumberString, + NdisParameterHexInteger); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_REQ(("Error, can't read interrupt number from registry...using default\n")); + adapter->InterruptNumber = (CCHAR)5; + } + else + { + adapter->InterruptNumber = (CCHAR)(returnedValue->ParameterData.IntegerData); + } + + // oh, yah, what was I on when I wrote this? + switch (adapter->InterruptNumber) + { + case 3: + case 5: + case 9: + case 10: + case 11: + // 4, 7 & 12 valid for v4 chips +RM + case 4: + case 7: + case 12: + break; + + default: + adapter->InterruptNumber = (CCHAR)5; + } + + // + // Read the TransceiverType + // + NdisReadConfiguration( + &status, + &returnedValue, + configHandle, + &transceiverString, + NdisParameterHexInteger); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n")); + adapter->TransceiverType = (CCHAR)4; + } + else + { + adapter->TransceiverType = (CCHAR)(returnedValue->ParameterData.IntegerData); + } + + // + // Read the IoChannelReady Setting + // + NdisReadConfiguration( + &status, + &returnedValue, + configHandle, + &IoChannelReadyString, + NdisParameterHexInteger); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_REQ(("Error, can't read transceiver type from registry...using AUTO\n")); + adapter->IoChannelReady = (CCHAR)4; // auto-detect is default + } + else + { + adapter->IoChannelReady = (CCHAR)(returnedValue->ParameterData.IntegerData); + } + + // + // See if a MAC address has been specified in the registry to + // override our hardware-set one. + // + { + UINT addrLen; + PUCHAR netAddr; + NDIS_STATUS status; + + // + // attempt to read the network address + // + NdisReadNetworkAddress( + &status, + &netAddr, + &addrLen, + configHandle); + + // did the operation succeed? + // + if (status == NDIS_STATUS_SUCCESS) + { + adapter->UseDefaultAddress = FALSE; + + // yes: use this address. + // + NdisMoveMemory( + &adapter->CurrentIndividualAddress, + netAddr, + EPRO_LENGTH_OF_ADDRESS); + } + else + { + // just use the one out of the eeprom + adapter->UseDefaultAddress = TRUE; + } + } + + + // Close the configuration file... + // + NdisCloseConfiguration(configHandle); + + return(NDIS_STATUS_SUCCESS); +} + +NDIS_STATUS EProInitialReset(PEPRO_ADAPTER adapter) +/*++ + + Routine Description: + + This call really does two things: first, it calls + EProHWInitialize to set up the hardware, and then it + registers the card's interrupt and starts the card going. + + Arguments: + + adapter - pointer to our adapter structure... + + Return Values: + +--*/ +{ + NDIS_STATUS status; + + status = EProHWInitialize(adapter); + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("FAILED in EProHWInitialize.\n")); + return(status); + } + + switch (adapter->IoChannelReady) + { + case EPRO_IOCHRDY_EARLY: + EPRO_DPRINTF_INIT(("EPro configured for EARLY IoChannelReady\n")); + break; + + case EPRO_IOCHRDY_LATE: + EPRO_DPRINTF_INIT(("EPro configured for LATE IoChannelReady\n")); + break; + + case EPRO_IOCHRDY_NEVER: + // They've set this in the cpanel - force 8 bits + // + EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n")); + adapter->Use8Bit = TRUE; + break; + + case EPRO_IOCHRDY_AUTO: + default: + + EPRO_DPRINTF_INIT(("EPro configured for AUTO IoChannelReady\n")); + + if (adapter->EProStepping < 4) //RM: don't do rev 4 + { + if (!EProAltIOCHRDYTest(adapter)) + { + EPRO_DPRINTF_INIT(("EPro failed the IOCHRDY test. Forcing 8-bit operation\n")); + + // configure for 8-bit operation + // + EPRO_DPRINTF_INIT(("EPro configured for NEVER IoChannelReady\n")); + adapter->Use8Bit = TRUE; + } + } + break; + } + + return(status); +} + +NDIS_STATUS +EProHWInitialize( + IN PEPRO_ADAPTER adapter + ) +/*++ + + Routine Description: + + Now we start dealing with the card. Probe and verify its + existence, try to power it up if necessary, init it, etc. + + Arguments: + + adapter - pointer to our adapter structure + + Return Values: + +--*/ +{ + UCHAR buf[4], fExecDone, result, intReg; + UINT i; + + // Make sure we're in bank 0 + // + EPRO_SWITCH_BANK_0(adapter); + + for (i = 0; i < 4; i++) + { + EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]); + } + + if (!EProVerifyRoundRobin(buf)) + { + // + // hmm, didn't find the board. Try powering it up, then try again. + // It's concievable that the board was in its "powered down" state + // and so we try the powerup procedure as a last-ditch effort. + // + EPRO_DPRINTF_INIT(("Initial probe failing. Attempting to power board up.\n")); + if (!EProPowerupBoard(adapter)) + { + EPRO_DPRINTF_INIT(("Couldn't power board up. Can't find board.\n")); + return(NDIS_STATUS_HARD_ERRORS); + } + } + + // Do a full reset. + // + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_FULL_RESET); + + // poll for the card to be done it's init sequence. + // + for (i = 0; i < 10000; i++) + { + EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &intReg); + + if (intReg & I82595_EXEC_INT_RCVD) + break; + + NdisStallExecution(10); + } + + if (i >= 10000) + { + EPRO_DPRINTF_INIT(("EPRO: Did NOT get return from init....\n")); + return(NDIS_STATUS_SOFT_ERRORS); + } + + + // According to the docs, writing a _1_ to the execution int bit + // clears it -- so we can just overwrite it to clear it. + // + EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, intReg); + + return(NDIS_STATUS_SUCCESS); +} + +NDIS_STATUS +EProHWConfigure( + IN PEPRO_ADAPTER adapter + ) +/*++ + + Routine Description: + + The second half of the init -- now the hardware has just been + told to reset. Wait for the reset to finish, then configure + the board... + + Arguments: + + adapter - pointer to our adapter structure + + Return Values: + +--*/ +{ + UCHAR result, intReg; + NDIS_STATUS status; + UINT i; + UCHAR intMask; + + EPRO_DPRINTF_INIT(("EPRO: In EProHWConfigure\n")); + + // + // Configure the adapter + // + EPRO_SWITCH_BANK_0(adapter); + + // + // These two lines are a blatant hack to get around some timing + // problems I was having in the init sequence. + // + EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result); + NdisStallExecution(1000); + + if (!EProWaitForExeDma(adapter)) + { + return(NDIS_STATUS_HARD_ERRORS); + } + + // Set the 82595's config registers up for the driver. + // RM: Moved this up here so we have the chip version upfront. + + // + // Switch to bank2 for configuration + // + EPRO_SWITCH_BANK_2(adapter); + + // + // Get 82595 chip version. + // + EPRO_RD_PORT_UCHAR(adapter, I82595_STEPPING_REG, &result); + adapter->EProStepping = (result >> I82595_STEPPING_OFFSET); + + EPRO_DPRINTF_INIT(("This is a level %x 82595\n", adapter->EProStepping)); + + if (adapter->EProStepping < 2) + { + adapter->EProUse32BitIO = FALSE; + EPRO_DPRINTF_INIT(("NOT using 32-bit I/O port.\n")); + } + else if (adapter->EProStepping > 4) //RM: included rev 4 + { + // + // We don't support this step of the adapter! + // + EPRO_DPRINTF_INIT(("Do not support step %u epro's\n", adapter->EProStepping)); + return(NDIS_STATUS_HARD_ERRORS); + } + else + { + // + // Step is 2, 3 or 4. + // + adapter->EProUse32BitIO = TRUE; + EPRO_DPRINTF_INIT(("using 32-bit I/O port.\n")); + } + + // + // Set configuration register 1 in bank 2 + // + EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG1_REG, EPRO_CONFIG_1); + + // + // Set the transceiver type... + // + EPRO_DPRINTF_INIT(("EPRO: Transceiver type is 0x%x\n", + adapter->TransceiverType)); + + switch (adapter->TransceiverType) + { + case 1: + result = EPRO_CONFIG_3_AUI; + break; + + case 2: + result = EPRO_CONFIG_3_BNC; + break; + + case 3: + result = EPRO_CONFIG_3_TPE; + break; + + case 4: + default: + result = EPRO_CONFIG_3_AUTO; + break; + } + + EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG2_REG, EPRO_CONFIG_2); + EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG3_REG, result); + + // + // Switch to Bank1 + // + EPRO_SWITCH_BANK_1(adapter); + + if (adapter->EProStepping < 4) //Alt Ready timing reg n/a in rev 4 -- + // included in EEPROM for back-compat only + { + + // + // Configure the card's IOCHRDY setting if we're forcing it + // + if (adapter->IoChannelReady == EPRO_IOCHRDY_EARLY) + { + // + // force EARLY (alternate) timing + // + EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result); + result |= I82595_ALT_IOCHRDY; + EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result); + } + + // + // Configure the card's IOCHRDY setting if we're forcing it + // + if (adapter->IoChannelReady == EPRO_IOCHRDY_LATE) + { + // + // Force LATE (isa compatible) timing + // + EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result); + result &= ~I82595_ALT_IOCHRDY; + EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result); + } + } + // + // Do we have to use 8-bit? + // + if (adapter->Use8Bit) + { + EPRO_DPRINTF_INIT(("Using 8 bits\n")); + + EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result); + result &= ~I82595_USE_8_BIT_FLAG; + EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result); + } + + // + // Set the buffer limit registers... + // + EPRO_WR_PORT_UCHAR(adapter, I82595_TX_LOWER_LIMIT_REG, EPRO_TX_LOWER_LIMIT); + EPRO_WR_PORT_UCHAR(adapter, I82595_TX_UPPER_LIMIT_REG, EPRO_TX_UPPER_LIMIT); + + EPRO_WR_PORT_UCHAR(adapter, I82595_RX_LOWER_LIMIT_REG, EPRO_RX_LOWER_LIMIT); + EPRO_WR_PORT_UCHAR(adapter, I82595_RX_UPPER_LIMIT_REG, EPRO_RX_UPPER_LIMIT); + + // + // Tell the card what Interrupt to use, default to 5. RM: Added check for V4. + // Default bad IRQs to 5 (mask 2 for all steppings). + // + + switch (adapter->InterruptNumber) + { + case 3: + intMask = (adapter->EProStepping == 4)? 0x0 : 0x1; + break; + + case 4: + intMask = (adapter->EProStepping == 4)? 0x1 : 0x2; + break; + + case 5: + intMask = 0x2; + break; + + case 7: + intMask = (adapter->EProStepping == 4)? 0x3 : 0x2; + break; + + case 9: + // + // note that this is out of order - because the epro + // uses the 0 to indicate 2/9 (2 on an 8-bit bus in DOS mode + // and 9 otherwise...or something like that) Anyways, it is + // 9 under NT. + // + intMask = (adapter->EProStepping == 4)? 0x4 : 0x0; + break; + + case 10: + intMask = (adapter->EProStepping == 4)? 0x5 : 0x3; + break; + + case 11: + intMask = (adapter->EProStepping == 4)? 0x6 : 0x4; + break; + + case 12: + intMask = (adapter->EProStepping == 4)? 0x7 : 0x2; + break; + + default: + + EPRO_DPRINTF_INIT(("EPRO: invalid interrupt selected using interrupt 5.")); + intMask = 0x2; + break; + } + + EPRO_RD_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, &result); + + result &= ~(I82595_INTERRUPT_SELECT_MASK); + result |= intMask; + EPRO_WR_PORT_UCHAR(adapter, I82595_INT_SELECT_REG, result); + + // + // Read the card's ethernet address out of the eeprom. + // + if (!EProCardReadEthernetAddress(adapter)) + { + EPRO_DPRINTF_INIT(("EPRO: Could not read the EPro card's ethernet address.\n")); + return(NDIS_STATUS_SOFT_ERRORS); + } + + if (adapter->UseDefaultAddress == TRUE) + { + // + // Copy the permanent address to the current address + // + NdisMoveMemory( + &adapter->CurrentIndividualAddress, + &adapter->PermanentIndividualAddress, + EPRO_LENGTH_OF_ADDRESS); + } + + // + // Set the card's ethernet address to the one specified in + // adapter->current... + // + if (!EProSetEthernetAddress(adapter)) + { + return(NDIS_STATUS_SOFT_ERRORS); + } + + EPRO_SWITCH_BANK_1(adapter); + + // + // flip the interrupt tri-state bit... + // + EPRO_RD_PORT_UCHAR(adapter, I82595_INTENABLE_REG, &result); + result|=I82595_ENABLE_INTS_FLAG; + EPRO_WR_PORT_UCHAR(adapter, I82595_INTENABLE_REG, result); + + EPRO_SWITCH_BANK_0(adapter); + + if (!EProWaitForExeDma(adapter)) + { + return(NDIS_STATUS_SOFT_ERRORS); + } + + // + // bank0 + // + EPRO_SWITCH_BANK_0(adapter); + + // + // Set the interrupt mask... + // + adapter->CurrentInterruptMask = EPRO_DEFAULT_INTERRUPTS; + + // + // Register the interrupt. + // + status = NdisMRegisterInterrupt( + &adapter->Interrupt, + adapter->MiniportAdapterHandle, + adapter->InterruptNumber, + adapter->InterruptNumber, + FALSE, + FALSE, + NdisInterruptLatched); + + if (status != NDIS_STATUS_SUCCESS) + { + EPRO_DPRINTF_INIT(("Register Interrupts FAILED\n")); + return(status); + } + + // + // Enable interrupts... + // + EProEnableInterrupts((NDIS_HANDLE)adapter); + + EProSelReset(adapter); + + EPRO_DPRINTF_INIT(("EtherExpress Pro: configuration complete\n")); + + return(NDIS_STATUS_SUCCESS); +} + +BOOLEAN +EProVerifyRoundRobin( + IN UCHAR *buf + ) +/*++ + + Routine Description: + + This routine takes a sequence of 4 bytes passed in as the + result of 4 consecutive reads from the possible card's register + at address 2 (ie if base port is 0x300, 4 reads from 0x302) and + determines if the four constitute the EPro's ID signature. If they + do (epro identified) this returns TRUE, otherwise FALSE. + + The 7th and 8th bits of these 4 should count 00 01 10 11 or some + permutation.... + + NOTE - if this code changes (because of chip updates, whatever) make + sure you change this function in the net-detection code (this function + is cut-and-pasted into detepro.c) + + Arguments: + + buf - a 4-byte character array with the four results in it... + + Return Values: + + TRUE if this is the 82595's signature + FALSE if it is not. + +--*/ +{ + UCHAR ch; + int i, i1; + + // Don't even bother. This works, take my word for it. + // + i1 = buf[0] >> 6; + + for (i = 1; i < 4; i++) + { + i1 = (i1 > 2) ? 0 : i1 + 1; + if ((buf[i] >> 6) != i1) + { + return(FALSE); + } + } + + return(TRUE); +} + +BOOLEAN +EProPowerupBoard( + IN PEPRO_ADAPTER adapter + ) +/*++ + + Routine Description: + + The 82595 has a "powered down" state which could be why it didn't + respond correctly to the ID register probe. + + Try the power up sequence. Return TRUE if the board responds + after the sequence, FALSE otherwise. + + Arguments: + + adapter - pointer to our adapter structure + + Return Values: + + TRUE - if the board was found after the power up sequence + FALSE - if it was not + +--*/ +{ + UCHAR buf[4]; + UINT i; + + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, 0); + + // 32ms + // + NdisStallExecution(32000); + + // Make sure we're in bank 0 + // + EPRO_SWITCH_BANK_0(adapter); + + for (i = 0; i < 4; i++) + { + EPRO_RD_PORT_UCHAR(adapter, I82595_ID_REG, &buf[i]); + } + + return(EProVerifyRoundRobin(buf)); +} + +BOOLEAN +EProCardReadEthernetAddress( + IN PEPRO_ADAPTER adapter + ) +{ + USHORT data; + + // EPRO_DPRINTF_INIT(("EProReadEthernetAddress\n")); + +#ifdef EPRO_DUMP_EEPROM + // Dump the eeprom... + { + USHORT i; + + for (i = 0; i < 64; i++) + { + if ((i % 16) == 0) + { + DbgPrint("\n"); + } + + EProEERead(adapter, i, &data); + DbgPrint("%x ", data); + } + + DbgPrint("\n"); + } +#endif + + // + // Read the ethernet address out of the card. Also swap endian + // as you do it... + // + EProEERead(adapter, EPRO_ETHERNET_ADDR_H, &data); + adapter->PermanentIndividualAddress[4] = (UCHAR)(data >> 8); + adapter->PermanentIndividualAddress[5] = (UCHAR)(data & 0x00ff); + + EProEERead(adapter, EPRO_ETHERNET_ADDR_M, &data); + adapter->PermanentIndividualAddress[2] = (UCHAR)(data >> 8); + adapter->PermanentIndividualAddress[3] = (UCHAR)(data & 0x00ff); + + EProEERead(adapter, EPRO_ETHERNET_ADDR_L, &data); + adapter->PermanentIndividualAddress[0] = (UCHAR)(data >> 8); + adapter->PermanentIndividualAddress[1] = (UCHAR)(data & 0x00ff); + + EPRO_DPRINTF_INIT(("MAC address read: %x %x %x %x %x %x\n", + adapter->PermanentIndividualAddress[0], + adapter->PermanentIndividualAddress[1], + adapter->PermanentIndividualAddress[2], + adapter->PermanentIndividualAddress[3], + adapter->PermanentIndividualAddress[4], + adapter->PermanentIndividualAddress[5])); + + return(TRUE); +} + + +BOOLEAN EProSetEthernetAddress(PEPRO_ADAPTER adapter) +/*++ + + Routine Description: + + The EPro's ethernet address is read out of the EEPROM by the driver + in EProReadEthernetAddress. It is stored by the driver in the + adapter->PermanentIndividualAddress array. This function takes the + address stored there (presumably set by ReadEthernetAddress) and + configures the board to use that address. It could also be used + to software-override the default ethernet address. + + Note that the software does not support multiple IA addresses + (multiple non-multicast addresses) although the hardware does. + + Arguments: + + adapter - pointer to our adapter structure + + Return Value: + + TRUE if the operation was successful + FALSE if it failed + +--*/ +{ + UCHAR result; + UINT i = 0; + +// switch to bank2 + EPRO_SWITCH_BANK_2(adapter); + +// write out the ethernet address. Make sure you write to reg 9 last: + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_0, adapter->PermanentIndividualAddress[0]); + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_1, adapter->PermanentIndividualAddress[1]); + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_2, adapter->PermanentIndividualAddress[2]); + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_3, adapter->PermanentIndividualAddress[3]); + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_4, adapter->PermanentIndividualAddress[4]); + +// switch to bank0 + EPRO_SWITCH_BANK_0(adapter); + + if (!EProWaitForExeDma(adapter)) { + return(FALSE); + } + +// switch to bank2 + EPRO_SWITCH_BANK_2(adapter); + + EPRO_WR_PORT_UCHAR(adapter, I82595_IA_REG_5, adapter->PermanentIndividualAddress[5]); + + return(TRUE); +} + +BOOLEAN EProAltIOCHRDYTest(PEPRO_ADAPTER adapter) +/*++ + + Routine Description: + + Check the current IOCHRDY timing and see if it is compatible. + if not, see if it can be changed and made compatible + otherwise fail. + + Arguments: + + adapter - pointer to our adapter structure + + Return Values: + + TRUE if the card can be configured properly to the way the machine + machine asserts the IOCHRDY line. + + FALSE if the card could NOT be configured appropriately - the machine + is broken and we'll have to use 8-bit mode. + +--*/ +{ + BOOLEAN testPending = TRUE, testResult, firstTime = TRUE; + UCHAR result; + + // switch to bank 1 + EPRO_SWITCH_BANK_1(adapter); + + do + { + // Enter test mode... + EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result); + result |= I82595_IOCHRDY_TEST_FLAG; + EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result); + + // Read from 0,1 + EPRO_RD_PORT_UCHAR(adapter, I82595_CMD_REG, &result); + + EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result); + + if (result & I82595_IOCHRDY_PASS_FLAG) + { + testPending = FALSE; + testResult = TRUE; + } + else + { + // test failed + if (firstTime) + { + // try it again - flip the current IOCHRDY timing and try again. + firstTime = FALSE; + EPRO_RD_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, &result); + + // toggle alt-rdy bit + result = (result & I82595_ALT_RDY_FLAG)? + result & (~I82595_ALT_RDY_FLAG) : + result | I82595_ALT_RDY_FLAG; + + EPRO_WR_PORT_UCHAR(adapter, I82595_ALT_RDY_REG, result); + } + else + { + // nope, failed twice, can't do it. + testPending = FALSE; + testResult = FALSE; + } + } + } while (testPending); + + // turn the test off + EPRO_RD_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, &result); + result &= ~I82595_IOCHRDY_TEST_FLAG; + EPRO_WR_PORT_UCHAR(adapter, I82595_IOCHRDY_TEST_REG, result); + + return(testResult); +} + diff --git a/private/ntos/ndis/ieepro/makefile b/private/ntos/ndis/ieepro/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/ntos/ndis/ieepro/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 OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/ntos/ndis/ieepro/request.c b/private/ntos/ndis/ieepro/request.c new file mode 100644 index 000000000..995b8c0f2 --- /dev/null +++ b/private/ntos/ndis/ieepro/request.c @@ -0,0 +1,989 @@ +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +static UINT EProSupportedOids[] = { + 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_MAXIMUM_LIST_SIZE, + OID_802_3_MULTICAST_LIST, + OID_802_3_RCV_ERROR_ALIGNMENT, + OID_802_3_XMIT_ONE_COLLISION, + OID_802_3_XMIT_MORE_COLLISIONS +}; + +NDIS_STATUS EProQueryInformation(IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_OID oid, + IN PVOID informationBuffer, + IN ULONG informationBufferLength, + OUT PULONG bytesWritten, + OUT PULONG bytesNeeded) +/*++ + + Routine Description: + + This is the query configuration handler for the EPro + + Arguments: + + miniportAdapterContext - really a pointer to our adapter structure + + oid - the oid we are querying + + informationBuffer - The buffer to copy the queried info into + + informationLength - how much room is there in the buffer + + bytesWritten - the number of bytes we actually wrote into + informationBuffer + + bytesNeeded - only valid if we return not enough space error -- + how much more space do we need to be able to give + you that data? + + Return Values: + + NDIS_STATUS_SUCCESS - operation successful + NDIS_STATUS_INALID_OID - invalid oid, or we don't support it + NDIS_STATUS_INVALID_LENGTH - not enough room in informationbuffer + see bytesNeeded for more info + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + UINT bytesToMove = 0; + PVOID moveSource = NULL; +// since we can't transfer #define'd constants the way they want us to... + ULONG GenericUL; + USHORT GenericUS; + NDIS_STATUS statusToReturn = NDIS_STATUS_SUCCESS; + + EPRO_DPRINTF_REQ(("EProQueryInformation. Oid = %lx\n", oid)); + +// the oid's are documented in the DDK. See that for info on all of them + switch(oid) { + case OID_GEN_SUPPORTED_LIST: + EPRO_DPRINTF_REQ((" querying oid: OID_GEN_SUPPORTED_LIST\n")); + moveSource = &EProSupportedOids; + bytesToMove = sizeof(EProSupportedOids); + break; + case OID_GEN_HARDWARE_STATUS: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_HARDWARE_STATUS\n")); + moveSource = &adapter->CurrentHardwareStatus; + bytesToMove = sizeof(adapter->CurrentHardwareStatus); + break; + case OID_GEN_MEDIA_SUPPORTED: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MEDIA_SUPPORTED\n")); + GenericUL = EPRO_GEN_MEDIA_SUPPORTED; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_MEDIA_IN_USE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MEDIA_IN_USE\n")); + GenericUL = EPRO_GEN_MEDIA_IN_USE; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_MAXIMUM_LOOKAHEAD: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_LOOKAHEAD\n")); + GenericUL = EPRO_GEN_MAXIMUM_LOKAHEAD; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_MAXIMUM_FRAME_SIZE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_FRAME_SIZE\n")); + GenericUL = EPRO_GEN_MAXIMUM_FRAME_SIZE; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_MAXIMUM_TOTAL_SIZE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAXIMUM_TOTAL_SIZE\n")); + GenericUL = EPRO_GEN_MAXIMUM_TOTAL_SIZE; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_MAC_OPTIONS: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_MAC_OPTIONS\n")); + GenericUL = EPRO_GEN_MAC_OPTIONS; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_PROTOCOL_OPTIONS: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_PROTOCOL_OPTIONS\n")); + moveSource = NULL; + bytesToMove = 0; + break; + case OID_GEN_LINK_SPEED: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_LINK_SPEED\n")); + GenericUL = EPRO_GEN_LINK_SPEED; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_TRANSMIT_BUFFER_SPACE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_TRANSMIT_BUFFER_SPACE\n")); + GenericUL = EPRO_GEN_TRANSMIT_BUFFER_SPACE; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_RECEIVE_BUFFER_SPACE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RECEIVE_BUFFER_SPACE\n")); + GenericUL = EPRO_GEN_RECEIVE_BUFFER_SPACE; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_TRANSMIT_BLOCK_SIZE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_TRANSMIT_BLOCK_SIZE\n")); + GenericUL = EPRO_TX_BUF_SIZE; + moveSource = &GenericUL; + bytesToMove = sizeof(ULONG); + break; + case OID_GEN_RECEIVE_BLOCK_SIZE: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RECEIVE_BOCK_SIZE\n")); + GenericUL = EPRO_RX_BUF_SIZE; + moveSource = &GenericUL; + bytesToMove = sizeof(ULONG); + break; + case OID_GEN_VENDOR_ID: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_VENDOR_ID\n")); + moveSource = &adapter->vendorID; + bytesToMove = sizeof(adapter->vendorID); + break; + case OID_GEN_VENDOR_DESCRIPTION: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_VENDOR_DESCRIPTION\n")); + moveSource = EPRO_VENDOR_DESC; + bytesToMove = sizeof(EPRO_VENDOR_DESC); + break; + case OID_GEN_DRIVER_VERSION: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_DRIVER_VERSION\n")); + GenericUS = ((USHORT)EPRO_DRIVER_VER_MAJOR << 8) | + EPRO_DRIVER_VER_MINOR; + moveSource = &GenericUS; + bytesToMove = sizeof(GenericUS); + break; + case OID_GEN_CURRENT_PACKET_FILTER: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_CURRENT_PACKET_FILTER\n")); + moveSource = &adapter->CurrentPacketFilter; + bytesToMove = sizeof(adapter->CurrentPacketFilter); + break; + case OID_GEN_CURRENT_LOOKAHEAD: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_CURRENT_LOOKAHEAD\n")); + GenericUL = adapter->RXLookAheadSize; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_GEN_XMIT_OK: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_XMIT_OK\n")); + moveSource = &adapter->FramesXmitOK; + bytesToMove = sizeof(adapter->FramesXmitOK); + break; + case OID_GEN_RCV_OK: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_OK\n")); + moveSource = &adapter->FramesRcvOK; + bytesToMove = sizeof(adapter->FramesRcvOK); + break; + case OID_GEN_XMIT_ERROR: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_XMIT_ERROR\n")); + moveSource = &adapter->FramesXmitErr; + bytesToMove = sizeof(adapter->FramesXmitErr); + break; + case OID_GEN_RCV_ERROR: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_ERROR\n")); + moveSource = &adapter->FramesRcvErr; + bytesToMove = sizeof(adapter->FramesRcvErr); + break; + case OID_GEN_RCV_NO_BUFFER: + EPRO_DPRINTF_REQ(("Querying oid - OID_GEN_RCV_NO_BUFFER\n")); + moveSource = &adapter->FramesMissed; + bytesToMove = sizeof(adapter->FramesMissed); + break; + case OID_802_3_PERMANENT_ADDRESS: + EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_PERMANENT_ADDRESS\n")); + moveSource = &adapter->PermanentIndividualAddress; + bytesToMove = sizeof(adapter->PermanentIndividualAddress); + break; + case OID_802_3_CURRENT_ADDRESS: + EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_CURRENT_ADDRESS\n")); + moveSource = &adapter->CurrentIndividualAddress; + bytesToMove = sizeof(adapter->CurrentIndividualAddress); + break; + case OID_802_3_MAXIMUM_LIST_SIZE: + EPRO_DPRINTF_REQ(("Querying Maximum Multicast List Size....\n")); + GenericUL = EPRO_MAX_MULTICAST; + moveSource = &GenericUL; + bytesToMove = sizeof(GenericUL); + break; + case OID_802_3_RCV_ERROR_ALIGNMENT: + EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_RCV_ERROR_ALIGNMENT\n")); + moveSource = &adapter->FrameAlignmentErrors; + bytesToMove = sizeof(adapter->FrameAlignmentErrors); + break; + case OID_802_3_XMIT_ONE_COLLISION: + EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_XMIT_ONE_COLLISION\n")); + moveSource = &adapter->FramesXmitOneCollision; + bytesToMove = sizeof(adapter->FramesXmitOneCollision); + break; + case OID_802_3_XMIT_MORE_COLLISIONS: + EPRO_DPRINTF_REQ(("Querying oid - OID_802_3_XMIT_MORE_COLLISION\n")); + moveSource = &adapter->FramesXmitManyCollisions; + bytesToMove = sizeof(adapter->FramesXmitManyCollisions); + break; + default: + EPRO_DPRINTF_REQ(("Invalid Oid in Query.\n")); + EPRO_DPRINTF_REQ(("iq")); + statusToReturn = NDIS_STATUS_INVALID_OID; + } + + if (statusToReturn == NDIS_STATUS_SUCCESS) { + if (bytesToMove > informationBufferLength) { + *bytesNeeded = bytesToMove; + statusToReturn = NDIS_STATUS_INVALID_LENGTH; + EPRO_DPRINTF_REQ(("Invalid Length in Query\n")); + } else { + NdisMoveMemory(informationBuffer, moveSource, bytesToMove); + (*bytesWritten)+=bytesToMove; + } + } + + EPRO_DPRINTF_REQ(("EProQueryInfo - Done\n")); + + EPRO_DPRINTF_REQ(("returning: 0x%lx\n", statusToReturn)); + return(statusToReturn); +} + +NDIS_STATUS EProSetInformation(IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_OID oid, + IN PVOID informationBuffer, + IN ULONG informationLength, + OUT PULONG bytesRead, + OUT PULONG bytesNeeded) +/*++ + + Routine Description: + + This is the MiniportSetInformation Handler for the EPro driver + + Arguments: + + miniportAdapterContext - really a pointer to our adapter structure + + oid - the oid to set + + informationBuffer - the buffer which contains the information we need + to carry out the set + + informationLength - the length of the informationBuffer's data + + bytesRead - how many bytes did we actually read out of informationBuffer + + bytesNeeded - if we failed -- how many bytes do we need to complete + the call? + + Return Values: + + NDIS_STATUS_SUCCESS - set completed OK + NDIS_STATUS_NOT_ACCEPTED - too many MC addresses set + NDIS_STATUS_INVALID_DATA - tried to set MC list, buf inf. buffer not + an integral multiple of 6 (len of 802_3 address) + NDIS_STATUS_PENDING - set PENDED (completed in EProHandleInterrupt) + NDIS_STATUS_INVALID_OID - the oid was bad, or we don't support it. + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + NDIS_STATUS statusToReturn = NDIS_STATUS_SUCCESS; + ULONG genericUL; + BOOLEAN fReturn; + + EPRO_DPRINTF_REQ(("EProSetInformation. Oid = %lx\n", oid)); + + switch(oid) + { + case OID_802_3_MULTICAST_LIST: + EPRO_DPRINTF_REQ(("setting: OID_802_3_MULTICAST_LIST\n")); + + if (informationLength % EPRO_LENGTH_OF_ADDRESS != 0) + { + *bytesNeeded = EPRO_LENGTH_OF_ADDRESS; + EPRO_DPRINTF_REQ(("INVALID data length...\n")); + return(NDIS_STATUS_INVALID_DATA); + } + + if ((informationLength / EPRO_LENGTH_OF_ADDRESS) > EPRO_MAX_MULTICAST) + { + EPRO_DPRINTF_REQ(("Attempted to set too many multicasts....\n")); + return(NDIS_STATUS_NOT_ACCEPTED); + } + + *bytesRead = informationLength; + *bytesNeeded = 0; + + // + // If they are trying to clear the multicast list and none + // have been set then we are done! + // + if ((0 == (informationLength / EPRO_LENGTH_OF_ADDRESS)) && + (0 == adapter->NumMCAddresses)) + { + return(NDIS_STATUS_SUCCESS); + } + + fReturn = EProChangeMulticastList( + adapter, + informationLength / EPRO_LENGTH_OF_ADDRESS, + informationBuffer); + if (adapter->fMulticastEnable) + { + BOOLEAN fReturnStatus; + + fReturnStatus = EProSetCardMulticastList( + adapter, + (fReturn) ? EPRO_CLEAR_CARD_MC : EPRO_SET_CARD_MC); + if (!fReturnStatus) + { + statusToReturn = NDIS_STATUS_NOT_ACCEPTED; + } + else + { + statusToReturn = NDIS_STATUS_PENDING; + } + } + + break; + + case OID_GEN_CURRENT_PACKET_FILTER: + EPRO_DPRINTF_REQ(("setting: OID_GEN_CURRENT_PACKET_FILTER\n")); + if (informationLength < 4) + { + EPRO_DPRINTF_REQ(("INVALID data length...\n")); + return(NDIS_STATUS_INVALID_LENGTH); + } + + NdisMoveMemory(&genericUL, informationBuffer, sizeof(ULONG)); + + *bytesRead = sizeof(ULONG); + *bytesNeeded = 0; + statusToReturn = EProSetPacketFilter(adapter, genericUL); + + break; + + case OID_GEN_CURRENT_LOOKAHEAD: + if (informationLength < 4) + { + return(NDIS_STATUS_INVALID_LENGTH); + } + + EPRO_DPRINTF_REQ(("EPRO: Attempting to set lookahead size\n")); + + NdisMoveMemory(&genericUL, informationBuffer, sizeof(ULONG)); + + *bytesRead = sizeof(ULONG); + *bytesNeeded = 0; + + if (genericUL <= EPRO_GEN_MAXIMUM_LOKAHEAD) + { + EPRO_DPRINTF_REQ(("EPRO: Current lookahead is now %d bytes\n", adapter->RXLookAheadSize)); + adapter->RXLookAheadSize = (USHORT)genericUL; + statusToReturn = NDIS_STATUS_SUCCESS; + } + else + { + statusToReturn = NDIS_STATUS_FAILURE; + } + break; + + default: + EPRO_DPRINTF_REQ(("Invalid oid in setinformation\n")); + EPRO_DPRINTF_REQ(("inv")); + statusToReturn = NDIS_STATUS_INVALID_OID; + } + + return(statusToReturn); +} + +NDIS_STATUS EProSetPacketFilter(PEPRO_ADAPTER adapter, ULONG newFilter) +/*++ + + Routine Description: + + This routine, invoked from EProSetInformation, is called to do the + real work of setting a packet filter. + + Arguments: + + Return Values: + +--*/ +{ + // reg2flags are the flags currently set in the configuration register in + // bank2 (bank 2, reg 2). This is used when we twiddle with the bank + // + UCHAR reg2Flags = 0, result; + + // Do we need to update the CONFIG registers in bank2? (iff broadcast or + // promiscuous setting are changed only) If so, then we will need to do + // a synchronized call, and also a reset... + // + BOOLEAN fUpdateConfig = FALSE; + ULONG oldFilter; + + NDIS_STATUS Status; + + EPRO_DPRINTF_REQ(("SetPacketFilter: %lx", newFilter)); + + // + // Validate the new packet filter that was passed in to be set. + // + if (newFilter & ~(NDIS_PACKET_TYPE_DIRECTED | + NDIS_PACKET_TYPE_PROMISCUOUS | + NDIS_PACKET_TYPE_BROADCAST | + //NDIS_PACKET_TYPE_ALL_MULTICAST | + NDIS_PACKET_TYPE_MULTICAST)) + { + EPRO_DPRINTF_REQ(("PacketFilter NOT SUPPORTED!\n")); + EPRO_DPRINTF_REQ(("Not Supported\n")); + + return(NDIS_STATUS_NOT_SUPPORTED); + } + + // + // Save the new packet filter. + // + oldFilter = adapter->CurrentPacketFilter; + adapter->CurrentPacketFilter = newFilter; + + + // + // Ooh, here's a good hardware weirdness. If you issue the rcv enable + // command to the 82595tx when it is already in receive-enable mode, + // it munges the next received packet. no joke. So we always + // temporarily disable receives here. + // + EProReceiveDisable(adapter); + + EPRO_DPRINTF_REQ(("Setting filter...\n")); + + Status = NDIS_STATUS_SUCCESS; + + do + { + // + // Now, if we've modified the PROMISCUOUS or BROADCAST + // settings, we have to re-configure the card.... + // + if (((oldFilter & NDIS_PACKET_TYPE_PROMISCUOUS) ^ (newFilter & NDIS_PACKET_TYPE_PROMISCUOUS)) || + ((oldFilter & NDIS_PACKET_TYPE_BROADCAST) ^ (newFilter & NDIS_PACKET_TYPE_BROADCAST))) + { + // + // Are we supposed to set or clear the promiscuous bit? + // + if (newFilter & NDIS_PACKET_TYPE_PROMISCUOUS) + { + EPRO_DPRINTF_REQ(("Promiscuous mode set...\n")); + + adapter->fPromiscuousEnable = TRUE; + reg2Flags |= I82595_PROMISCUOUS_FLAG; + } + else + { + // + // Promiscuous mode bit NOT set - do we need to turn it off? + // + adapter->fPromiscuousEnable = FALSE; + } + + // + // Are we supposed to set or clear the broadcast bit? + // + if (newFilter & NDIS_PACKET_TYPE_BROADCAST) + { + adapter->fBroadcastEnable = TRUE; + } + else + { + adapter->fBroadcastEnable = FALSE; + reg2Flags |= I82595_NO_BROADCAST_FLAG; + } + + // + // okay, we're going to have to modify the config, so we better stop + // receives to get ready for the reset... + + // Okay, we're going to have to modify the configuration... + // So wait for any receives or sends to finish so the card is + // idle... + // + if (!EProWaitForExeDma(adapter)) + { + EPRO_DPRINTF_RX(("FAILURE waiting for exedma....\n")); + Status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + + // + // This gets expanded to a Sync (synchronizedwithinterrupt) call -- + // since it changes banks, it can NOT happen at the same time as the + // ISR (which requires bank0) + // + EProBroadcastPromiscuousChange(adapter, reg2Flags); + + // + // Okay, make sure the card is idle again before we enable receives... + // + if (!EProWaitForExeDma(adapter)) + { + adapter->fHung = TRUE; + return(NDIS_STATUS_HARD_ERRORS); +// EPRO_ASSERT(FALSE); + } + } + + // + // Enable receives. + // + EProReceiveEnable(adapter); + + // + // Has the multicast bit changed? + // + if ((oldFilter & NDIS_PACKET_TYPE_MULTICAST) ^ + (newFilter & NDIS_PACKET_TYPE_MULTICAST)) + { + // + // Was the bit set or turned off? + // + if (newFilter & NDIS_PACKET_TYPE_MULTICAST) + { + adapter->fMulticastEnable = TRUE; + + // + // If there are no multicast addresses to set then we are done. + // + if (0 == adapter->NumMCAddresses) + { + Status = NDIS_STATUS_SUCCESS; + break; + } + + // + // Set the multicast addresses to the card. + // + if (!EProSetCardMulticastList(adapter, EPRO_SET_CARD_MC)) + { + EPRO_DPRINTF_REQ(("ERROR setting multicastlist on card\n")); + return(NDIS_STATUS_NOT_ACCEPTED); + } + else + { + Status = NDIS_STATUS_PENDING; + break; + } + } + else + { + // + // If they haven't set the MC bit, we check to see if we think + // it is on and turn it off if need be... + // + adapter->fMulticastEnable = FALSE; + + // + // If there are no multicast addresses set on the card + // the we are done. + // + if (0 == adapter->NumMCAddresses) + { + Status = NDIS_STATUS_SUCCESS; + break; + } + + // + // Clear any multicast addresses that are currently on the + // adapter. + // + if (!EProSetCardMulticastList(adapter, EPRO_CLEAR_CARD_MC)) + { + EPRO_DPRINTF_REQ(("ERROR setting Multicast List on card...\n")); + + Status = NDIS_STATUS_NOT_ACCEPTED; + break; + } + else + { + Status = NDIS_STATUS_PENDING; + break; + } + } + } + + + } while (FALSE); + + + + // + // if the filter = 0, then we are leaving with receives disabled + // + if (0 == newFilter) + { + // + // Make sure that + // + EProReceiveDisable(adapter); + adapter->CurrentPacketFilter = newFilter; + return(NDIS_STATUS_SUCCESS); + } + + // This is probably a NOTREACHED... + + return(NDIS_STATUS_SUCCESS); + +} + +BOOLEAN EProSyncBroadcastPromiscuousChange(PVOID context) +/*++ + + Routine Description: + + This routine is called by a macro expansion of the function + EProBroadcastPromiscuousChange -- the macro expands that call to + a NdisMSynchronizeWithInterrupt call to this function. This function + CANNOT BE CALLED DIRECTLY WHERE THERE IS A CHANCE IT CAN RUN CONCURRENTLY + WITH EProDisableInterrupts. Very Bad Things will happen if the two run + concurrently (only on an MP machine - on a UP machine, the syncwithint + call can be avoided - but alas we don't have the luxury of having + seperate binaries for each... + + Arguments: + + context - a EPRO_BRDPROM_CONTEXT which is basically just a strucutre + holding all the parameters to the EProBroadcastPromiscuousChange + macro (adapter structure pointer and reg2flags settings) + + Return Values: + + always TRUE... + +--*/ +{ + PEPRO_ADAPTER adapter = ((PEPRO_BRDPROM_CONTEXT)context)->Adapter; + UCHAR reg2flags = ((PEPRO_BRDPROM_CONTEXT)context)->Reg2Flags; + UCHAR result; + + EPRO_SWITCH_BANK_2(adapter); + + EPRO_RD_PORT_UCHAR(adapter, I82595_CONFIG2_REG, &result); + result &= ~(I82595_PROMISCUOUS_FLAG | I82595_NO_BROADCAST_FLAG); + result |= reg2flags; + EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG2_REG, result); + + // according to the docs, the configure is triggered by a write to reg 3, so we just + // read and write to it... + // + EPRO_RD_PORT_UCHAR(adapter, I82595_CONFIG3_REG, &result); + EPRO_WR_PORT_UCHAR(adapter, I82595_CONFIG3_REG, result); + + // Probably don't need this (82595 is supposed to default to bank0 after + // a reset or sel-reset + // + EPRO_SWITCH_BANK_0(adapter); + + // need to do a selreset after a config register modification + // per 82595 docs... + // + EProSelReset(adapter); + + EPRO_ASSERT_BANK_0(adapter); + + return(TRUE); +} + + +BOOLEAN +EProChangeMulticastList( + IN PEPRO_ADAPTER adapter, + IN UINT addressCount, + IN UCHAR addresses[][EPRO_LENGTH_OF_ADDRESS]) +/*++ + + Routine Description: + + This routine changed the multicast list as stored by the driver. + IT DOES NOT ACTUALLY MODIFY THE MULTICAST LIST IN THE HARDWARE --- + EProSetCardMulticastList does that. + + Arguments: + + adapter - pointer to our adapter structure + + addressCount - how many addresses to set + + addresses[] - the data... + + Return Values: + + NDIS_STATUS_NOT_ACCEPTED - tried to set too many (notreached b/c + setpacketfilter checks this too) + NDIS_STATUS_SUCCESS - operation completed ok. + +--*/ +{ + UINT i; + BOOLEAN fReturn = FALSE; + + EPRO_DPRINTF_REQ(("EProChangeMulticastList. Setting %d addresses...\n", + addressCount)); + + // now, put the multicast list into the adapter structure... + // + for (i = 0; i < addressCount; i++) + { + NdisMoveMemory( + &adapter->MCAddress[i], + &addresses[i], + EPRO_LENGTH_OF_ADDRESS); + } + + // + // If we just cleared the multicast address list then we need to + // return the fact. + // + if ((adapter->NumMCAddresses != 0) && (0 == addressCount)) + { + fReturn = TRUE; + } + + // + // Save the new number of multicast addresses. + // + adapter->NumMCAddresses = addressCount; + + return(fReturn); +} + + +BOOLEAN EProSetCardMulticastList(PEPRO_ADAPTER adapter, int operation) +/*++ + + Routine Description: + + This is the routine which takes the driver's MC list and copies it down + to the card. The MC list must already be set in the driver with + EProChangeMulticastList. + + Arguments: + + adapter - pointer to our adapter structure + + operation - see epro.h for the definitions. Basically SET or CLEAR + either we are turning off MC or re-entering the list. + + Return Values: + + TRUE - MC list set okay and has been PENDED (completed in EProHandleInterrupt) + FALSE - MC list didn't set okay and was not pended + +--*/ +{ + // The header for the MC_SETUP structure + EPRO_MC_HEADER mcHead; + + // Setting the MC list uses a transmit buffer. + PEPRO_TRANSMIT_BUFFER curTBuf = adapter->CurrentTXBuf; + + // look variable... + BOOLEAN fGotBuffer = FALSE; + + USHORT lengthNeeded = I82595_TX_FRM_HDR_SIZE + + (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) + 2; + USHORT timeout = 0; + + EPRO_ASSERT_BANK_0(adapter); + EPRO_DPRINTF_REQ(("Setting the MC list on the card...%d\n", operation)); + + // Make sure we have a free buffer pointer structure. + // + if (!curTBuf->fEmpty) + { + while (!EProCheckTransmitCompletion(adapter, curTBuf)) + { + timeout++; + + if (timeout > EPRO_TX_TIMEOUT) + { + return(FALSE); + } + + NdisStallExecution(1); + } + } + + // Is there a transmit in progress? If not, then we can just + // set the buffer to address zero and go + // + if (adapter->TXChainStart == NULL) + { + curTBuf->TXBaseAddr = EPRO_TX_LOWER_LIMIT_SHORT; + } + else + { + // Okay, there is a transmit in progress. Let's see if there is enough + // transmit buffer space. + // + USHORT freeSpace = 0; + + // are we above the free space? + // + if (adapter->TXChainStart->TXBaseAddr < curTBuf->TXBaseAddr) + { + freeSpace = EPRO_TX_UPPER_LIMIT_SHORT - curTBuf->TXBaseAddr; + freeSpace += adapter->TXChainStart->TXBaseAddr - + EPRO_TX_LOWER_LIMIT_SHORT; + } + else + { + freeSpace = adapter->TXChainStart->TXBaseAddr - + curTBuf->TXBaseAddr; + } + + + while (freeSpace < lengthNeeded) + { + UINT timeout1; + + while (!EProCheckTransmitCompletion(adapter, adapter->TXChainStart)) + { + if (timeout1++ > EPRO_TX_TIMEOUT) + { + return(FALSE); + } + + NdisStallExecution(1); + } + + if (adapter->TXChainStart->TXBaseAddr < curTBuf->TXBaseAddr) + { + freeSpace = EPRO_TX_UPPER_LIMIT_SHORT - curTBuf->TXBaseAddr; + freeSpace += adapter->TXChainStart->TXBaseAddr - + EPRO_TX_LOWER_LIMIT_SHORT; + } + else + { + freeSpace = adapter->TXChainStart->TXBaseAddr - + curTBuf->TXBaseAddr; + } + } + } + + // + // Okay, now we have to make sure we've got enough space to actually + // put the data in the transmit area... + // + + // Now we've got a buffer.... + // + EPRO_ASSERT(curTBuf->fEmpty); + + mcHead.CommandField = I82595_CMD_MC_SETUP; + + // Clear the header + // + NdisZeroMemory(mcHead.NullBytes, 5); + + // Okay, are we setting or clearing? If we're clearing then the byte count + // is 0, if we're setting, then its a function of the number of addresses... + // + if (operation != EPRO_CLEAR_CARD_MC) + { + mcHead.ByteCountLo = (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) & 0xff; + mcHead.ByteCountHi = (adapter->NumMCAddresses * EPRO_LENGTH_OF_ADDRESS) >> 8; + } + else + { + mcHead.ByteCountLo = 0; + mcHead.ByteCountHi = 0; + } + + EPRO_DPRINTF_REQ(("There are %d MC addresses.\n", adapter->NumMCAddresses)); + EPRO_DPRINTF_REQ(("There are %x%x bytes of MC addresses at %lx\n", mcHead.ByteCountHi, + mcHead.ByteCountLo, &adapter->MCAddress)); + EPRO_DPRINTF_REQ(("Sizeof MCHEAD is %x\n", sizeof(mcHead))); + + // bank0 + // + EPRO_ASSERT_BANK_0(adapter); + + EPRO_DPRINTF_REQ(("Address on card is %lx\n", curTBuf->TXBaseAddr)); + EPRO_SET_HOST_ADDR(adapter, curTBuf->TXBaseAddr); + EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, ((USHORT *)(&mcHead)), sizeof(mcHead) >> 1); + + if (operation != EPRO_CLEAR_CARD_MC) + { + // since we know the len_of_address is an even #, we make the + // assumption here that the amount of memory to copy is divisible + // by two (so the shift is safe) + // + EPRO_COPY_BUFFER_TO_NIC_USHORT( + adapter, + (USHORT *)(&adapter->MCAddress), + (adapter->NumMCAddresses * 3)); // 3 shorts... + } + + + // okay, set up to and pend this thing.... + + if (!EProWaitForExeDma(adapter)) + { + // we're in trouble if this happens... + // + adapter->fHung = TRUE; + return(FALSE); +// EPRO_ASSERT(FALSE); + } + + adapter->IntPending = EPRO_INT_MC_SET_PENDING; + adapter->IntContext = (PVOID)curTBuf; + + // enable EXE interrupts so we can do this asynchronously... + // + EProSetInterruptMask(adapter, EPRO_RX_TX_EXE_INTERRUPTS); + + // set the BAR and go.... + // + EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, curTBuf->TXBaseAddr); + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_CMD_MC_SETUP); + + // Move the currenttxbuf pointer forward... + // + adapter->CurrentTXBuf = curTBuf->NextBuf; + + return(TRUE); +} + + diff --git a/private/ntos/ndis/ieepro/sndrcv.c b/private/ntos/ndis/ieepro/sndrcv.c new file mode 100644 index 000000000..a32d4098c --- /dev/null +++ b/private/ntos/ndis/ieepro/sndrcv.c @@ -0,0 +1,1178 @@ +#include <ndis.h> +#include "82595.h" +#include "eprohw.h" +#include "eprosw.h" +#include "epro.h" +#include "eprodbg.h" + +////////////////////////////////////////////////////////////////////// +// SEND code +////////////////////////////////////////////////////////////////////// + +ULONG numberOfResources = 0; + +NDIS_STATUS EProSend(IN NDIS_HANDLE miniportAdapterContext, + IN PNDIS_PACKET packet, + IN UINT flags) +/*++ +Routine Description: + + The MiniportSend handler for the EPro. About 18 million different + things happen here: + + 1) We need to see if there are free transmit buffer pointer for + this packet. + 2) Once we've got a tx buffer pointer, we then see if we have enough + physical memory space for this transmit. If we don't, then + we resources out + 3) We need to copy the 82595 frame header, then the packet to the card + 4) We need to start the transmit if none are in progress + 5) We need to update some structures to keep track of the transmit + +Arguments: + miniportAdapterContext - Really a pointer to our EPRO_ADAPTER structure + + packet - the packet to send + + flags - an optional FLAGS field - not used currently in NDIS + +Return Value: + + NDIS_STATUS_RESOURCES - no free transmit buffers. Please hang up and then + dial again. If you need help, please dial your operator + NDIS_STATUS_PENDING - The packet is on the card and is being sent. + +--*/ + +{ + PEPRO_ADAPTER adapter = (EPRO_ADAPTER *)miniportAdapterContext; +// This is the adapter's current transmit buffer... + PEPRO_TRANSMIT_BUFFER curTBuf = adapter->CurrentTXBuf; + USHORT freeSpace; + UINT totalPacketLength; + USHORT result; + +// If we're currently executing an MC_SETUP command, we can't +// handle any transmits. The reason is that the MC_SETUP uses +// a transmit buffer, and we will have problems trying to complete +// transfers if we do both at the same time. There are a few ways +// we could get around this, but they'd make things more complicated, +// and don't gain us much if we go by the assumption that in "normal" +// use we won't get that many MC-setups... + if (adapter->IntPending == EPRO_INT_MC_SET_PENDING) { + return(NDIS_STATUS_RESOURCES); + } + +// Check for free buffer. If can't find one, then return +// NDIS_STATUS_RESOURCES. +// is the current buffer free? + if (!curTBuf->fEmpty) { +// nope. can we free it? + if (!EProCheckTransmitCompletion(adapter, curTBuf)) { + numberOfResources++; + return(NDIS_STATUS_RESOURCES); + } + } + +// Get the total length of this packet so we can see if we have +// room for it. + NdisQueryPacket(packet, NULL, NULL, NULL, &totalPacketLength); + + curTBuf->TXSize = totalPacketLength; + +// Add in the 82595's tx memory structure plus 2 bytes padding +// between frames + totalPacketLength+=(I82595_TX_FRM_HDR_SIZE + 2); + +// is there a transmit in progress? + if (adapter->TXChainStart == NULL) { + curTBuf->TXBaseAddr = EPRO_TX_LOWER_LIMIT_SHORT; + curTBuf->NextBuf->TXBaseAddr = totalPacketLength; + } else { +// Do we have free space for this packet? + EPRO_ASSERT(adapter->TXChainStart != curTBuf); + EPRO_ASSERT(curTBuf->TXBaseAddr >= EPRO_TX_LOWER_LIMIT_SHORT); + +// Although TxBaseAddr == upper limit is NOT LEGAL, we allow it in +// this assert because it will fall through the next if statement +// and be dealt with properly. (freespace will = 0 and then we will wrap) + EPRO_ASSERT(curTBuf->TXBaseAddr <= EPRO_TX_UPPER_LIMIT_SHORT); + +// Now we need to know if the current buffer position is above or +// below the space in use. + if (adapter->TXChainStart->TXBaseAddr >= curTBuf->TXBaseAddr) { +// We're BELOW the in-use space + freeSpace = adapter->TXChainStart->TXBaseAddr - + curTBuf->TXBaseAddr; + } else { + freeSpace = EPRO_TX_UPPER_LIMIT_SHORT - + curTBuf->TXBaseAddr; + freeSpace += (adapter->TXChainStart->TXBaseAddr - + EPRO_TX_LOWER_LIMIT_SHORT); + } + + if (freeSpace < totalPacketLength) { + return(NDIS_STATUS_RESOURCES); + } + } + +// Now, the set the next buffer's address: + curTBuf->NextBuf->TXBaseAddr = curTBuf->TXBaseAddr + + totalPacketLength; + + if (curTBuf->NextBuf->TXBaseAddr >= EPRO_TX_UPPER_LIMIT_SHORT) + curTBuf->NextBuf->TXBaseAddr -= EPRO_TX_UPPER_LIMIT_SHORT; + +// Okay, when we've gotten to this point, it's because we've determined +// that there is enough space on the card for the packet. So, now we +// set the current transmit buffer to be empty. + curTBuf->fEmpty = FALSE; +// move the current buffer pointer forward + adapter->CurrentTXBuf = curTBuf->NextBuf; + +// bank 0 + EPRO_ASSERT_BANK_0(adapter); + +// set our packet pointer so we can ethindicatereceive later. + curTBuf->TXPacket = packet; + +// This is a double-check that the txbuffer structure was freed +// correctly -- this is set in checktransmitcompletion + EPRO_ASSERT(curTBuf->TXSendAddr == 0xffff); + +// We make a backup copy of the TXBaseAddr, in case we use up all +// of our buffer pointer strucutres and wrap around and overwrite the +// TXBaseAddr of this buffer.... + curTBuf->TXSendAddr = curTBuf->TXBaseAddr; + +// Set the address on the card to copy to + EPRO_SET_HOST_ADDR(adapter, curTBuf->TXBaseAddr); + EProCopyPacketToCard(adapter, packet); + +// Is there a transmit already going? + if (!adapter->TXChainStart) { +// Nope - queue this one up and let it rip.. + { + UINT i; + UCHAR result; + + for (i=0;i<I82595_SPIN_TIMEOUT;i++) { + EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result); + if (!(result &I82595_EXEC_STATE)) { + if (result & I82595_EXEC_INT_RCVD) { + EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, + I82595_EXEC_INT_RCVD); + } + break; + } + } + } + + // Set up and start the transmit + EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, curTBuf->TXBaseAddr); + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT); + + adapter->TXChainStart = curTBuf; + } else { +// If chainstart != NULL (ie is pointing to a buffer) and there is no tx +// in progress - we're hosed.... +// if (curTBuf->LastBuf->TXSendAddr + 4 >= EPRO_TX_UPPER_LIMIT_SHORT) { +// EPRO_SET_HOST_ADDR(adapter, ((curTBuf->LastBuf->TXSendAddr + 4) - +// EPRO_TX_UPPER_LIMIT_SHORT)); +// } else { +// EPRO_SET_HOST_ADDR(adapter, (curTBuf->LastBuf->TXSendAddr + 4)); +// } +// EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, +// curTBuf->TXSendAddr); +// EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, +// curTBuf->LastBuf->TXSize | 8000); +// +// EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &result); +// +// EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT_RESUME); + } + +// okay, we're PENDING... + return(NDIS_STATUS_PENDING); +} + + + +VOID EProCopyPacketToCard(PEPRO_ADAPTER adapter, + PNDIS_PACKET packet) +/*++ + +Routine Description: + + This routine copies a packet down to the card. We assume the card's IO port + has been set to the correct address at function entry. + +Parameters: + + adapter - Pointer to our EPRO_ADAPTER structure + + packet - pointer to the NDIS_PACKET we are copying down. + +Return Values: + + none + +--*/ +{ +// frame header.... + EPRO_TX_FRAME_HEADER txFrameHeader; +// This is a hack to transfer buffers of odd lengths + BOOLEAN fForward = FALSE; +// this is the + USHORT forwardedShort; +// The physical address of the buffer to copy out of... + PVOID bufferAddr; +// packet information + UINT bufferCount, totalPacketLength, bufferLen, currentOffset; +// This is the current buffer of the packet that is passed in... + PNDIS_BUFFER curBuffer; + +// Get the first buffer out of the packet. + NdisQueryPacket(packet, NULL, &bufferCount, + &curBuffer, &totalPacketLength); + +// Copy the TX header down to the card. + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, I82595_XMT_SHORT); + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0); + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0); + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, totalPacketLength); + +///////////////////////////////////////////////////// +// LOOP on all the buffers in the packet... +///////////////////////////////////////////////////// + do { + NdisQueryBuffer(curBuffer, &bufferAddr, &bufferLen); + +// skip over zero-length buffers. + if (bufferLen == 0) { + NdisGetNextBuffer(curBuffer, &curBuffer); + continue; + } + +// BEGIN fix for odd-length buffers + if (fForward) { + fForward = FALSE; + forwardedShort |= ((*((UCHAR *)bufferAddr)) << 8); + ((UCHAR *)bufferAddr)++; + bufferLen--; + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, forwardedShort); + } + + if (bufferLen & 1) { + fForward = TRUE; + forwardedShort =*(UCHAR *)( ((UCHAR *)bufferAddr) + (bufferLen-1) ); + } +// END fix for odd-length buffers... + +#ifndef EPRO_USE_32_BIT_IO + EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, + ((UNALIGNED USHORT *)bufferAddr), + ((ULONG)bufferLen>>1)); +#else +// using 32-bit + if (adapter->EProUse32BitIO) { + if (bufferLen & 2) { + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, + *((UNALIGNED USHORT *)bufferAddr)); + (UCHAR *)bufferAddr += 2; + EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, ((UNALIGNED ULONG *)bufferAddr), + ((ULONG)bufferLen >> 2)); + } else { + EPRO_COPY_BUFFER_TO_NIC_ULONG(adapter, ((UNALIGNED ULONG *)bufferAddr), + ((ULONG)bufferLen >> 2)); + } + } else { +// This is an older version of the 82595 - we need to use 16-bit anyway + EPRO_COPY_BUFFER_TO_NIC_USHORT(adapter, + (USHORT *)bufferAddr, + ((ULONG)bufferLen>>1)); + } +#endif + + NdisGetNextBuffer(curBuffer, &curBuffer); + + } while (curBuffer); +//////////////////////////////////////////////////////// +// END of loop for all buffers in packet +//////////////////////////////////////////////////////// + +// copy down a trailing byte + if (fForward) { + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, forwardedShort); + } +} + + + + +BOOLEAN EProCheckTransmitCompletion(PEPRO_ADAPTER adapter, + PEPRO_TRANSMIT_BUFFER txBuf) +/*++ +Routine Description: + + This routine takes the transmit buffer pointed to by txBuf and tries to + free it. This can be called from two places. On an adapter that is very + very busy transmitting, it can get called from our send handler if the send + handler is called and all the transmit buffers on the card are full. This + routine is called directly from the send handler to minimize the latency of + the returning NDIS_STATUS_RESOURCES----free buffer in interrupt handler dpc--- + ---ndis calls back down in it's send handler. There is the possibility here + that packets will be sent out of order in this, but it doesn't matter, let the + protocols figure that out. + + This routine is also called by our handleinterrupt handler where it does the + exact same thing, except in response to a transmit interrupt. + +Arguments: + + adapter - a pointer to our EPRO_ADAPTER structure + + txBuf - this is a pointer to the transmit buffer we are checking + +Return Value: + + TRUE if the buffer is already free or has been indicated and now is free. + FALSE if the buffer is not finished being transmitted. + +--*/ +{ + UCHAR result; + USHORT status; +// NDIS_STATUS returnStatus = NDIS_STATUS_FAILURE; + + if (!txBuf) { + return(FALSE); + } + + if (txBuf->fEmpty) { + return(TRUE); + } + +// if we got through the first if, then there must be a non-empty +// buffer. Therefore, we have to assume that there is a transmit in +// progress (txchainstart is set to the tx in progress) - if there +// is not one in progress, then something is screwed. + EPRO_ASSERT(adapter->TXChainStart != NULL); + +// bank0 + EPRO_ASSERT_BANK_0(adapter); + +// Check and see if this transmit has completed... + EPRO_SET_HOST_ADDR(adapter, txBuf->TXSendAddr); + +// check DN (tx done) flag... + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &status); + +// See if the TX_DONE bit is set... + if (!(status & I82595_TX_DN_BYTE_MASK)) { + return(FALSE); + } + +// Check the status of the transmition + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, &status); + + if (status & I82595_TX_OK_SHORT_MASK) { +// returnStatus = NDIS_STATUS_SUCCESS; + adapter->FramesXmitOK++; + if ((status & I82595_NO_COLLISIONS_MASK) > 0) { + adapter->FramesXmitOneCollision++; + if ((status & I82595_NO_COLLISIONS_MASK) > 1) { + adapter->FramesXmitManyCollisions++; + } + } + } else { + adapter->FramesXmitErr++; + +// D---it, the frame errored out... +// Just re-send it. + EPRO_SET_HOST_ADDR(adapter, adapter->TXChainStart->TXSendAddr); + + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, I82595_XMT); + EPRO_WR_PORT_USHORT(adapter, I82595_MEM_IO_REG, 0); + + if (!EProWaitForExeDma(adapter)) { + adapter->fHung = TRUE; +// EPRO_ASSERT(FALSE); + } + + EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, + adapter->TXChainStart->TXSendAddr); + + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT); + + return(FALSE); + } + +// move the chain forward b/c this buffer has been freed.... +#if DBG + adapter->TXChainStart->TXSendAddr = 0xffff; +#endif + adapter->TXChainStart = adapter->TXChainStart->NextBuf; + + if (adapter->TXChainStart == adapter->CurrentTXBuf) { +// since we just moved the chain FORWARD one, if these +// two pointers are equal it means the buffer is EMPTY, not full... + adapter->TXChainStart = NULL; + } else { + +// Make sure the card is idle +// EProWaitForExeDma(adapter); + { + UINT i; + + for (i=0;i<I82595_SPIN_TIMEOUT;i++) { + EPRO_RD_PORT_UCHAR(adapter, I82595_STATUS_REG, &result); + if (!(result &I82595_EXEC_STATE)) { + if (result & I82595_EXEC_INT_RCVD) { + EPRO_WR_PORT_UCHAR(adapter, I82595_STATUS_REG, + I82595_EXEC_INT_RCVD); + } + break; + } + } + } + +// Get the next TX going.... + EPRO_WR_PORT_USHORT(adapter, I82595_TX_BAR_REG, + adapter->TXChainStart->TXSendAddr); + + EPRO_WR_PORT_UCHAR(adapter, I82595_CMD_REG, I82595_XMT); + } + +// this buffer is empty now. + txBuf->fEmpty = TRUE; + +// Yes, here's the deep and dark secret: either we succeed a packet, +// or we re-send it, so whenever packets complete, they ALWAYS +// succeed :) + NdisMSendComplete(adapter->MiniportAdapterHandle, + txBuf->TXPacket, NDIS_STATUS_SUCCESS); + + return(TRUE); +} + + +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// +// RECEIVE code... +////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////// + + + +UINT EProHandleReceive(PEPRO_ADAPTER adapter) +/*++ +Routine Description: + + This is the dpc-level code that really handles a receive interrupt. + +Arguments: + + adapter - pointer to the adapter structure. + +Return Value: + + the number of packets received + +--*/ +{ + // The 82595s RCV header + EPRO_RCV_HEADER header; + + // the Ethernet header to indicate up + EPRO_ETH_HEADER ethHeader; + + // temp variable to figure out how much to copy up + USHORT bytesToCopy; + + // Our context to pass in NdisMEthIndicateReceive... + EPRO_RCV_CONTEXT context; + + // Use this to loop and handle multiple receives in one int... + // + UCHAR tempCopy; + UINT numRcvd = 0; + + // bank0 + // EPRO_SWITCH_BANK_0(adapter); + // + EPRO_ASSERT_BANK_0(adapter); + + if ((adapter->RXCurrentAddress < EPRO_RX_LOWER_LIMIT_SHORT) || + (adapter->RXCurrentAddress > EPRO_RX_UPPER_LIMIT_SHORT)) + { + adapter->fHung = TRUE; +#if DBG + DbgPrint("the RxCurrentAddress is not within acceptable limits: 0x%x\n", adapter->RXCurrentAddress); +// EPRO_ASSERT(FALSE); +#endif + + return(0); + } + + // Read the header... + EPRO_SET_HOST_ADDR(adapter, adapter->RXCurrentAddress); + + EPRO_READ_BUFFER_FROM_NIC_USHORT( + adapter, + (USHORT *)&header, + ((ULONG)sizeof(EPRO_RCV_HEADER) >> 1)); + + // Process one or more received frames... + while ((header.Event == I82595_RX_EOF) && !adapter->fHung) + { + // Was the transmit OK? + if (!header.Status1 & I82595_RX_OK) + { + adapter->FramesRcvErr++; + // Since we configure the 82595 to discard bad frames, we know we've reached the + // latest received frame when we hit a bad one -- since the card will "reclaim" + // the space filled by the bad frame as soon as it gets another one. + break; + } + else + { + numRcvd++; + + // Fill in our receive context - to be passed in to TransferData + context.RXFrameSize = (USHORT)((USHORT)header.ByteCountLo) | (((USHORT)header.ByteCountHi) << 8); + + // Figure out how many bytes to indicate up. Either the size of the current lookahead + // or the entire frame - whichever is smaller. + bytesToCopy = ((context.RXFrameSize-sizeof(EPRO_ETH_HEADER)) > adapter->RXLookAheadSize) ? + adapter->RXLookAheadSize : + (context.RXFrameSize - sizeof(EPRO_ETH_HEADER)); + + EPRO_READ_BUFFER_FROM_NIC_USHORT( + adapter, + (USHORT *)(ðHeader), + sizeof(EPRO_ETH_HEADER) >> 1); + +#ifndef EPRO_USE_32_BIT_IO + EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, &adapter->RXLookAhead, bytesToCopy >> 1); +#else + if (adapter->EProUse32BitIO) + { + if (bytesToCopy & 2) + { + EPRO_RD_PORT_USHORT( + adapter, + I82595_MEM_IO_REG, + (UNALIGNED USHORT *)(&adapter->RXLookAhead)); + + EPRO_READ_BUFFER_FROM_NIC_ULONG( + adapter, + (UNALIGNED ULONG *)(((UCHAR *)&(adapter->RXLookAhead)) + 2), + bytesToCopy >> 2); + } + else + { + EPRO_READ_BUFFER_FROM_NIC_ULONG( + adapter, + (UNALIGNED ULONG *)(&(adapter->RXLookAhead)), + bytesToCopy >> 2); + } + } + else + { + // This is an old version of the 82595 - we have to use 16-bit IO + EPRO_READ_BUFFER_FROM_NIC_USHORT( + adapter, + (USHORT *)&adapter->RXLookAhead, + bytesToCopy>>1); + } +#endif + + if (bytesToCopy & 1) + { + // just read the low-order byte here.... + EPRO_RD_PORT_UCHAR(adapter, I82595_MEM_IO_REG, &tempCopy); + + adapter->RXLookAhead[bytesToCopy-1] = tempCopy; + } + + context.RXCurrentAddress = adapter->RXCurrentAddress; + context.LookAheadSize = bytesToCopy; + + // indicate packet + NdisMEthIndicateReceive(adapter->MiniportAdapterHandle, + (NDIS_HANDLE)&context, + (PCHAR)ðHeader, + sizeof(EPRO_ETH_HEADER), + &adapter->RXLookAhead, + bytesToCopy, + context.RXFrameSize - sizeof(EPRO_ETH_HEADER)); + + // verify bank0 + EPRO_ASSERT_BANK_0(adapter); + } + +{ + USHORT temp = (USHORT)header.NextFrmLo | (((USHORT)header.NextFrmHi) << 8); + + if ((temp < EPRO_RX_LOWER_LIMIT_SHORT) || + (temp > EPRO_RX_UPPER_LIMIT_SHORT)) + { + adapter->fHung = TRUE; +#if DBG + DbgPrint("The receive header has an invalid next frame pointer!\n"); + DbgPrint("current rx: %lx, rx: %lx, hi: %x, lo: %x hdr: %lx\n", + adapter->RXCurrentAddress, + temp, + header.NextFrmHi, + header.NextFrmLo, + &header); + +// EPRO_ASSERT(FALSE); +#endif + + break; + } +} + + adapter->RXCurrentAddress = (USHORT)header.NextFrmLo | (((USHORT)header.NextFrmHi) << 8); + + // Seek to the next frame + EPRO_SET_HOST_ADDR(adapter, adapter->RXCurrentAddress); + + // Read the header... + EPRO_READ_BUFFER_FROM_NIC_USHORT( + adapter, + (USHORT *)(&header), + sizeof(EPRO_RCV_HEADER) >> 1); + } + + // now, update the stop reg to = the bottom of the received frame.... + if (numRcvd > 0) + { + USHORT value; + + value = context.RXCurrentAddress + context.RXFrameSize; + + // wrap around... + if (value >= EPRO_RX_UPPER_LIMIT_SHORT) + { + value -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT); + } + + if (!((value <= EPRO_RX_UPPER_LIMIT_SHORT) && + (value >= EPRO_RX_LOWER_LIMIT_SHORT))) + { + adapter->fHung = TRUE; +#if DBG + DbgPrint("ca: %lx, fs: %lx, val: %lx", + context.RXCurrentAddress, + context.RXFrameSize, + value); +// EPRO_ASSERT(FALSE); +#endif + } + + EPRO_WR_PORT_USHORT(adapter, I82595_RX_STOP_REG, value); + } + + adapter->FramesRcvOK += numRcvd; + + return(numRcvd); +} + +#if 0 +// You know. This code PASSES all the stress tests. Passes everything the +// tester can throw out, but still is broken when I try to make it work +// in real life. <sigh>. Look at this later. + +NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet, + OUT PUINT bytesTransferred, + IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_HANDLE miniportReceivedContext, + IN UINT byteOffset, + IN UINT bytesToTransfer) +/*++ + +Routine Description: + + The transferdata handler for the EPro. + +Arguments: + + packet - The packet to transfer the data into + + bytesTransferred - The number of bytes actually copied into packet. + + miniportAdapterContext - Reallly a pointer to our EPRO_ADAPTER structure + + miniportReceivedContext - This is our EPRO_RCV_CONTEXT, which basically just + has the packet length and pointer to where it lies + in the card's address space. + + byteOffset - where in the frame to begin trasferring from + + bytesToTransfer - how many bytes to transfer. + +Return Value: + + NDIS_STATUS_SUCCESS - data transfered OK + NDIS_STATUS_FAILURE - tried to transfer off end of frame + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; +// The 82595's on-card RCV memory structure + EPRO_RCV_HEADER header; +// An 802.3 ethernet header. + EPRO_ETH_HEADER ethHeader; +// How many bytes have we copied, how many are left to copy + USHORT byteCount, bytesToCopy; + PEPRO_RCV_CONTEXT pcontext = (PEPRO_RCV_CONTEXT)miniportReceivedContext; +// The current buffer we are copying into. + PNDIS_BUFFER curDestBuf; +// The physical address of the buffer we are currently copying into + PVOID curDestBufAddr; +// The length of that buffer + UINT curDestBufLen; +// Two bytes used when we have to transfer in to odd-length buffers (since +// accesses to the EPro's memory are only by-word. + UCHAR tempCopy[2]; +// This is TRUE if we are "forwarding" a single byte from an odd-length transfer + BOOLEAN fForward = FALSE; +// the address to read from on the card + USHORT cardAddress; + UINT bytesWriteThisPacket; + +// TODO - copy first lookahead size bytes out of lookahead buffer. + + *bytesTransferred = 0; + +// switch to bank0 for mem io + EPRO_ASSERT_BANK_0(adapter); + +// Make sure they're not seeking past the end of the frame + if (byteOffset > pcontext->RXFrameSize) { + return(NDIS_STATUS_FAILURE); + } + +// get the first buffer + NdisQueryPacket(packet, NULL, NULL, &curDestBuf, NULL); + +// copy the amount requested, or the entire packet - whichever is smaller + if ((bytesToTransfer + byteOffset) <= pcontext->RXFrameSize) { + bytesToCopy = bytesToTransfer; + } else { + bytesToCopy = (pcontext->RXFrameSize - byteOffset); + } + +// first loop -- copy up to the end of the lookahead buffer's worth: + if (byteOffset < adapter->RXLookAheadSize) { + UINT laOffset = byteOffset; + UINT laToCopy = adapter->RXLookAheadSize - laOffset; + + if (laToCopy > bytesToCopy) { + laToCopy = bytesToCopy; + } + + *bytesTransferred+=laToCopy; + bytesToCopy-=laToCopy; + + while (laToCopy > 0) { + NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen); + + if (curDestBufLen == 0) { + continue; + } + + // We either write the entire buffer size bytes or the number of bytes + // remaining to copy - whichever is smaller. + bytesWriteThisPacket = (laToCopy > curDestBufLen) ? + curDestBufLen : laToCopy; + + EPRO_ASSERT(bytesWriteThisPacket <= laToCopy); + + NdisMoveMemory(curDestBufAddr, &adapter->RXLookAhead[laOffset], + bytesWriteThisPacket); + + laToCopy-=bytesWriteThisPacket; + laOffset+=bytesWriteThisPacket; + } + + byteOffset = adapter->RXLookAheadSize; + + EPRO_ASSERT(bytesToCopy >= laToCopy); + + if (bytesToCopy == 0) { + EProLogStr(" 1BytesTo:"); + EProLogLong(bytesToTransfer); + EProLogStr("BytesTransf:"); + EProLogLong(*bytesTransferred); + return(NDIS_STATUS_SUCCESS); + } + + if (curDestBufLen > bytesWriteThisPacket) { + (UCHAR *)curDestBufAddr += bytesWriteThisPacket; + } else { + curDestBufLen = 0; + while (curDestBufLen == 0) { + NdisGetNextBuffer(curDestBuf, &curDestBuf); + if (!curDestBuf) { + EProLogStr(" 2BytesTo:"); + EProLogLong(bytesToTransfer); + EProLogStr("BytesTransf:"); + EProLogLong(*bytesTransferred); + return(NDIS_STATUS_SUCCESS); + } + NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen); + } + } + } else { + NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen); + } + +// set our memory address on the card... + cardAddress = (pcontext->RXCurrentAddress + sizeof(EPRO_RCV_HEADER) + + sizeof(EPRO_ETH_HEADER) + byteOffset); + +// Set the address on the card. Note that you can do sequential reads +// from the IO port which WRAP around the memory boundry, but if you +// manually set the address, you have to wrap manually. + if (cardAddress >= EPRO_RX_UPPER_LIMIT_SHORT) { + cardAddress -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT); + } + +// Are we starting of reading from an odd address? + if (cardAddress & 1) { +// yes; odd offset -- forward a byte in... + fForward = TRUE; + cardAddress--; + } + +// Okay, now seek to the right address on the card + EPRO_SET_HOST_ADDR(adapter, cardAddress); + +// Are we forwarding a byte in? If so, fetch it now.... + if (fForward == TRUE) { + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy)); + } + + +// continue until we either run out of buffers, or out of bytes.... + while((bytesToCopy > 0) && (curDestBuf!=NULL)) { +// We either write the entire buffer size bytes or the number of bytes +// remaining to copy - whichever is smaller. + bytesWriteThisPacket = (bytesToCopy > curDestBufLen) ? + curDestBufLen : bytesToCopy; + bytesToCopy-=bytesWriteThisPacket; + +// Ooh, we're going to transfer some bytes... + *bytesTransferred+=bytesWriteThisPacket; + +// Okay. Did we have to forward a byte in? Copy it to the buffer NOW.. + if (fForward == TRUE) { + *(UCHAR *)curDestBufAddr = tempCopy[1]; + fForward = FALSE; + ((UCHAR *)curDestBufAddr)++; + bytesWriteThisPacket--; + } + +// Copy the bulk of the data... +#ifndef EPRO_USE_32_BIT_IO + EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr, + bytesWriteThisPacket>>1); +#else + if (adapter->EProUse32BitIO) { + if (bytesWriteThisPacket & 2) { + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)curDestBufAddr); + EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter, + (UNALIGNED ULONG *)((UCHAR *)curDestBufAddr +2), + bytesWriteThisPacket >> 2); + } else { + EPRO_READ_BUFFER_FROM_NIC_ULONG(adapter, + (UNALIGNED ULONG *)curDestBufAddr, + bytesWriteThisPacket >> 2); + } + } else { + EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr, + bytesWriteThisPacket>>1); + } +#endif + +// Okay, the rshift in the last call will lose the odd byte. If there is one, we need +// to read it and possibly forward the second byte.... + if (bytesWriteThisPacket & 1) { + fForward = TRUE; + // Read the LOW order byte. + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy)); + ((UCHAR *)curDestBufAddr)[bytesWriteThisPacket-1] = tempCopy[0]; + } + NdisGetNextBuffer(curDestBuf, &curDestBuf); + if (curDestBuf != NULL) { + NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen); + } + } + + EProLogStr(" 3BytesTo:"); + EProLogLong(bytesToTransfer); + EProLogStr("BytesTransf:"); + EProLogLong(*bytesTransferred); + return(NDIS_STATUS_SUCCESS); +} + +#else + + +NDIS_STATUS EProTransferData(OUT PNDIS_PACKET packet, + OUT PUINT bytesTransferred, + IN NDIS_HANDLE miniportAdapterContext, + IN NDIS_HANDLE miniportReceivedContext, + IN UINT byteOffset, + IN UINT bytesToTransfer) +/*++ + +Routine Description: + + The transferdata handler for the EPro. + +Arguments: + + packet - The packet to transfer the data into + + bytesTransferred - The number of bytes actually copied into packet. + + miniportAdapterContext - Reallly a pointer to our EPRO_ADAPTER structure + + miniportReceivedContext - This is our EPRO_RCV_CONTEXT, which basically just + has the packet length and pointer to where it lies + in the card's address space. + + byteOffset - where in the frame to begin trasferring from + + bytesToTransfer - how many bytes to transfer. + +Return Value: + + NDIS_STATUS_SUCCESS - data transfered OK + NDIS_STATUS_FAILURE - tried to transfer off end of frame + +--*/ +{ + PEPRO_ADAPTER adapter = (PEPRO_ADAPTER)miniportAdapterContext; + + // The 82595's on-card RCV memory structure + EPRO_RCV_HEADER header; + + // An 802.3 ethernet header. + EPRO_ETH_HEADER ethHeader; + + // How many bytes have we copied, how many are left to copy + USHORT byteCount, bytesToCopy; + PEPRO_RCV_CONTEXT pcontext = (PEPRO_RCV_CONTEXT)miniportReceivedContext; + + // The current buffer we are copying into. + PNDIS_BUFFER curDestBuf; + + // The physical address of the buffer we are currently copying into + PVOID curDestBufAddr; + + // The length of that buffer + UINT curDestBufLen; + + // Two bytes used when we have to transfer in to odd-length buffers (since + // accesses to the EPro's memory are only by-word. + UCHAR tempCopy[2]; + + // This is TRUE if we are "forwarding" a single byte from an odd-length transfer + BOOLEAN fForward = FALSE; + + // the address to read from on the card + USHORT cardAddress; + + // TODO - copy first lookahead size bytes out of lookahead buffer. + + *bytesTransferred = 0; + + // switch to bank0 for mem io + // EPRO_SWITCH_BANK_0(adapter); + EPRO_ASSERT_BANK_0(adapter); + + // Make sure they're not asking for too much. + // if (bytesToTransfer + byteOffset > pcontext->RXFrameSize) + // { + // return(NDIS_STATUS_FAILURE); + // } + + // Make sure they're not seeking past the end of the frame + if (byteOffset > pcontext->RXFrameSize) + { + return(NDIS_STATUS_FAILURE); + } + + + // copy the amount requested, or the entire packet - whichever is smaller + if ((bytesToTransfer + byteOffset) <= pcontext->RXFrameSize) + { + bytesToCopy = bytesToTransfer; + } + else + { + bytesToCopy = (pcontext->RXFrameSize - byteOffset); + } + +// set our memory address on the card... + cardAddress = (pcontext->RXCurrentAddress + + sizeof(EPRO_RCV_HEADER) + + sizeof(EPRO_ETH_HEADER) + + byteOffset); + + if (cardAddress >= EPRO_RX_UPPER_LIMIT_SHORT) + { + // cardAddress = EPRO_RX_LOWER_LIMIT_SHORT + (cardAddress - EPRO_RX_UPPER_LIMIT_SHORT); + // Go algebraic simplification: + cardAddress -= (EPRO_RX_UPPER_LIMIT_SHORT - EPRO_RX_LOWER_LIMIT_SHORT); + } + + + // Are we starting of reading from an odd address? + if (cardAddress & 1) + { + // yes; odd offset -- forward a byte in... + fForward = TRUE; + cardAddress--; + } + + // Okay, now seek to the right address on the card + EPRO_SET_HOST_ADDR(adapter, cardAddress); + + // Are we forwarding a byte in? If so, fetch it now.... + if (fForward == TRUE) + { + EPRO_RD_PORT_USHORT(adapter, I82595_MEM_IO_REG, (USHORT *)(&tempCopy)); + } + + // get the first buffer + NdisQueryPacket(packet, NULL, NULL, &curDestBuf, NULL); + + // continue until we either run out of buffers, or out of bytes.... + while((bytesToCopy > 0) && (curDestBuf!=NULL)) + { + UINT bytesWriteThisPacket; + + NdisQueryBuffer(curDestBuf, &curDestBufAddr, &curDestBufLen); + + // We either write the entire buffer size bytes or the number of bytes + // remaining to copy - whichever is smaller. + bytesWriteThisPacket = + (bytesToCopy > curDestBufLen) ? curDestBufLen : bytesToCopy; + + // Ooh, we're going to transfer some bytes... + *bytesTransferred+=bytesWriteThisPacket; + + // Okay. Did we have to forward a byte in? Copy it to the buffer NOW.. + if (fForward == TRUE) + { + *(UCHAR *)curDestBufAddr = tempCopy[1]; + fForward = FALSE; + ((UCHAR *)curDestBufAddr)++; + bytesWriteThisPacket--; + } + + // Copy the bulk of the data... +#ifndef EPRO_USE_32_BIT_IO + EPRO_READ_BUFFER_FROM_NIC_USHORT(adapter, curDestBufAddr, bytesWriteThisPacket>>1); +#else + if (adapter->EProUse32BitIO) + { + if (bytesWriteThisPacket & 2) + { + EPRO_RD_PORT_USHORT( + adapter, + I82595_MEM_IO_REG, + (UNALIGNED USHORT *)curDestBufAddr); + + EPRO_READ_BUFFER_FROM_NIC_ULONG( + adapter, + ((UCHAR *)curDestBufAddr +2), + bytesWriteThisPacket >> 2); + } + else + { + EPRO_READ_BUFFER_FROM_NIC_ULONG( + adapter, + curDestBufAddr, + bytesWriteThisPacket >> 2); + } + } + else + { + EPRO_READ_BUFFER_FROM_NIC_USHORT( + adapter, + curDestBufAddr, + bytesWriteThisPacket >> 1); + } +#endif + + // Okay, the rshift in the last call will lose the odd byte. If there is one, we need + // to read it and possibly forward the second byte.... + if (bytesWriteThisPacket & 1) + { + fForward = TRUE; + + // Read the LOW order byte. + EPRO_RD_PORT_USHORT( + adapter, + I82595_MEM_IO_REG, + (USHORT *)(&tempCopy)); + + ((UCHAR *)curDestBufAddr)[bytesWriteThisPacket-1] = tempCopy[0]; + } + NdisGetNextBuffer(curDestBuf, &curDestBuf); + bytesToCopy -= curDestBufLen; + } + + return(NDIS_STATUS_SUCCESS); +} + +#endif + + +BOOLEAN EProSyncCopyBufferToNicUlong(PVOID context) +{ + UCHAR result; + PEPRO_ADAPTER adapter = ((PEPRO_COPYBUF_CONTEXT)context)->Adapter; +// PVOID buffer = ((PEPRO_COPYBUF_CONTEXT)context)->Buffer; +// UINT len = ((PEPRO_COPYBUF_CONTEXT)context)->Len; + + EPRO_RD_PORT_UCHAR(adapter, I82595_32IOSEL_REG, &result); +// result |= I82595_32IOSEL; + EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, (result | I82595_32IOSEL)); + NdisRawWritePortBufferUlong(adapter->IoPAddr + I82595_32MEM_IO_REG, + ((PEPRO_COPYBUF_CONTEXT)context)->Buffer, + ((PEPRO_COPYBUF_CONTEXT)context)->Len); +// result &= ~I82595_32IOSEL; + EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, result); + + return(TRUE); +} + + +BOOLEAN EProSyncReadBufferFromNicUlong(PVOID context) +{ + UCHAR result; + PEPRO_ADAPTER adapter = ((PEPRO_COPYBUF_CONTEXT)context)->Adapter; +// PVOID buffer = ((PEPRO_COPYBUF_CONTEXT)context)->Buffer; +// UINT len = ((PEPRO_COPYBUF_CONTEXT)context)->Len; + + EPRO_RD_PORT_UCHAR(adapter, I82595_32IOSEL_REG, &result); +// result |= I82595_32IOSEL; + EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, (result | I82595_32IOSEL)); + NdisRawReadPortBufferUlong(adapter->IoPAddr + I82595_32MEM_IO_REG, + ((PEPRO_COPYBUF_CONTEXT)context)->Buffer, + ((PEPRO_COPYBUF_CONTEXT)context)->Len); +// result &= ~I82595_32IOSEL; + EPRO_WR_PORT_UCHAR(adapter, I82595_32IOSEL_REG, result); + + return(TRUE); +} + diff --git a/private/ntos/ndis/ieepro/sources b/private/ntos/ndis/ieepro/sources new file mode 100644 index 000000000..e950c6ce5 --- /dev/null +++ b/private/ntos/ndis/ieepro/sources @@ -0,0 +1,48 @@ +!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=ieepro +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=DRIVER + +TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\ndis.lib + +C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER + +INCLUDES=..\..\inc + +SOURCES=epro.c \ + init.c \ + request.c \ + eeprom.c \ + sndrcv.c \ + eprodbg.c \ + epro.rc + +RELATIVE_DEPTH=..\.. + +MSC_WARNING_LEVEL=/W3 /WX |