/*+ * file: srom.c * * Copyright (C) 1992-1995 by * Digital Equipment Corporation, Maynard, Massachusetts. * All rights reserved. * * This software is furnished under a license and may be used and copied * only in accordance of the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * The information in this software is subject to change without notice * and should not be construed as a commitment by digital equipment * corporation. * * Digital assumes no responsibility for the use or reliability of its * software on equipment which is not supplied by digital. * * * Abstract: This file contains the code to access the onboard ROM of * adapters based on DEC's DC21X4 Ethernet Controller. * * Author: Philippe klein * * Revision History: * * 05-Oct-95 phk Modified Miniport version * 10-Jan-95 phk Add ParseSRom * 29-Nov-95 phk Add parsing for SROM format V3 * -*/ #include #define SROM_93LC46B_SIZE 64 //words #define SROM_93LC46B_MAX_CYCLES 25 #define SROM_93LC46B_ADDRESS_MSB 5 #define SROM_93LC46B_DATA_MSB 15 #define SROM_93LC46B_DATA_BIT 3 #define SROM_93LC46B_VALID_BITMASK 0x8 #define SROM_93LC46B_DELAY (10) #define CSR_READ 0x4000 #define CSR_WRITE 0x2000 #define SEL_SROM 0x0800 #define DATA_1 0x0004 #define DATA_0 0x0000 #define CLK 0x0002 #define CS 0x0001 #define DISABLE_AUTOSENSE 0x8000 #define EXT 0x40 #define DC21X4_MEDIA 0x3F #define MODE 0x0071 #define SENSE_BN 0x000E #define SENSE_DIS 0x8000 #define DEFAULT 0x4000 #define POLARITY 0x0080 #define SENSE_SHIFT 1 #define MODE_SHIFT 18 #define SROM_LEGACY 0x00 #define SROM_V1 0x01 #define SROM_V2 0x02 #define SROM_V3 0x03 #define SROM_SIZE (SROM_93LC46B_SIZE*2) #define SROM_IEEE_LEN 32 #define TEST_PATTERN 0xAA5500FF #define SROM_TIMEOUT 50 #define ZX312_SIGNATURE 0x0095C000 #define GET_MODE(_command) \ ( (*(UNALIGNED ULONG *)(_command) & MODE) << MODE_SHIFT ) #define IF_DEFAULT_MEDIA(_command) \ ( *(UNALIGNED ULONG *)(_command) & DEFAULT ) #define GET_POLARITY(_command) \ ( (*(UNALIGNED ULONG *)(_command) & POLARITY) ? 0xffffffff : 0 ) #define GET_SENSE_MASK(_command) \ ((*(UNALIGNED ULONG *)(_command) & SENSE_DIS) ? \ 0 : (ULONG)(1 << ((*(UNALIGNED ULONG *)(_command) & SENSE_BN)>> SENSE_SHIFT ))) #pragma pack(1) typedef struct _SROM_ID_BLOCK{ USHORT VendorID; USHORT SysID; USHORT Reserved[6]; USHORT ID_Checksum; UCHAR FormatVersion; UCHAR AdapterCount; UCHAR NetworkAddress[ETH_LENGTH_OF_ADDRESS]; } SROM_ID_BLOCK, *PSROM_ID_BLOCK; typedef struct _ADAPTER_ENTRIES{ UCHAR DeviceNumber; USHORT Offset; } ADAPTER_ENTRIES, *PADAPTER_ENTRIES; #pragma pack() #define DE500_STR 0x1D #define BOARD_SIGNATURE(_srom) \ ((*(UNALIGNED ULONG *)&(_srom)[DE500_STR] == *(PULONG)&DE500Strng[0]) && \ (*(UNALIGNED ULONG *)&(_srom)[DE500_STR+sizeof(ULONG)] == *(PULONG)&DE500Strng[sizeof(ULONG)])) // PHY Parsing definitions #define EXTENDED_FORMAT 0x80 #define LENGTH 0x7f #define TYPE_0 0x0 #define TYPE_1 0x1 #define TYPE_2 0x2 #define TYPE_3 0x3 #define MEDIA_CAPABILITIES_MASK 0xf800 #define NWAY_ADVERTISEMENT_MASK 0x03e0 #pragma NDIS_PAGABLE_FUNCTION(DC21X4ReadSerialRom) /*+ * * DC21X4ReadSerialRom * * Routine Description: * * Read the Dc21X4 Serial Rom to retrieve the adapter information * * Arguments: * * Adapter * * Return Value: * * Status * * -*/ extern NDIS_STATUS DC21X4ReadSerialRom ( IN PDC21X4_ADAPTER Adapter ) { UNALIGNED UCHAR *EthAddress; UCHAR IdProm[SROM_IEEE_LEN *2]; ULONG Value; INT Time; UINT i; #if __DBG DbgPrint ("DC21X4ReadSerialROM\n"); #endif //Read the Station Address switch (Adapter->AdapterType) { case NdisInterfacePci: // Read the Network Address from the PCI board ID ROM // through DC21X4's Serial ROM port switch (Adapter->DeviceId) { default: return DC21X4ParseSRom(Adapter); case DC21040_CFID: Adapter->MediaCapable = (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5); //Initialize DC21040s ID_PROM pointer DC21X4_WRITE_PORT( DC21X4_IDPROM, 0 ); // Read the 32 bytes of the Ethernet ID PROM for (i = 0; i < SROM_IEEE_LEN; i++) { Time = SROM_TIMEOUT; do { NdisStallExecution(1*MILLISECOND); // Wait 1 ms DC21X4_READ_PORT( DC21X4_IDPROM, &Value ); } while ((Value & DC21X4_IDPROM_DATA_UNVALID) && ((Time--)>0)); if (Time > 0) { IdProm[i] = (UCHAR)(Value & DC21X4_IDPROM_DATA); } else { return NDIS_STATUS_FAILURE; } } EthAddress = &IdProm[0]; } break; case NdisInterfaceEisa: Adapter->MediaCapable = (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5); // Read the 32 bytes of the Ethernet ID PROM for (i = 0; i < SROM_IEEE_LEN; i++) { NdisRawReadPortUchar( Adapter->PortOffset + EISA_ID_PROM_OFFSET, &IdProm[i] ); #if __DBG DbgPrint ("Eisa: IDROM @%x %x r\n", Adapter->PortOffset + EISA_ID_PROM_OFFSET, IdProm[i]); #endif } // Duplicate the ID Prom data in the 32 upper bytes of // the array to cover the case where the 2 test patterns // rap around the 32 bytes block MOVE_MEMORY ( &IdProm[SROM_IEEE_LEN], &IdProm[0], SROM_IEEE_LEN ); //Align on the test patterns for (i=4; i <= SROM_IEEE_LEN*2; i++) { if ( (*(UNALIGNED ULONG *)&IdProm[i-4] == TEST_PATTERN) && (*(UNALIGNED ULONG *)&IdProm[i] == TEST_PATTERN) ) break; } if ( i >= SROM_IEEE_LEN ) { // The test patterns were not found Adapter->PermanentAddressValid = FALSE; return NDIS_STATUS_SUCCESS; } else { EthAddress = &IdProm[i+4]; } break; } if (IS_NULL_ADDRESS(EthAddress)) { Adapter->PermanentAddressValid = FALSE; #if __DBG DbgPrint ("SROM: NULL Burnt_In Ethernet Address\n"); #endif } else if ((*(PULONG)EthAddress & 0xFFFFFF) == ZX312_SIGNATURE) { // Zynx ZX312 Rev3's SROM does not contain a checksum Adapter->PermanentAddressValid = TRUE; #if __DBG DbgPrint ("SROM: ZX312 Rev3\n"); #endif } else { Adapter->PermanentAddressValid = VerifyChecksum(EthAddress); #if __DBG if (!Adapter->PermanentAddressValid) DbgPrint ("SROM: Invalid CheckSum\n"); #endif } if (Adapter->PermanentAddressValid) { MOVE_MEMORY ( &Adapter->PermanentNetworkAddress[0], EthAddress, ETH_LENGTH_OF_ADDRESS ); } //Sia values Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21040_SIA0_10BT; Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21040_SIA1_10BT; Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21040_SIA2_10BT; Adapter->Media[Medium10Base2].SiaRegister[0] = DC21040_SIA0_10B2; Adapter->Media[Medium10Base2].SiaRegister[1] = DC21040_SIA1_10B2; Adapter->Media[Medium10Base2].SiaRegister[2] = DC21040_SIA2_10B2; Adapter->Media[Medium10Base5].SiaRegister[0] = DC21040_SIA0_10B5; Adapter->Media[Medium10Base5].SiaRegister[1] = DC21040_SIA1_10B5; Adapter->Media[Medium10Base5].SiaRegister[2] = DC21040_SIA2_10B5; return NDIS_STATUS_SUCCESS; } #pragma NDIS_PAGABLE_FUNCTION(VerifyChecksum) /*+ * * VerifyChecksum * * Routine Description: * * Verify the checksum of an Ethernet Address * * Arguments: * * Adapter - The adapter which is being verified. * * EthAddress - A pointer to the address to be checked * This 6_byte Ethernet address is followed * by a zero byte, followed by a value such * that the sum of a checksum on the Ethernet * address and this value is 0xff. * * Return Value: * * TRUE if success * -*/ BOOLEAN VerifyChecksum( IN UNALIGNED UCHAR *EthAddress ) { UINT i; UCHAR CheckSum[2]; ULONG Sum = 0; // The checksum yields from the polynom: // 10 2 9 8 // (B[0]*2 + B[1]*2 + B[2]*2 + B[3]*2 + B[4]*2 + B[5]) mod (2**16-1) for (i=0; i<= 2; i++) { Sum *= 2; if (Sum > 0xffff) Sum -= 0xffff; Sum += (*(EthAddress+(2*i)) << 8) + *(EthAddress+(2*i)+1); if (Sum > 0xffff) Sum -= 0xffff; } if (Sum >= 0xffff) { Sum = 0; } CheckSum[0] = (UCHAR)(Sum / 0x100); CheckSum[1] = (UCHAR)(Sum % 0x100); #if __DBG DbgPrint(" CheckSum = %02x %02x\n",CheckSum[0],CheckSum[1]); #endif return (*(UNALIGNED USHORT *)CheckSum == *(UNALIGNED USHORT *)(EthAddress + 6)) ; } /*+ * DC21X4ParseExtendedBlock * * Routine Description: * * This routine is called by the SROM Parser and takes care of the * parsing of the info block with Extended format (EXT=1) in the 21140's * info leaf. * * Arguments: * * Adapter - Pointer to the Data Structure * MediaBlock - Pointer to the Serial Rom data. * GeneralPurposeCtrl - Value of the General Purpose Ctrl * * Return Value: * * None * -*/ extern VOID DC21X4ParseExtendedBlock( IN PDC21X4_ADAPTER Adapter, IN OUT UNALIGNED UCHAR **MediaBlock, IN USHORT GeneralPurposeCtrl, OUT PUCHAR PMediaCode ) { UNALIGNED UCHAR *DataBytePtr; UNALIGNED USHORT *DataWordPtr; UNALIGNED UCHAR *EndOfBlock; UCHAR MediaCode; INT i; INT PhyNumber; UCHAR Length; UCHAR Type; USHORT External; DataBytePtr = (UNALIGNED CHAR *)(*MediaBlock); Length = (*(DataBytePtr++) & LENGTH); EndOfBlock = DataBytePtr + Length; Type = *(DataBytePtr++); #if __DBG DbgPrint("Block Length =%02x\n", Length); DbgPrint("Block Type =%02x\n", Type); #endif switch (Type) { case TYPE_0: DC21X4ParseFixedBlock( Adapter, &DataBytePtr, GeneralPurposeCtrl, PMediaCode ); break; case TYPE_1: case TYPE_3: PhyNumber = (INT) *(DataBytePtr++); if (PhyNumber >= MAX_PHY_TABLE) { #if __DBG DbgPrint("PhyNumber =%02x Out of RANGE!!!\n", PhyNumber); #endif break; } //General Purpose Control Adapter->Phy[PhyNumber].GeneralPurposeCtrl = GeneralPurposeCtrl; //General Purpose Data Adapter->Phy[PhyNumber].GepSequenceLength = (INT) *(DataBytePtr++); if (Adapter->Phy[PhyNumber].GepSequenceLength > MAX_GPR_SEQUENCE) { #if __DBG DbgPrint("GepSequence =%02x Out of RANGE!!!\n", Adapter->Phy[PhyNumber].GepSequenceLength ); #endif break; } switch (Type) { case TYPE_1: //GepSequence Length in bytes for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) { Adapter->Phy[PhyNumber].GepSequence[i] = *(DataBytePtr++); } break; case TYPE_3: //GepSequence Length in words for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) { Adapter->Phy[PhyNumber].GepSequence[i] = *(UNALIGNED USHORT *)(DataBytePtr); DataBytePtr += sizeof(USHORT); } break; } // Reset sequence Adapter->Phy[PhyNumber].ResetSequenceLength = (INT) *(DataBytePtr++); if (Adapter->Phy[PhyNumber].ResetSequenceLength > MAX_RESET_SEQUENCE) { #if __DBG DbgPrint("ResetSequence =%02x Out of RANGE!!!\n", Adapter->Phy[PhyNumber].ResetSequenceLength ); #endif break; } for (i=0; i < Adapter->Phy[PhyNumber].ResetSequenceLength; i++) { Adapter->Phy[PhyNumber].ResetSequence[i] = *(DataBytePtr++); } // Capabilities,Nway,FullDuplex & TxmThreshold DataWordPtr = (UNALIGNED USHORT *) DataBytePtr; Adapter->Phy[PhyNumber].MediaCapabilities = (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK); Adapter->Phy[PhyNumber].NwayAdvertisement = (*(DataWordPtr++) & NWAY_ADVERTISEMENT_MASK); Adapter->Phy[PhyNumber].FullDuplexBits = (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK); Adapter->Phy[PhyNumber].TxThresholdModeBits = (*(DataWordPtr++) & MEDIA_CAPABILITIES_MASK); Adapter->Phy[PhyNumber].Present = TRUE; Adapter->PhyMediumInSrom = TRUE; DataBytePtr = (UNALIGNED UCHAR *) DataWordPtr; // GEP Interrupt switch (Type) { case TYPE_3: Adapter->Phy[PhyNumber].GepInterruptMask = *(DataBytePtr++) << DC21X4_GEP_INTERRUPT_BIT_SHIFT; break; } #if __DBG DbgPrint("PHY Number= %02x\n", PhyNumber); DbgPrint("GPR Sequence Length= %d\n", Adapter->Phy[PhyNumber].GepSequenceLength); for (i=0; i < Adapter->Phy[PhyNumber].GepSequenceLength; i++) { DbgPrint("GPR Sequence[%d]=%02x\n", i, Adapter->Phy[PhyNumber].GepSequence[i]); } DbgPrint("RESET Sequence Length= %d\n", Adapter->Phy[PhyNumber].ResetSequenceLength); for (i=0; i < Adapter->Phy[PhyNumber].ResetSequenceLength; i++) { DbgPrint("RESET Sequence[%d]=%02x\n", i, Adapter->Phy[PhyNumber].ResetSequence[i]); } DbgPrint("Media Capabilities= %04x\n", Adapter->Phy[PhyNumber].MediaCapabilities); DbgPrint("NWAY Advertisement= %04x\n", Adapter->Phy[PhyNumber].NwayAdvertisement); DbgPrint("FD Bit map= %02x\n",Adapter->Phy[PhyNumber].FullDuplexBits); DbgPrint("TTM Bit map= %02x\n",Adapter->Phy[PhyNumber].TxThresholdModeBits); DbgPrint("GEP Interrupt mask = %01x\n",Adapter->Phy[PhyNumber].GepInterruptMask); #endif break; case TYPE_2: MediaCode = *(DataBytePtr) & DC21X4_MEDIA; if (MediaCode >= MAX_MEDIA_TABLE) { break; } Adapter->MediaCapable |= 1 << MediaCode; External = *(DataBytePtr++) & EXT; #if __DBG DbgPrint("SRom: Media Code= %02x\n", MediaCode); DbgPrint("SRom: Media Capable= %02x\n", Adapter->MediaCapable); #endif DataWordPtr = (UNALIGNED USHORT *)DataBytePtr; if (External) { // EXT bit is set : // overwrite the SIA Registers default values // with the values stored into the SROM Adapter->Media[MediaCode].SiaRegister[0] = ((ULONG)*(DataWordPtr++) & 0xFFFF); Adapter->Media[MediaCode].SiaRegister[1] = ((ULONG)*(DataWordPtr++) & 0xFFFF); Adapter->Media[MediaCode].SiaRegister[2] = ((ULONG)*(DataWordPtr++) & 0xFFFF); #if __DBG DbgPrint("SRom: EXT= 1:\n"); DbgPrint("SRom: SiaReg[0]= %08x\n",Adapter->Media[MediaCode].SiaRegister[0]); DbgPrint("SRom: SiaReg[1]= %08x\n",Adapter->Media[MediaCode].SiaRegister[1]); DbgPrint("SRom: SiaReg[2]= %08x\n",Adapter->Media[MediaCode].SiaRegister[2]); #endif } Adapter->Media[MediaCode].GeneralPurposeCtrl = ((ULONG)*(DataWordPtr++) & 0xFFFF); Adapter->Media[MediaCode].GeneralPurposeData = ((ULONG)*(DataWordPtr) & 0xFFFF); #if __DBG DbgPrint("SRom: Gep Ctrl = %08x\n",Adapter->Media[MediaCode].GeneralPurposeCtrl); DbgPrint("SRom: Gep Data = %08x\n",Adapter->Media[MediaCode].GeneralPurposeData); #endif *PMediaCode = MediaCode; break; default: #if __DBG DbgPrint("Type =%02x unknown... skipping\n", Type ); #endif break; } *MediaBlock = EndOfBlock; } /*+ * DC21X4ParseFixedBlock * * Routine Description: * * This routine is called by the SROM Parser and takes care of the * parsing of the info block with fixed format (EXT=0) in the 21140's * info leaf. * * Arguments: * * Adapter - Pointer to the Data Structure * DataBytePtr - Pointer to the Serial Rom data. * GeneralPurposeCtrl - Value of the General Purpose Ctrl * * Return Value: * * None. * -*/ extern VOID DC21X4ParseFixedBlock( IN PDC21X4_ADAPTER Adapter, IN OUT UNALIGNED UCHAR **MediaBlock, IN USHORT GeneralPurposeCtrl, OUT PUCHAR PMediaCode ) { UNALIGNED UCHAR *DataBytePtr; UCHAR MediaCode; DataBytePtr = (UNALIGNED CHAR *)(*MediaBlock); MediaCode = *(DataBytePtr) & DC21X4_MEDIA; if (MediaCode >= MAX_MEDIA_TABLE) { DataBytePtr += ((2*sizeof(DataBytePtr)) + sizeof(USHORT)); *MediaBlock = DataBytePtr; return ; } Adapter->MediaCapable |= 1 << MediaCode; Adapter->Media[MediaCode].GeneralPurposeCtrl = (ULONG)GeneralPurposeCtrl; Adapter->Media[MediaCode].GeneralPurposeData = (ULONG)(*(++DataBytePtr) & 0xFF); Adapter->Media[MediaCode].Mode = GET_MODE(++DataBytePtr); Adapter->Media[MediaCode].Polarity = GET_POLARITY(DataBytePtr); Adapter->Media[MediaCode].SenseMask = GET_SENSE_MASK(DataBytePtr); #if __DBG DbgPrint("Media Code= %02x\n", MediaCode); DbgPrint("Media Capable= %02x\n", Adapter->MediaCapable); DbgPrint("GPData= %02x\n",Adapter->Media[MediaCode].GeneralPurposeData); DbgPrint("Mode= %02x\n",Adapter->Media[MediaCode].Mode); DbgPrint("Polarity= %x\n",Adapter->Media[MediaCode].Polarity); DbgPrint("Sense Mask= %x\n",Adapter->Media[MediaCode].SenseMask); #endif Adapter->Media[MediaCode].Mode |= (Adapter->Media[MediaCode].Mode & DC21X4_TXM_THRESHOLD_MODE)? Adapter->Threshold10Mbps : Adapter->Threshold100Mbps; if ( Adapter->Media[MediaCode].SenseMask && MediaCode != Medium10BaseTFd && MediaCode != Medium100BaseTxFd && MediaCode != Medium100BaseFxFd){ //Add the media code to the MediaPrecedence table Adapter->MediaPrecedence[Adapter->MediaCount++] = MediaCode; } // Check if default media if (IF_DEFAULT_MEDIA(DataBytePtr)) { Adapter->DefaultMediumFlag = TRUE; Adapter->DefaultMedium = MediaCode; #if __DBG DbgPrint("SRom: Default Media = %04x\n",MediaCode); #endif } *PMediaCode = MediaCode; DataBytePtr += sizeof(USHORT); *MediaBlock = DataBytePtr; } #pragma NDIS_PAGABLE_FUNCTION(DC21X4ParseSRom) /* * DC21X4ParseSRom * * Routine Description: * * ParseSRom parses the Serial ROM to retrieve the Ethernet Station * address of the adapter and the adapter's media specific information * * Adapter - pointer to adapter structure * * Return Value: * * Ndis Status * -*/ NDIS_STATUS DC21X4ParseSRom( IN PDC21X4_ADAPTER Adapter ) { PSROM_ID_BLOCK SRomIdBlock; UNALIGNED ADAPTER_ENTRIES *AdapterEntry; UNALIGNED UCHAR *DataBytePtr; UNALIGNED USHORT *DataWordPtr; PUCHAR SRomData; USHORT GeneralPurposeCtrl; USHORT MediaCount; USHORT MediaType; UCHAR MediaCode; ULONG Offset = 0; INT Index = 0; INT i; BOOLEAN ExtendedFormat; ULONG CheckSum; UCHAR Tmp[ETH_LENGTH_OF_ADDRESS]; UCHAR DC21140Leaf [] = { 0x00,0x08, // AutoSense 0x1f, // General Purpose Ctrl 0x04, // Media Count 0x00,0x0b,0x8e,0x00, // Tp 0x03,0x1b,0x6d,0x00, // 100BaseTx 0x04,0x03,0x8e,0x00, // TpFd 0x05,0x1b,0x6d,0x00 // 100BaseTxFd }; UCHAR DE500Strng[] = {"DE500-XA"}; NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS; // Allocate space to dump the whole SROM ALLOC_MEMORY (&NdisStatus, &SRomData, SROM_SIZE); if (NdisStatus != NDIS_STATUS_SUCCESS) { #if __DBG DbgPrint ( "SROM ALLOC_MEMORY FAILED\n"); #endif return NdisStatus; } // Read the whole ROM if (DC21X4ReadSRom( Adapter, &Offset, SROM_SIZE, SRomData)) { SRomIdBlock = (PSROM_ID_BLOCK)SRomData; } else { #if __DBG DbgPrint ( "ReadSRom failed\n"); #endif FREE_MEMORY(SRomData, SROM_SIZE); return NDIS_STATUS_HARD_ERRORS; } // Check the Checksum CheckSum = CRC32(SRomData,SROM_SIZE-2) & 0xFFFF; if (CheckSum != *(PUSHORT)&SRomData[SROM_SIZE-2]) { // Check if the SROM is a "legacy" formated SROM // containing only the network address if ((Adapter-> DeviceId == DC21140_CFID) && !IS_NULL_ADDRESS(SRomData) && VerifyChecksum(SRomData) ) { #if __DBG DbgPrint ( "Legacy SRom...\n"); #endif MOVE_MEMORY ( &Adapter->PermanentNetworkAddress[0], &SRomData[0], ETH_LENGTH_OF_ADDRESS ); Adapter->PermanentAddressValid = TRUE; SRomIdBlock->FormatVersion = SROM_LEGACY; DataBytePtr = &DC21140Leaf[0]; } else { #if __DBG DbgPrint ( "Invalid SROM Checksum - Expected:%04x Read:%04x\n", CheckSum,*(PUSHORT)&SRomData[SROM_SIZE-2]); #endif FREE_MEMORY(SRomData, SROM_SIZE); return NDIS_STATUS_SOFT_ERRORS; } } // Check the SROM Version switch (SRomIdBlock->FormatVersion) { default: #if __DBG DbgPrint ("SRom: Unsupported Format Version (%x)!\n", SRomIdBlock->FormatVersion); #endif FREE_MEMORY(SRomData, SROM_SIZE); return NDIS_STATUS_SOFT_ERRORS; case SROM_V1: case SROM_V3: // Parse the Adapter Device Number. #if __DBG DbgPrint ("SRom: Version: %2x\n",SRomIdBlock->FormatVersion ); DbgPrint ("SRom: Adapter Count: %2x\n", SRomIdBlock->AdapterCount); DbgPrint ("SRom: Network Base Address: %02x-%02x-%02x-%02x-%02x-%02x\n", SRomIdBlock->NetworkAddress[0],SRomIdBlock->NetworkAddress[1], SRomIdBlock->NetworkAddress[2],SRomIdBlock->NetworkAddress[3], SRomIdBlock->NetworkAddress[4],SRomIdBlock->NetworkAddress[5]); #endif AdapterEntry = (PADAPTER_ENTRIES)&SRomData[sizeof(SROM_ID_BLOCK)]; if ((INT)SRomIdBlock->AdapterCount > 1) { // Parse the Adapter's Device Number. for (; Index < (INT)SRomIdBlock->AdapterCount; Index++,AdapterEntry++) { #if __DBG DbgPrint ("SRom: DeviceNumber, %2x\n",AdapterEntry->DeviceNumber ); DbgPrint ("SRom: Offset, %4x\n", AdapterEntry->Offset); #endif if (AdapterEntry->DeviceNumber == (UCHAR)Adapter->SlotNumber) { break; } } } if (Index == (INT)SRomIdBlock->AdapterCount) { #if __DBG DbgPrint("SRom: Adapter's Device Number %d not found in SROM\n", Adapter->SlotNumber); #endif FREE_MEMORY(SRomData, SROM_SIZE); return NDIS_STATUS_ADAPTER_NOT_FOUND; } // Check if the Station Address is a NULL Address if IS_NULL_ADDRESS(SRomIdBlock->NetworkAddress) { #if __DBG DbgPrint ("SRom: NULL Network Address\n"); #endif Adapter->PermanentAddressValid = FALSE; } else { if (Index !=0) { // Add the adapter index to the base network Address // (The carry is propagated to the 3 lower bytes // of the address only (the 3 upper bytes are the vendor id)) for (i=0;i<3;i++) { Tmp[i] = SRomIdBlock->NetworkAddress[ETH_LENGTH_OF_ADDRESS-(i+1)]; } *(UNALIGNED ULONG *)&Tmp[0] += Index; for (i=0;i<3;i++) { SRomIdBlock->NetworkAddress[ETH_LENGTH_OF_ADDRESS-(i+1)] = Tmp[i]; } } #if __DBG DbgPrint ("SRom: Network Address: %02x-%02x-%02x-%02x-%02x-%02x\n", SRomIdBlock->NetworkAddress[0],SRomIdBlock->NetworkAddress[1], SRomIdBlock->NetworkAddress[2],SRomIdBlock->NetworkAddress[3], SRomIdBlock->NetworkAddress[4],SRomIdBlock->NetworkAddress[5]); #endif MOVE_MEMORY ( &Adapter->PermanentNetworkAddress[0], SRomIdBlock->NetworkAddress, ETH_LENGTH_OF_ADDRESS ); Adapter->PermanentAddressValid = TRUE; } //Parse the Media Info Blocks. DataBytePtr = &(SRomData[AdapterEntry->Offset]); case SROM_LEGACY: Adapter->MediaCapable = 0; switch (Adapter-> DeviceId) { case DC21041_CFID: // Initialize the Media table with the default values. Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21041_SIA0_10BT; Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21041_SIA1_10BT; Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21041_SIA2_10BT; Adapter->Media[Medium10Base2].SiaRegister[0] = DC21041_SIA0_10B2; Adapter->Media[Medium10Base2].SiaRegister[1] = DC21041_SIA1_10B2; Adapter->Media[Medium10Base2].SiaRegister[2] = DC21041_SIA2_10B2; Adapter->Media[Medium10Base5].SiaRegister[0] = DC21041_SIA0_10B5; Adapter->Media[Medium10Base5].SiaRegister[1] = DC21041_SIA1_10B5; Adapter->Media[Medium10Base5].SiaRegister[2] = DC21041_SIA2_10B5; MediaType = *(UNALIGNED USHORT *)DataBytePtr; DataBytePtr += sizeof(USHORT); MediaCount = *(DataBytePtr++); #if __DBG DbgPrint("SRom: MediaType= %04x \n", MediaType); DbgPrint("SRom: Media Count= %d \n", MediaCount); #endif for (Index=0; Index < MediaCount; Index++) { MediaCode = *DataBytePtr & DC21X4_MEDIA; if (MediaCode >= MAX_MEDIA_TABLE) { DataBytePtr += (sizeof(DataBytePtr) + ((*DataBytePtr & EXT) ? (3 * sizeof(DataWordPtr)):0)); continue; } Adapter->MediaCapable |= 1 << MediaCode; #if __DBG DbgPrint("SRom: Media Code= %02x\n", MediaCode); DbgPrint("SRom: Media Capable= %02x\n", Adapter->MediaCapable); #endif if (*(DataBytePtr++) & EXT) { // EXT bit is set : // overwrite the SIA Registers default values // with the values stored into the SROM DataWordPtr = (UNALIGNED USHORT *) DataBytePtr; Adapter->Media[MediaCode].SiaRegister[0] = ((ULONG)*(DataWordPtr++) & 0xFFFF); Adapter->Media[MediaCode].SiaRegister[1] = ((ULONG)*(DataWordPtr++) & 0xFFFF); Adapter->Media[MediaCode].SiaRegister[2] = ((ULONG)*(DataWordPtr++) & 0xFFFF); DataBytePtr = (UNALIGNED UCHAR *) DataWordPtr; #if __DBG DbgPrint("SRom: EXT= 1:\n"); DbgPrint("SRom: SiaReg[0]= %08x\n",Adapter->Media[MediaCode].SiaRegister[0]); DbgPrint("SRom: SiaReg[1]= %08x\n",Adapter->Media[MediaCode].SiaRegister[1]); DbgPrint("SRom: SiaReg[2]= %08x\n",Adapter->Media[MediaCode].SiaRegister[2]); #endif } } break; case DC21140_CFID: switch (SRomIdBlock->FormatVersion) { case SROM_LEGACY: case SROM_V1: if (Adapter->RevisionNumber == DC21140_REV1_1) { Adapter->DynamicAutoSense = BOARD_SIGNATURE(SRomData); break; } default: //MediaType MediaType = *(UNALIGNED USHORT *)DataBytePtr; Adapter->DynamicAutoSense = ((MediaType & DISABLE_AUTOSENSE) == 0); #if __DBG DbgPrint("SRom: MediaType= %04x \n", MediaType); #endif } #if __DBG DbgPrint("SRom: Dynamic Autosense %s\n", Adapter->DynamicAutoSense? "Enabled":"Disabled"); #endif DataBytePtr += sizeof(USHORT); GeneralPurposeCtrl = (((USHORT)*(DataBytePtr++) & 0xFF)|(0x100)); MediaCount = *(DataBytePtr++); #if __DBG DbgPrint("SRom: General Purpose Control= %08x \n", GeneralPurposeCtrl); DbgPrint("SRom: MediaCount= %d \n", MediaCount); #endif for (Index=0; Index < MediaCount; Index++) { ExtendedFormat = (*DataBytePtr & EXTENDED_FORMAT); if ((SRomIdBlock->FormatVersion == SROM_V3) && ExtendedFormat) { DC21X4ParseExtendedBlock( Adapter, &DataBytePtr, GeneralPurposeCtrl, &MediaCode ); } else { DC21X4ParseFixedBlock( Adapter, &DataBytePtr, GeneralPurposeCtrl, &MediaCode ); } } if (!Adapter->DefaultMediumFlag && Adapter->MediaCount>0) { Adapter->DefaultMedium = Adapter->MediaPrecedence[Adapter->MediaCount-1]; } break; case DC21142_CFID: if (SRomIdBlock->FormatVersion < SROM_V3) { #if __DBG DbgPrint ("SRom: Unsupported Format Version (%x)!\n", SRomIdBlock->FormatVersion); #endif FREE_MEMORY(SRomData, SROM_SIZE); return NDIS_STATUS_SOFT_ERRORS; } // Initialize the Media table with the default values. Adapter->Media[Medium10BaseT].SiaRegister[0] = DC21142_SIA0_10BT; Adapter->Media[Medium10BaseT].SiaRegister[1] = DC21142_SIA1_10BT; Adapter->Media[Medium10BaseT].SiaRegister[2] = DC21142_SIA2_10BT; Adapter->Media[Medium10Base2].SiaRegister[0] = DC21142_SIA0_10B2; Adapter->Media[Medium10Base2].SiaRegister[1] = DC21142_SIA1_10B2; Adapter->Media[Medium10Base2].SiaRegister[2] = DC21142_SIA2_10B2; Adapter->Media[Medium10Base5].SiaRegister[0] = DC21142_SIA0_10B5; Adapter->Media[Medium10Base5].SiaRegister[1] = DC21142_SIA1_10B5; Adapter->Media[Medium10Base5].SiaRegister[2] = DC21142_SIA2_10B5; MediaType = *(UNALIGNED USHORT *)DataBytePtr; Adapter->DynamicAutoSense = ((MediaType & DISABLE_AUTOSENSE) == 0); #if __DBG DbgPrint("SRom: Dynamic Autosense %s\n", Adapter->DynamicAutoSense? "Enabled":"Disabled"); #endif DataBytePtr += sizeof(USHORT); MediaCount = *(DataBytePtr++); #if __DBG DbgPrint("SRom: MediaType= %04x \n", MediaType); DbgPrint("SRom: MediaCount= %d \n", MediaCount); #endif for (Index=0; Index < MediaCount; Index++) { DC21X4ParseExtendedBlock( Adapter, (PVOID)&DataBytePtr, (USHORT)NULL, &MediaCode ); } if (!Adapter->DefaultMediumFlag && Adapter->MediaCount>0) { Adapter->DefaultMedium = Adapter->MediaPrecedence[Adapter->MediaCount-1]; } break; default: NdisStatus = NDIS_STATUS_DEVICE_FAILED; } break; } if ( (MediaCount == 1) && Adapter->MediaCapable && !Adapter->PhyMediumInSrom ) { //Force MediaType to the single supported medium #if __DBG DbgPrint("SRom: One single supported medium: Force MediaType %04x to ",Adapter->MediaType); #endif Adapter->MediaType &= ~(MEDIA_MASK | MEDIA_AUTOSENSE); Adapter->MediaType |= MediaCode; #if __DBG DbgPrint("%04x\n",Adapter->MediaType); #endif } //if no 10Base port is populated, switch Port_Select to 100Base if (!(Adapter->MediaCapable & (MEDIUM_10BT | MEDIUM_10B2 | MEDIUM_10B5))) { Adapter->OperationMode |= DC21X4_PORT_SELECT; } FREE_MEMORY(SRomData, SROM_SIZE); return NdisStatus; } #pragma NDIS_PAGABLE_FUNCTION(DC21X4ReadSRom) /* * DC21X4ReadSRom * * Routine Description: * * ReadSRom is called by DC21X4RegisterAdapter to read the onboard ROM * for the network address and other parameters. * This routine reads the required number of bytes from the given * offset in the ROM. * * Arguments: * * Adapter - * * Offset - byte offset into SROM to start reading from. Must * be word aligned * Len - number of bytes to read * Data - pointer to buffer to read data into. * if NULL, don't return data * * Return Value: * * TRUE if success, FALSE if hardware failure encountered. * -*/ BOOLEAN DC21X4ReadSRom( IN PDC21X4_ADAPTER Adapter, IN OUT PULONG Offset, IN USHORT Len, OUT PUCHAR Buffer ) { INT i; INT j; ULONG Dbit; ULONG Dout; USHORT WOffset; USHORT WLen; USHORT WData; // Make sure the ROM_Address is EVEN. if (*Offset & 1) { #if __DBG DbgPrint ("ReadSRom failure - Offset not word aligned\n"); #endif return FALSE; } // Round up the length to multiple of words. WLen = (Len + 1) / 2; // Convert the ROM_Address byte offset to word offset WOffset = (USHORT)(*Offset >> 1); // Make sure the requested read does not exceed the ROM size if ( (WOffset + WLen) > SROM_93LC46B_SIZE) { #if __DBG DbgPrint ("ReadSRom warning - address range excedes ROM size\n"); #endif return FALSE; } // Switch CSR to work with new SROM interface DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM ); // Make sure SROM is in idle state // (deliver it enough clocks with CS set, Din = 0). for (i = 0; i < SROM_93LC46B_MAX_CYCLES; i++) { DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS ); NdisStallExecution(SROM_93LC46B_DELAY); } DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM ); NdisStallExecution(SROM_93LC46B_DELAY); // Read the data for (j = 0; j < WLen; j++,WOffset++) { //Output the READ command to the SROM DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_1 ); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK | DATA_1 ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_1 ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_1 ); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK | DATA_1 ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_1 ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_0 ); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK | DATA_0 ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | DATA_0 ); NdisStallExecution(SROM_93LC46B_DELAY); // Output the WORD Address of the SROM for (i = SROM_93LC46B_ADDRESS_MSB; i>= 0; i--) { Dbit = (USHORT)((WOffset >> i) & 1) << 2; DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | Dbit ); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK | Dbit ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | Dbit ); NdisStallExecution(SROM_93LC46B_DELAY); } // Verify that the SROM output data became now 0. DC21X4_READ_PORT( DC21X4_IDPROM, &Dout ); if (Dout & SROM_93LC46B_VALID_BITMASK) { #if __DBG DbgPrint ("ReadSRom failure - SROM didn't become busy in read command\n"); #endif return(FALSE); } // Read the data from the SROM WData = 0; for (i = SROM_93LC46B_DATA_MSB; i >= 0; i--) { DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS | CLK ); NdisStallExecution(SROM_93LC46B_DELAY); DC21X4_READ_PORT( DC21X4_IDPROM, &Dout ); DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM | CS ); WData |= ((Dout >> SROM_93LC46B_DATA_BIT) & 1) << i; NdisStallExecution(SROM_93LC46B_DELAY); } #if _DBG DbgPrint("Data = %04x\n",WData); #endif // Put our read data in user buffer if (Buffer) { if (Len >= 2) { *(PUSHORT)Buffer = WData; Buffer += 2; Len -= 2; } else { // Least significant byte only is copied *Buffer = WData & 0xff; Buffer++; Len--; } } //Negate the chip select (CS) to end the SROM command DC21X4_WRITE_PORT( DC21X4_IDPROM, CSR_WRITE | SEL_SROM ); NdisStallExecution(SROM_93LC46B_DELAY); } *Offset = WOffset << 1; return TRUE; }