/*++ Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved. Module Name: card.c Abstract: Card-specific functions for the NDIS 3.0 Novell 2000 driver. Author: Sean Selitrennikoff Environment: Kernel mode, FSD Revision History: --*/ #include "precomp.h" BOOLEAN CardSlotTest( IN PNE2000_ADAPTER Adapter ); BOOLEAN CardRamTest( IN PNE2000_ADAPTER Adapter ); #pragma NDIS_PAGEABLE_FUNCTION(CardCheckParameters) BOOLEAN CardCheckParameters( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Checks that the I/O base address is correct. Arguments: Adapter - pointer to the adapter block. Return Value: TRUE, if IoBaseAddress appears correct. --*/ { UCHAR Tmp; // // If adapter responds to a stop command correctly -- assume it is there. // // // Turn off interrupts first. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0); // // Stop the card. // SyncCardStop(Adapter); // // Pause // NdisStallExecution(2000); // // Read response // NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp); if ((Tmp == (CR_NO_DMA | CR_STOP)) || (Tmp == (CR_NO_DMA | CR_STOP | CR_START)) ) { return(TRUE); } else { return(FALSE); } } #ifdef NE2000 #pragma NDIS_PAGEABLE_FUNCTION(CardSlotTest) BOOLEAN CardSlotTest( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Checks if the card is in an 8 or 16 bit slot and sets a flag in the adapter structure. Arguments: Adapter - pointer to the adapter block. Return Value: TRUE, if all goes well, else FALSE. --*/ { UCHAR Tmp; UCHAR RomCopy[32]; UCHAR i; BOOLEAN found; // // Reset the chip // NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF); // // Go to page 0 and stop // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA); // // Pause // NdisStallExecution(2000); // // Check that it is stopped // NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp); if (Tmp != (CR_NO_DMA | CR_STOP)) { IF_LOUD(DbgPrint("Could not stop the card\n");) return(FALSE); } // // Setup to read from ROM // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_BYTE_WIDE | DCR_FIFO_8_BYTE | DCR_NORMAL ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0); // // Ack any interrupts that may be hanging around // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF); // // Setup to read in the ROM, the address and byte count. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0x0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0x0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 32); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_DMA_READ | CR_START ); // // Read first 32 bytes in 16 bit mode // for (i = 0; i < 32; i++) { NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, RomCopy + i); } IF_VERY_LOUD( DbgPrint("Resetting the chip\n"); ) // // Reset the chip // NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RESET, &Tmp); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RESET, 0xFF); // // Check ROM for 'B' (byte) or 'W' (word) // NOTE: If the buffer has bot BB and WW then use WW instead of BB IF_VERY_LOUD( DbgPrint("Checking slot type\n"); ) found = FALSE; for (i = 16; i < 31; i++) { if (((RomCopy[i] == 'B') && (RomCopy[i+1] == 'B')) || ((RomCopy[i] == 'W') && (RomCopy[i+1] == 'W')) ) { if (RomCopy[i] == 'B') { Adapter->EightBitSlot = TRUE; found = TRUE; } else { Adapter->EightBitSlot = FALSE; found = TRUE; break; // Go no farther } } } if (found) { IF_VERY_LOUD( (Adapter->EightBitSlot?DbgPrint("8 bit slot\n"): DbgPrint("16 bit slot\n")); ) } else { // // If neither found -- then not an NE2000 // IF_VERY_LOUD( DbgPrint("Failed slot type\n"); ) } return(found); } #endif // NE2000 #pragma NDIS_PAGEABLE_FUNCTION(CardRamTest) BOOLEAN CardRamTest( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Finds out how much RAM the adapter has. It starts at 1K and checks thru 60K. It will set Adapter->RamSize to the appropriate value iff this function returns TRUE. Arguments: Adapter - pointer to the adapter block. Return Value: TRUE, if all goes well, else FALSE. --*/ { PUCHAR RamBase, RamPointer; PUCHAR RamEnd; UCHAR TestPattern[]={ 0xAA, 0x55, 0xFF, 0x00 }; PULONG pTestPattern = (PULONG)TestPattern; UCHAR ReadPattern[4]; PULONG pReadPattern = (PULONG)ReadPattern; for (RamBase = (PUCHAR)0x400; RamBase < (PUCHAR)0x10000; RamBase += 0x400) { // // Write Test pattern // if (!CardCopyDown(Adapter, RamBase, TestPattern, 4)) { continue; } // // Read pattern // if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) { continue; } IF_VERY_LOUD( DbgPrint("Addr 0x%x: 0x%x, 0x%x, 0x%x, 0x%x\n", RamBase, ReadPattern[0], ReadPattern[1], ReadPattern[2], ReadPattern[3] ); ) // // If they are the same, find the end // if (*pReadPattern == *pTestPattern) { for (RamEnd = RamBase; !(PtrToUlong(RamEnd) & 0xFFFF0000); RamEnd += 0x400) { // // Write test pattern // if (!CardCopyDown(Adapter, RamEnd, TestPattern, 4)) { break; } // // Read pattern // if (!CardCopyUp(Adapter, ReadPattern, RamEnd, 4)) { break; } if (*pReadPattern != *pTestPattern) { break; } } break; } } IF_LOUD( DbgPrint("RamBase 0x%x, RamEnd 0x%x\n", RamBase, RamEnd); ) // // If not found, error out // if ((RamBase >= (PUCHAR)0x10000) || (RamBase == RamEnd)) { return(FALSE); } // // Watch for boundary case when RamEnd is maximum value // if ((ULONG_PTR)RamEnd & 0xFFFF0000) { RamEnd -= 0x100; } // // Check all of ram // for (RamPointer = RamBase; RamPointer < RamEnd; RamPointer += 4) { // // Write test pattern // if (!CardCopyDown(Adapter, RamPointer, TestPattern, 4)) { return(FALSE); } // // Read pattern // if (!CardCopyUp(Adapter, ReadPattern, RamBase, 4)) { return(FALSE); } if (*pReadPattern != *pTestPattern) { return(FALSE); } } // // Store Results // Adapter->RamBase = RamBase; Adapter->RamSize = (ULONG)(RamEnd - RamBase); return(TRUE); } #pragma NDIS_PAGEABLE_FUNCTION(CardInitialize) BOOLEAN CardInitialize( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Initializes the card into a running state. Arguments: Adapter - pointer to the adapter block. Return Value: TRUE, if all goes well, else FALSE. --*/ { UCHAR Tmp; USHORT i; // // Stop the card. // SyncCardStop(Adapter); // // Initialize the Data Configuration register. // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_AUTO_INIT | DCR_FIFO_8_BYTE ); // // Set Xmit start location // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_START, 0xA0); // // Set Xmit configuration // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0x0); // // Set Receive configuration // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, RCR_MONITOR); // // Set Receive start // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_START, 0x4); // // Set Receive end // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_PAGE_STOP, 0xFF); // // Set Receive boundary // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_BOUNDARY, 0x4); // // Set Xmit bytes // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_LSB, 0x3C); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_COUNT_MSB, 0x0); // // Pause // NdisStallExecution(2000); // // Ack all interrupts that we might have produced // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF); // // Change to page 1 // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE1 | CR_STOP); // // Set current // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_CURRENT, 0x4); // // Back to page 0 // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 | CR_STOP); // // Pause // NdisStallExecution(2000); // // Check that Command register reflects this last command // NdisRawReadPortUchar(Adapter->IoPAddr + NIC_COMMAND, &Tmp); if (!(Tmp & CR_STOP)) { IF_LOUD(DbgPrint("Invalid command register\n");) return(FALSE); } // // Do initialization errata // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 55); // // Setup for a read // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_DMA_READ | CR_START ); #ifdef NE2000 // // Check if the slot is 8 or 16 bit (affects data transfer rate). // if ((Adapter->BusType == NdisInterfaceMca) || (NE2000_PCMCIA == Adapter->CardType)) { Adapter->EightBitSlot = FALSE; } else { IF_VERY_LOUD(DbgPrint("CardSlotTest\n");) if (CardSlotTest(Adapter) == FALSE) { // // Stop chip // SyncCardStop(Adapter); IF_LOUD(DbgPrint(" -- Failed\n");) return(FALSE); } } #else // NE2000 Adapter->EightBitSlot = TRUE; #endif // NE2000 // // Mask Interrupts // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_MASK, 0x0); // // Setup the Adapter for reading ram // // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin if (Adapter->EightBitSlot) { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_BYTE_WIDE ); } else { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_FIFO_8_BYTE | DCR_NORMAL | DCR_WORD_WIDE ); } // // Clear transmit configuration. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, 0); // // Clear receive configuration. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RCV_CONFIG, 0); // // Clear any interrupts // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xFF); // // Stop the chip // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_NO_DMA | CR_STOP); // // Clear any DMA values // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0); // // Clear any DMA values // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0); // // Wait for the reset to complete. // i = 0x3FFF; while (--i) { NdisRawReadPortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp); if (Tmp & ISR_RESET) break; NdisStallExecution(4); } // // Put card in loopback mode // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK); // // Start the chip. // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_NO_DMA | CR_START ); // // Test for the amount of RAM // if (NE2000_ISA == Adapter->CardType) { if (CardRamTest(Adapter) == FALSE) { // // Stop the chip // SyncCardStop(Adapter); return(FALSE); } } else { // // We know what it is for the pcmcia adapters, // so don't waste time on detecting it. // Adapter->RamBase = (PUCHAR)0x4000; Adapter->RamSize = 0x4000; } // // Stop the chip // SyncCardStop(Adapter); return(TRUE); } #pragma NDIS_PAGEABLE_FUNCTION(CardReadEthernetAddress) BOOLEAN CardReadEthernetAddress( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Reads in the Ethernet address from the Novell 2000. Arguments: Adapter - pointer to the adapter block. Return Value: The address is stored in Adapter->PermanentAddress, and StationAddress if it is currently zero. --*/ { UINT c; // // Things are done a little differently for PCMCIA adapters. // if (NE2000_PCMCIA == Adapter->CardType) { #if 0 NDIS_STATUS Status; PUCHAR pAttributeWindow; NDIS_PHYSICAL_ADDRESS AttributePhysicalAddress; // // Setup the physical address for the attribute window. // NdisSetPhysicalAddressHigh(AttributePhysicalAddress, 0); NdisSetPhysicalAddressLow( AttributePhysicalAddress, Adapter->AttributeMemoryAddress ); // // We need to get the pcmcia information from the tuple. // Status = NdisMMapIoSpace( (PVOID *)&pAttributeWindow, Adapter->MiniportAdapterHandle, AttributePhysicalAddress, Adapter->AttributeMemorySize ); if (NDIS_STATUS_SUCCESS != Status) { // // Failed to setup the attribute window. // return(FALSE); } // // Read the ethernet address from the card. // for (c = 0; c < ETH_LENGTH_OF_ADDRESS; c++) { NdisReadRegisterUchar( (PUCHAR)(pAttributeWindow + CIS_NET_ADDR_OFFSET + c * 2), &Adapter->PermanentAddress[c]); } #endif if (ETH_LENGTH_OF_ADDRESS != NdisReadPcmciaAttributeMemory( Adapter->MiniportAdapterHandle, CIS_NET_ADDR_OFFSET/2, Adapter->PermanentAddress, ETH_LENGTH_OF_ADDRESS )) { return(FALSE); } } else { // // Setup to read the ethernet address // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 12); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, 0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, 0); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_DMA_READ ); // // Read in the station address. (We have to read words -- 2 * 6 -- bytes) // for (c = 0; c < NE2000_LENGTH_OF_ADDRESS; c++) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Adapter->PermanentAddress[c] ); } } IF_LOUD( DbgPrint( "Ne2000: PermanentAddress [ %02x-%02x-%02x-%02x-%02x-%02x ]\n", Adapter->PermanentAddress[0], Adapter->PermanentAddress[1], Adapter->PermanentAddress[2], Adapter->PermanentAddress[3], Adapter->PermanentAddress[4], Adapter->PermanentAddress[5] ); ) // // Use the burned in address as the station address, unless the // registry specified an override value. // if ((Adapter->StationAddress[0] == 0x00) && (Adapter->StationAddress[1] == 0x00) && (Adapter->StationAddress[2] == 0x00) && (Adapter->StationAddress[3] == 0x00) && (Adapter->StationAddress[4] == 0x00) && (Adapter->StationAddress[5] == 0x00) ) { Adapter->StationAddress[0] = Adapter->PermanentAddress[0]; Adapter->StationAddress[1] = Adapter->PermanentAddress[1]; Adapter->StationAddress[2] = Adapter->PermanentAddress[2]; Adapter->StationAddress[3] = Adapter->PermanentAddress[3]; Adapter->StationAddress[4] = Adapter->PermanentAddress[4]; Adapter->StationAddress[5] = Adapter->PermanentAddress[5]; } return(TRUE); } BOOLEAN CardSetup( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Sets up the card. Arguments: Adapter - pointer to the adapter block, which must be initialized. Return Value: TRUE if successful. --*/ { UINT i; UINT Filter; UCHAR Tmp; // // Write to and read from CR to make sure it is there. // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0 ); NdisRawReadPortUchar( Adapter->IoPAddr + NIC_COMMAND, &Tmp ); if ((Tmp & (CR_STOP | CR_NO_DMA | CR_PAGE0)) != (CR_STOP | CR_NO_DMA | CR_PAGE0) ) { return(FALSE); } // // Set up the registers in the correct sequence, as defined by // the 8390 specification. // if (Adapter->EightBitSlot) { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_BYTE_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE ); } else { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_DATA_CONFIG, DCR_WORD_WIDE | DCR_NORMAL | DCR_FIFO_8_BYTE ); } NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RCV_CONFIG, Adapter->NicReceiveConfig ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_BOUNDARY, Adapter->NicPageStart ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_PAGE_START, Adapter->NicPageStart ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_PAGE_STOP, Adapter->NicPageStop ); Adapter->Current = Adapter->NicPageStart + (UCHAR)1; Adapter->NicNextPacket = Adapter->NicPageStart + (UCHAR)1; Adapter->BufferOverflow = FALSE; NdisRawWritePortUchar(Adapter->IoPAddr + NIC_INTR_STATUS, 0xff); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_INTR_MASK, Adapter->NicInterruptMask ); // // Move to page 1 to write the station address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE1 ); for (i = 0; i < NE2000_LENGTH_OF_ADDRESS; i++) { NdisRawWritePortUchar( Adapter->IoPAddr + (NIC_PHYS_ADDR + i), Adapter->StationAddress[i] ); } Filter = Adapter->PacketFilter; // // Write out the multicast addresses // for (i = 0; i < 8; i++) { NdisRawWritePortUchar( Adapter->IoPAddr + (NIC_MC_ADDR + i), (UCHAR)((Filter & NDIS_PACKET_TYPE_ALL_MULTICAST) ? 0xff : Adapter->NicMulticastRegs[i]) ); } // // Write out the current receive buffer to receive into // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_CURRENT, Adapter->Current ); // // move back to page 0 and start the card... // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA | CR_PAGE0 ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE0 ); // // ... but it is still in loopback mode. // return(TRUE); } VOID CardStop( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Stops the card. Arguments: Adapter - pointer to the adapter block Return Value: None. --*/ { UINT i; UCHAR Tmp; // // Turn on the STOP bit in the Command register. // SyncCardStop(Adapter); // // Clear the Remote Byte Count register so that ISR_RESET // will come on. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0); // // Wait for ISR_RESET, but only for 1.6 milliseconds (as // described in the March 1991 8390 addendum), since that // is the maximum time for a software reset to occur. // // for (i = 0; i < 4; i++) { NdisRawReadPortUchar(Adapter->IoPAddr+NIC_INTR_STATUS, &Tmp); if (Tmp & ISR_RESET) break; NdisStallExecution(500); } if (i == 4) { IF_LOUD( DbgPrint("RESET\n");) IF_LOG( Ne2000Log('R');) } // // Put the card in loopback mode, then start it. // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_XMIT_CONFIG, TCR_LOOPBACK); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_NO_DMA); // // At this point the card is still in loopback mode. // } BOOLEAN CardReset( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Resets the card. Arguments: Adapter - pointer to the adapter block Return Value: TRUE if everything is OK. --*/ { // // Stop the chip // CardStop(Adapter); // // Wait for the card to finish any receives or transmits // NdisStallExecution(2000); // // CardSetup() does a software reset. // if (!CardSetup(Adapter)) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 2, cardReset, NE2000_ERRMSG_CARD_SETUP ); return(FALSE); } // // Restart the chip // CardStart(Adapter); return TRUE; } BOOLEAN CardCopyDownPacket( IN PNE2000_ADAPTER Adapter, IN PNDIS_PACKET Packet, OUT PUINT Length ) /*++ Routine Description: Copies the packet Packet down starting at the beginning of transmit buffer XmitBufferNum, fills in Length to be the length of the packet. Arguments: Adapter - pointer to the adapter block Packet - the packet to copy down Return Value: Length - the length of the data in the packet in bytes. TRUE if the transfer completed with no problems. --*/ { // // Addresses of the Buffers to copy from and to. // PUCHAR CurBufAddress; PUCHAR OddBufAddress; PUCHAR XmitBufAddress; // // Length of each of the above buffers // UINT CurBufLen; UINT PacketLength; // // Was the last transfer of an odd length? // BOOLEAN OddBufLen = FALSE; // // Current NDIS_BUFFER that is being copied from // PNDIS_BUFFER CurBuffer; // // Programmed I/O, have to transfer the data. // NdisQueryPacket(Packet, NULL, NULL, &CurBuffer, &PacketLength); // // Skip 0 length copies // if (PacketLength == 0) { return(TRUE); } // // Get the starting buffer address // XmitBufAddress = (PUCHAR)Adapter->XmitStart + Adapter->NextBufToFill*TX_BUF_SIZE; // // Get address and length of the first buffer in the packet // NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen); while (CurBuffer && (CurBufLen == 0)) { NdisGetNextBuffer(CurBuffer, &CurBuffer); NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen); } // // set up the card // { // // Temporary places for holding values for transferring to // an odd aligned address on 16-bit slots. // UCHAR Tmp; UCHAR Tmp1; USHORT TmpShort; // // Values for waiting for noticing when a DMA completes. // USHORT OldAddr, NewAddr; // // Count of transfers to do // USHORT Count; // // Buffer to read from for odd aligned transfers // PUCHAR ReadBuffer; if (!Adapter->EightBitSlot && ((ULONG_PTR)XmitBufAddress & 0x1)) { // // Avoid transfers to odd addresses in word mode. // // For odd addresses we need to read first to get the previous // byte and then merge it with our first byte. // // // Set Count and Source address // // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(XmitBufAddress - 1)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB((PtrToUlong(XmitBufAddress) - 1)) ); // NE2000 PCMCIA CHANGE START // // NE2000 PCMCIA CHANGE!!! // //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1 ); //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // // NE2000 PCMCIA CHANGE!!! // //NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp1 ); NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort ); Tmp1 = LSB(TmpShort); // NE2000 PCMCIA CHANGE END // // Do Write errata as described on pages 1-143 and // 1-144 of the 1992 LAN databook // // // Set Count and destination address // ReadBuffer = XmitBufAddress + ((ULONG_PTR)XmitBufAddress & 1); OldAddr = NewAddr = (USHORT)(ReadBuffer); // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // // Read from port // NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort ); // // Wait for addr to change // TmpShort = 0xFFFF; while (TmpShort != 0) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp ); NewAddr = Tmp; NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp ); NewAddr |= (Tmp << 8); if (NewAddr != OldAddr) { break; } NdisStallExecution(1); TmpShort--; } if (NewAddr == OldAddr) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 2, cardCopyDownPacket, (ULONG_PTR)XmitBufAddress ); return(FALSE); } // // Set Count and destination address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(XmitBufAddress - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(XmitBufAddress - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Write) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_WRITE ); // // It seems that the card stores words in LOW:HIGH order // NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC, (USHORT)(Tmp1 | ((*CurBufAddress) << 8)) ); // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp1 ); if (Tmp1 & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } } CurBufAddress++; XmitBufAddress++; PacketLength--; CurBufLen--; } // // Do Write errata as described on pages 1-143 and 1-144 of // the 1992 LAN databook // // // Set Count and destination address // ReadBuffer = XmitBufAddress + ((ULONG_PTR)XmitBufAddress & 1); OldAddr = NewAddr = (USHORT)(ReadBuffer); // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); if (Adapter->EightBitSlot) { // // Read from port // NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); } else { // // Read from port // NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort ); } // // Wait for addr to change // TmpShort = 0xFFFF; while (TmpShort != 0) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp ); NewAddr = Tmp; NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp ); NewAddr |= (Tmp << 8); if (NewAddr != OldAddr) { break; } NdisStallExecution(1); TmpShort--; } if (NewAddr == OldAddr) { NdisWriteErrorLogEntry( Adapter->MiniportAdapterHandle, NDIS_ERROR_CODE_HARDWARE_FAILURE, 2, cardCopyDownPacket, (ULONG_PTR)XmitBufAddress ); return(FALSE); } // // Set Count and destination address // // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0 ); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(XmitBufAddress)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(XmitBufAddress)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, LSB(PacketLength) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, MSB(PacketLength) ); // // Set direction (Write) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_WRITE ); } // setup // // Copy the data now // do { UINT Count; UCHAR Tmp; // // Write the previous byte with this one // if (OddBufLen) { // // It seems that the card stores words in LOW:HIGH order // NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC, (USHORT)(*OddBufAddress | ((*CurBufAddress) << 8)) ); OddBufLen = FALSE; CurBufAddress++; CurBufLen--; } if (Adapter->EightBitSlot) { // byte mode NdisRawWritePortBufferUchar( Adapter->IoPAddr + NIC_RACK_NIC, CurBufAddress, CurBufLen ); } else { // word mode NdisRawWritePortBufferUshort( Adapter->IoPAddr + NIC_RACK_NIC, (PUSHORT)CurBufAddress, (CurBufLen >> 1)); // // Save trailing byte (if an odd lengthed transfer) // if (CurBufLen & 0x1) { OddBufAddress = CurBufAddress + (CurBufLen - 1); OddBufLen = TRUE; } } // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp ); if (Tmp & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } } // // Move to the next buffer // NdisGetNextBuffer(CurBuffer, &CurBuffer); if (CurBuffer){ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen); } // // Get address and length of the next buffer // while (CurBuffer && (CurBufLen == 0)) { NdisGetNextBuffer(CurBuffer, &CurBuffer); if (CurBuffer){ NdisQueryBuffer(CurBuffer, (PVOID *)&CurBufAddress, &CurBufLen); } } } while (CurBuffer); // // Write trailing byte (if necessary) // if (OddBufLen) { UINT Count; UCHAR Tmp; USHORT TmpShort; if (NE2000_PCMCIA == Adapter->CardType) { // NE2000 PCMCIA CHANGE!!! start TmpShort = (USHORT)*OddBufAddress; NdisRawWritePortUshort(Adapter->IoPAddr + NIC_RACK_NIC, TmpShort); // NE2000 PCMCIA CHANGE!!! end } else { NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RACK_NIC, *OddBufAddress); } // // Wait for DMA to complete robin-2 // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp ); if (Tmp & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } } } // // Return length written // *Length = PacketLength; return TRUE; } BOOLEAN CardCopyDown( IN PNE2000_ADAPTER Adapter, IN PUCHAR TargetBuffer, IN PUCHAR SourceBuffer, IN UINT Length ) /*++ Routine Description: Copies Length bytes from the SourceBuffer to the card buffer space at card address TargetBuffer. Arguments: Adapter - pointer to the adapter block SourceBuffer - Buffer in virtual address space TargetBuffer - Buffer in card address space Length - number of bytes to transfer to card Return Value: TRUE if the transfer completed with no problems. --*/ { // // Temporary place holders for odd alignment transfers // UCHAR Tmp, TmpSave; USHORT TmpShort; // // Values for waiting for noticing when a DMA completes. // USHORT OldAddr, NewAddr; // // Count of transfers to do // USHORT Count; // // Address the copy if coming from // PUCHAR ReadBuffer; // // Skip 0 length copies // if (Length == 0) { return(TRUE); } if (!Adapter->EightBitSlot && ((ULONG_PTR)TargetBuffer & 0x1)) { // // For odd addresses we need to read first to get the previous // byte and then merge it with our first byte. // // // Set Count and Source address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(TargetBuffer - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(TargetBuffer - 1)) ); // NE2000 PCMCIA CHANGE!!! start //NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x1); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0); // NE2000 PCMCIA CHANGE!!! end // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // NE2000 PCMCIA CHANGE!!! start //NdisRawReadPortUchar(Adapter->IoPAddr + NIC_RACK_NIC, &TmpSave); NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort); TmpSave = LSB(TmpShort); // NE2000 PCMCIA CHANGE!!! end // // Do Write errata as described on pages 1-143 and 1-144 of the 1992 // LAN databook // // // Set Count and destination address // ReadBuffer = TargetBuffer + ((ULONG_PTR)TargetBuffer & 1); OldAddr = NewAddr = (USHORT)(ReadBuffer); // NdisRawWritePortUchar(Adapter->IoPAddr + NIC_COMMAND, CR_PAGE0); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // // Read from port // NdisRawReadPortUshort(Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort); // // Wait for addr to change // TmpShort = 0xFFFF; while (TmpShort != 0) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp ); NewAddr = Tmp; NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp ); NewAddr |= (Tmp << 8); if (NewAddr != OldAddr) { break; } NdisStallExecution(1); TmpShort--; } if (NewAddr == OldAddr) { return(FALSE); } // // Set Count and destination address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(TargetBuffer - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(TargetBuffer - 1)) ); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2); NdisRawWritePortUchar(Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0); // // Set direction (Write) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_WRITE ); // // It seems that the card stores words in LOW:HIGH order // NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC, (USHORT)(TmpSave | ((*SourceBuffer) << 8)) ); // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp ); if (Tmp & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } } SourceBuffer++; TargetBuffer++; Length--; } // // Do Write errata as described on pages 1-143 and 1-144 of the 1992 // LAN databook // // // Set Count and destination address // ReadBuffer = TargetBuffer + ((ULONG_PTR)TargetBuffer & 1); OldAddr = NewAddr = (USHORT)(ReadBuffer); // NdisRawWritePortUchar( // robin // Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(ReadBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); if (Adapter->EightBitSlot) { // // Read from port // NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); NdisRawReadPortUchar( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); } else { // // Read from port // NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &TmpShort ); } // // Wait for addr to change // TmpShort = 0xFFFF; while (TmpShort != 0) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_LSB, &Tmp ); NewAddr = Tmp; NdisRawReadPortUchar( Adapter->IoPAddr + NIC_CRDA_MSB, &Tmp ); NewAddr |= (Tmp << 8); if (NewAddr != OldAddr) { break; } NdisStallExecution(1); TmpShort--; } if (NewAddr == OldAddr) { return(FALSE); } // // Set Count and destination address // // NdisRawWritePortUchar( // robin // Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(TargetBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(TargetBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, LSB(Length) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, MSB(Length) ); // // Set direction (Write) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_WRITE ); if (Adapter->EightBitSlot) { // // Repeatedly write to out port // NdisRawWritePortBufferUchar( Adapter->IoPAddr + NIC_RACK_NIC, SourceBuffer, Length); } else { // // Write words to out ports // NdisRawWritePortBufferUshort( Adapter->IoPAddr + NIC_RACK_NIC, (PUSHORT)SourceBuffer, (Length >> 1)); // // Write trailing byte (if necessary) // if (Length & 0x1) { SourceBuffer += (Length - 1); // NE2000 PCMCIA CHANGE!!! start //NdisRawWritePortUchar( // Adapter->IoPAddr + NIC_RACK_NIC, // *SourceBuffer //); TmpShort = (USHORT)(*SourceBuffer); NdisRawWritePortUshort( Adapter->IoPAddr + NIC_RACK_NIC, TmpShort ); // NE2000 PCMCIA CHANGE!!! end } } // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &Tmp ); if (Tmp & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } #if DBG if (!(Tmp & ISR_DMA_DONE)) { DbgPrint("CopyDownDMA didn't finish!"); } #endif // DBG } IF_LOG(Ne2000Log('>');) return TRUE; } BOOLEAN CardCopyUp( IN PNE2000_ADAPTER Adapter, IN PUCHAR TargetBuffer, IN PUCHAR SourceBuffer, IN UINT BufferLength ) /*++ Routine Description: Copies data from the card to memory. Arguments: Adapter - pointer to the adapter block Target - the target address Source - the source address (on the card) BufferLength - the number of bytes to copy Return Value: TRUE if the transfer completed with no problems. --*/ { // // Used to check when the dma is done // UCHAR IsrValue; // // Count of the number of transfers to do // USHORT Count; // // Place holder for port values // UCHAR Temp; if (BufferLength == 0) { return TRUE; } // // Read the Command Register, to make sure it is ready for a write // NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Temp); if (Adapter->EightBitSlot) { // // If byte mode // // // Set Count and destination address // // NdisRawWritePortUchar( // robin // Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(SourceBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(SourceBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, LSB(BufferLength) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, MSB(BufferLength) ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // // Repeatedly read from port // NdisRawReadPortBufferUchar( Adapter->IoPAddr + NIC_RACK_NIC, TargetBuffer, BufferLength ); } else { // // Else word mode // USHORT Tmp; // NdisRawWritePortUchar( // robin // Adapter->IoPAddr + NIC_COMMAND, // robin // CR_PAGE0 // robin // ); // robin // // Avoid transfers to odd addresses // if ((ULONG_PTR)SourceBuffer & 0x1) { // // For odd addresses we need to read previous word and store the // second byte // // // Set Count and Source address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(SourceBuffer - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(SourceBuffer - 1)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, 0x2 ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, 0x0 ); // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); *TargetBuffer = MSB(Tmp); // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &IsrValue ); if (IsrValue & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } #if DBG if (!(IsrValue & ISR_DMA_DONE)) { DbgPrint("CopyUpDMA didn't finish!"); } #endif // DBG } SourceBuffer++; TargetBuffer++; BufferLength--; } // // Set Count and destination address // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_LSB, LSB(PtrToUlong(SourceBuffer)) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_ADDR_MSB, MSB(PtrToUlong(SourceBuffer)) ); // NE2000 PCMCIA CHANGE!!! start // NdisRawWritePortUchar( // Adapter->IoPAddr + NIC_RMT_COUNT_LSB, // LSB(BufferLength) // ); // // NdisRawWritePortUchar( // Adapter->IoPAddr + NIC_RMT_COUNT_MSB, // MSB(BufferLength) // ); if (BufferLength & 1) { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, LSB(BufferLength + 1) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, MSB(BufferLength + 1) ); } else { NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_LSB, LSB(BufferLength) ); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_RMT_COUNT_MSB, MSB(BufferLength) ); } // NE2000 PCMCIA CHANGE!!! end // // Set direction (Read) // NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_START | CR_PAGE0 | CR_DMA_READ ); // // Read words from port // NdisRawReadPortBufferUshort( Adapter->IoPAddr + NIC_RACK_NIC, (PUSHORT)TargetBuffer, (BufferLength >> 1)); // // Read trailing byte (if necessary) // if (BufferLength & 1) { TargetBuffer += (BufferLength - 1); // NE2000 PCMCIA CHANGE!!! start //NdisRawReadPortUchar( // Adapter->IoPAddr + NIC_RACK_NIC, // TargetBuffer //); NdisRawReadPortUshort( Adapter->IoPAddr + NIC_RACK_NIC, &Tmp ); *TargetBuffer = LSB(Tmp); // NE2000 PCMCIA CHANGE!!! end } } // // Wait for DMA to complete // Count = 0xFFFF; while (Count) { NdisRawReadPortUchar( Adapter->IoPAddr + NIC_INTR_STATUS, &IsrValue ); if (IsrValue & ISR_DMA_DONE) { break; } else { Count--; NdisStallExecution(4); } } #if DBG if (!(IsrValue & ISR_DMA_DONE)) { DbgPrint("CopyUpDMA didn't finish!\n"); } IF_LOG(Ne2000Log('<');) #endif // DBG return TRUE; } ULONG CardComputeCrc( IN PUCHAR Buffer, IN UINT Length ) /*++ Routine Description: Runs the AUTODIN II CRC algorithm on buffer Buffer of length Length. Arguments: Buffer - the input buffer Length - the length of Buffer Return Value: The 32-bit CRC value. Note: This is adapted from the comments in the assembly language version in _GENREQ.ASM of the DWB NE1000/2000 driver. --*/ { ULONG Crc, Carry; UINT i, j; UCHAR CurByte; Crc = 0xffffffff; for (i = 0; i < Length; i++) { CurByte = Buffer[i]; for (j = 0; j < 8; j++) { Carry = ((Crc & 0x80000000) ? 1 : 0) ^ (CurByte & 0x01); Crc <<= 1; CurByte >>= 1; if (Carry) { Crc = (Crc ^ 0x04c11db6) | Carry; } } } return Crc; } VOID CardGetMulticastBit( IN UCHAR Address[NE2000_LENGTH_OF_ADDRESS], OUT UCHAR * Byte, OUT UCHAR * Value ) /*++ Routine Description: For a given multicast address, returns the byte and bit in the card multicast registers that it hashes to. Calls CardComputeCrc() to determine the CRC value. Arguments: Address - the address Byte - the byte that it hashes to Value - will have a 1 in the relevant bit Return Value: None. --*/ { ULONG Crc; UINT BitNumber; // // First compute the CRC. // Crc = CardComputeCrc(Address, NE2000_LENGTH_OF_ADDRESS); // // The bit number is now in the 6 most significant bits of CRC. // BitNumber = (UINT)((Crc >> 26) & 0x3f); *Byte = (UCHAR)(BitNumber / 8); *Value = (UCHAR)((UCHAR)1 << (BitNumber % 8)); } VOID CardFillMulticastRegs( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Erases and refills the card multicast registers. Used when an address has been deleted and all bits must be recomputed. Arguments: Adapter - pointer to the adapter block Return Value: None. --*/ { UINT i; UCHAR Byte, Bit; // // First turn all bits off. // for (i=0; i<8; i++) { Adapter->NicMulticastRegs[i] = 0; } // // Now turn on the bit for each address in the multicast list. // for ( ; i > 0; ) { i--; CardGetMulticastBit(Adapter->Addresses[i], &Byte, &Bit); Adapter->NicMulticastRegs[Byte] |= Bit; } } BOOLEAN SyncCardStop( IN PVOID SynchronizeContext ) /*++ Routine Description: Sets the NIC_COMMAND register to stop the card. Arguments: SynchronizeContext - pointer to the adapter block Return Value: TRUE if the power has failed. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); NdisRawWritePortUchar( Adapter->IoPAddr + NIC_COMMAND, CR_STOP | CR_NO_DMA ); return(FALSE); } VOID CardStartXmit( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Sets the NIC_COMMAND register to start a transmission. The transmit buffer number is taken from Adapter->CurBufXmitting and the length from Adapter->PacketLens[Adapter->CurBufXmitting]. Arguments: Adapter - pointer to the adapter block Return Value: TRUE if the power has failed. --*/ { UINT Length = Adapter->PacketLens[Adapter->CurBufXmitting]; UCHAR Tmp; // // Prepare the NIC registers for transmission. // NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_START, (UCHAR)(Adapter->NicXmitStart + (UCHAR)(Adapter->CurBufXmitting*BUFS_PER_TX))); // // Pad the length to 60 (plus CRC will be 64) if needed. // if (Length < 60) { Length = 60; } NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_MSB, MSB(Length)); NdisRawWritePortUchar(Adapter->IoPAddr+NIC_XMIT_COUNT_LSB, LSB(Length)); // // Start transmission, check for power failure first. // NdisRawReadPortUchar(Adapter->IoPAddr+NIC_COMMAND, &Tmp); NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_XMIT | CR_NO_DMA); IF_LOG( Ne2000Log('x');) } BOOLEAN SyncCardGetCurrent( IN PVOID SynchronizeContext ) /*++ Routine Description: Gets the value of the CURRENT NIC register and stores it in Adapter->Current Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); // // Have to go to page 1 to read this register // NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE1); NdisRawReadPortUchar(Adapter->IoPAddr+NIC_CURRENT, &Adapter->Current); NdisRawWritePortUchar(Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE0); return FALSE; } BOOLEAN SyncCardGetXmitStatus( IN PVOID SynchronizeContext ) /*++ Routine Description: Gets the value of the "transmit status" NIC register and stores it in Adapter->XmitStatus. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); NdisRawReadPortUchar( Adapter->IoPAddr+NIC_XMIT_STATUS, &Adapter->XmitStatus); return FALSE; } VOID CardSetBoundary( IN PNE2000_ADAPTER Adapter ) /*++ Routine Description: Sets the value of the "boundary" NIC register to one behind Adapter->NicNextPacket, to prevent packets from being received on top of un-indicated ones. Arguments: Adapter - pointer to the adapter block Return Value: None. --*/ { // // Have to be careful with "one behind NicNextPacket" when // NicNextPacket is the first buffer in receive area. // if (Adapter->NicNextPacket == Adapter->NicPageStart) { NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY, (UCHAR)(Adapter->NicPageStop-(UCHAR)1)); } else { NdisRawWritePortUchar( Adapter->IoPAddr+NIC_BOUNDARY, (UCHAR)(Adapter->NicNextPacket-(UCHAR)1)); } } BOOLEAN SyncCardSetReceiveConfig( IN PVOID SynchronizeContext ) /*++ Routine Description: Sets the value of the "receive configuration" NIC register to the value of Adapter->NicReceiveConfig. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RCV_CONFIG, Adapter->NicReceiveConfig); return FALSE; } BOOLEAN SyncCardSetAllMulticast( IN PVOID SynchronizeContext ) /*++ Routine Description: Turns on all the bits in the multicast register. Used when the card must receive all multicast packets. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); UINT i; // // Have to move to page 1 to set these registers. // NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE1); for (i=0; i<8; i++) { NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i), 0xff); } NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE0); return FALSE; } BOOLEAN SyncCardCopyMulticastRegs( IN PVOID SynchronizeContext ) /*++ Routine Description: Sets the eight bytes in the card multicast registers. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); UINT i; // // Have to move to page 1 to set these registers. // NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE1); for (i=0; i<8; i++) { NdisRawWritePortUchar( Adapter->IoPAddr+(NIC_MC_ADDR+i), Adapter->NicMulticastRegs[i]); } NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA | CR_PAGE0); return FALSE; } BOOLEAN SyncCardAcknowledgeOverflow( IN PVOID SynchronizeContext ) /*++ Routine Description: Sets the "buffer overflow" bit in the NIC interrupt status register, which re-enables interrupts of that type. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); UCHAR AcknowledgeMask = 0; if (Adapter->InterruptStatus & ISR_RCV_ERR) { SyncCardUpdateCounters(Adapter); } return FALSE; } BOOLEAN SyncCardUpdateCounters( IN PVOID SynchronizeContext ) /*++ Routine Description: Updates the values of the three counters (frame alignment errors, CRC errors, and missed packets). Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); UCHAR Tmp; NdisRawReadPortUchar( Adapter->IoPAddr+NIC_FAE_ERR_CNTR, &Tmp); Adapter->FrameAlignmentErrors += Tmp; NdisRawReadPortUchar( Adapter->IoPAddr+NIC_CRC_ERR_CNTR, &Tmp); Adapter->CrcErrors += Tmp; NdisRawReadPortUchar( Adapter->IoPAddr+NIC_MISSED_CNTR, &Tmp); Adapter->MissedPackets += Tmp; return FALSE; } BOOLEAN SyncCardHandleOverflow( IN PVOID SynchronizeContext ) /*++< Routine Description: Sets all the flags for dealing with a receive overflow, stops the card and acknowledges all outstanding interrupts. Arguments: SynchronizeContext - pointer to the adapter block Return Value: None. --*/ { PNE2000_ADAPTER Adapter = ((PNE2000_ADAPTER)SynchronizeContext); UCHAR Status; IF_LOG( Ne2000Log('F');) // // Turn on the STOP bit in the Command register. // SyncCardStop(Adapter); // // Wait for ISR_RESET, but only for 1.6 milliseconds (as // described in the March 1991 8390 addendum), since that // is the maximum time for a software reset to occur. // // NdisStallExecution(2000); // // Save whether we were transmitting to avoid a timing problem // where an indication resulted in a send. // if (!(Adapter->InterruptStatus & (ISR_XMIT | ISR_XMIT_ERR))) { CardGetInterruptStatus(Adapter,&Status); if (!(Status & (ISR_XMIT | ISR_XMIT_ERR))) { Adapter->OverflowRestartXmitDpc = Adapter->TransmitInterruptPending; IF_LOUD( DbgPrint("ORXD=%x\n",Adapter->OverflowRestartXmitDpc); ) } } Adapter->TransmitInterruptPending = FALSE; // // Clear the Remote Byte Count register so that ISR_RESET // will come on. // NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RMT_COUNT_MSB, 0); NdisRawWritePortUchar( Adapter->IoPAddr+NIC_RMT_COUNT_LSB, 0); // // According to National Semiconductor, the next check is necessary // See Step 5. of the overflow process // // NOTE: The setting of variables to check if the transmit has completed // cannot be done here because anything in the ISR has already been ack'ed // inside the main DPC. Thus, the setting of the variables, described in // the Handbook was moved to the main DPC. // // Continued: If you did the check here, you will doubly transmit most // packets that happened to be on the card when the overflow occurred. // // // Put the card in loopback mode, then start it. // NdisRawWritePortUchar( Adapter->IoPAddr+NIC_XMIT_CONFIG, TCR_LOOPBACK); // // Start the card. This does not Undo the loopback mode. // NdisRawWritePortUchar( Adapter->IoPAddr+NIC_COMMAND, CR_START | CR_NO_DMA); return FALSE; }