#include #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;iRXCurrentAddress = 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); //}