windows-nt/Source/XPSP1/NT/drivers/net/ms/e100bex/eeprom.c
2020-09-26 16:20:57 +08:00

304 lines
8.5 KiB
C

/****************************************************************************
** COPYRIGHT (C) 1994-1997 INTEL CORPORATION **
** DEVELOPED FOR MICROSOFT BY INTEL CORP., HILLSBORO, OREGON **
** HTTP://WWW.INTEL.COM/ **
** THIS FILE IS PART OF THE INTEL ETHEREXPRESS PRO/100B(TM) AND **
** ETHEREXPRESS PRO/100+(TM) NDIS 5.0 MINIPORT SAMPLE DRIVER **
****************************************************************************/
/****************************************************************************
Module Name:
eeprom.c
This driver runs on the following hardware:
- 82558 based PCI 10/100Mb ethernet adapters
(aka Intel EtherExpress(TM) PRO Adapters)
Environment:
Kernel Mode - Or whatever is the equivalent on WinNT
Revision History
- JCB 8/14/97 Example Driver Created
- Dchen 11-01-99 Modified for the new sample driver
*****************************************************************************/
#include "precomp.h"
#pragma hdrstop
#pragma warning (disable: 4244 4514)
#define EEPROM_MAX_SIZE 256
//*****************************************************************************
//
// I/O based Read EEPROM Routines
//
//*****************************************************************************
//-----------------------------------------------------------------------------
// Procedure: EEpromAddressSize
//
// Description: determines the number of bits in an address for the eeprom
// acceptable values are 64, 128, and 256
//
// Arguments:
// Size -- size of the eeprom
//
// Returns:
// bits in an address for that size eeprom
//-----------------------------------------------------------------------------
USHORT GetEEpromAddressSize(
IN USHORT Size)
{
switch (Size)
{
case 64: return 6;
case 128: return 7;
case 256: return 8;
}
return 0;
}
//-----------------------------------------------------------------------------
// Procedure: GetEEpromSize
//
// Description: This routine determines the size of the EEPROM.
//
// Arguments:
// Reg - EEPROM word to read.
//
// Returns:
// Size of the EEPROM, or zero if error.
//-----------------------------------------------------------------------------
USHORT GetEEpromSize(
IN PUCHAR CSRBaseIoAddress)
{
USHORT x, data;
USHORT size = 1;
// select EEPROM, reset bits, set EECS
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~(EEDI | EEDO | EESK);
x |= EECS;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
// write the read opcode
ShiftOutBits(EEPROM_READ_OPCODE, 3, CSRBaseIoAddress);
// experiment to discover the size of the eeprom. request register zero
// and wait for the eeprom to tell us it has accepted the entire address.
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
do
{
size *= 2; // each bit of address doubles eeprom size
x |= EEDO; // set bit to detect "dummy zero"
x &= ~EEDI; // address consists of all zeros
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
NdisStallExecution(100);
RaiseClock(&x, CSRBaseIoAddress);
LowerClock(&x, CSRBaseIoAddress);
// check for "dummy zero"
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
if (size > EEPROM_MAX_SIZE)
{
size = 0;
break;
}
}
while (x & EEDO);
// Now read the data (16 bits) in from the selected EEPROM word
data = ShiftInBits(CSRBaseIoAddress);
EEpromCleanup(CSRBaseIoAddress);
return size;
}
//-----------------------------------------------------------------------------
// Procedure: ReadEEprom
//
// Description: This routine serially reads one word out of the EEPROM.
//
// Arguments:
// Reg - EEPROM word to read.
//
// Returns:
// Contents of EEPROM word (Reg).
//-----------------------------------------------------------------------------
USHORT ReadEEprom(
IN PUCHAR CSRBaseIoAddress,
IN USHORT Reg,
IN USHORT AddressSize)
{
USHORT x;
USHORT data;
// select EEPROM, reset bits, set EECS
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~(EEDI | EEDO | EESK);
x |= EECS;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
// write the read opcode and register number in that order
// The opcode is 3bits in length, reg is 6 bits long
ShiftOutBits(EEPROM_READ_OPCODE, 3, CSRBaseIoAddress);
ShiftOutBits(Reg, AddressSize, CSRBaseIoAddress);
// Now read the data (16 bits) in from the selected EEPROM word
data = ShiftInBits(CSRBaseIoAddress);
EEpromCleanup(CSRBaseIoAddress);
return data;
}
//-----------------------------------------------------------------------------
// Procedure: ShiftOutBits
//
// Description: This routine shifts data bits out to the EEPROM.
//
// Arguments:
// data - data to send to the EEPROM.
// count - number of data bits to shift out.
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID ShiftOutBits(
IN USHORT data,
IN USHORT count,
IN PUCHAR CSRBaseIoAddress)
{
USHORT x,mask;
mask = 0x01 << (count - 1);
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~(EEDO | EEDI);
do
{
x &= ~EEDI;
if(data & mask)
x |= EEDI;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
NdisStallExecution(100);
RaiseClock(&x, CSRBaseIoAddress);
LowerClock(&x, CSRBaseIoAddress);
mask = mask >> 1;
} while(mask);
x &= ~EEDI;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
}
//-----------------------------------------------------------------------------
// Procedure: ShiftInBits
//
// Description: This routine shifts data bits in from the EEPROM.
//
// Arguments:
//
// Returns:
// The contents of that particular EEPROM word
//-----------------------------------------------------------------------------
USHORT ShiftInBits(
IN PUCHAR CSRBaseIoAddress)
{
USHORT x,d,i;
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~( EEDO | EEDI);
d = 0;
for(i=0; i<16; i++)
{
d = d << 1;
RaiseClock(&x, CSRBaseIoAddress);
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~(EEDI);
if(x & EEDO)
d |= 1;
LowerClock(&x, CSRBaseIoAddress);
}
return d;
}
//-----------------------------------------------------------------------------
// Procedure: RaiseClock
//
// Description: This routine raises the EEPOM's clock input (EESK)
//
// Arguments:
// x - Ptr to the EEPROM control register's current value
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID RaiseClock(
IN OUT USHORT *x,
IN PUCHAR CSRBaseIoAddress)
{
*x = *x | EESK;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x);
NdisStallExecution(100);
}
//-----------------------------------------------------------------------------
// Procedure: LowerClock
//
// Description: This routine lower's the EEPOM's clock input (EESK)
//
// Arguments:
// x - Ptr to the EEPROM control register's current value
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID LowerClock(
IN OUT USHORT *x,
IN PUCHAR CSRBaseIoAddress)
{
*x = *x & ~EESK;
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), *x);
NdisStallExecution(100);
}
//-----------------------------------------------------------------------------
// Procedure: EEpromCleanup
//
// Description: This routine returns the EEPROM to an idle state
//
// Arguments:
//
// Returns: (none)
//-----------------------------------------------------------------------------
VOID EEpromCleanup(
IN PUCHAR CSRBaseIoAddress)
{
USHORT x;
x = READ_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG));
x &= ~(EECS | EEDI);
WRITE_PORT_USHORT((PUSHORT)(CSRBaseIoAddress + CSR_EEPROM_CONTROL_REG), x);
RaiseClock(&x, CSRBaseIoAddress);
LowerClock(&x, CSRBaseIoAddress);
}