2020-09-30 17:12:29 +02:00

1522 lines
41 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*+
* 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 <precomp.h>
#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;
}