📄 miiphy.c
字号:
/*
*
* MIIPHY.EXE
*
* This utility programs configurations of an MII compliant and
* manageable PHY device attached connected to a MAC of the FEAST
* (91C1XXxx) or EPIC (83C17X) families.
*
* Compiled with Borland C++ v3.1 (Small model)
*
*
* 11/23/99 PG v2.21 Added the support for 91c110 dual function
* card.
*
* 01/07/99 RK v2.20 Fix incorrect OUI reporting when forced PHY
* address is used.
* Use Proprietary status to report duplex and
* speed when possible (instead of command)
* Add support for SEEQ PHY.
* 10/28/98 RK v2.10 Fix access to PHYs from all EVBs to all
* PHYs including TDK and 180.
* 08/21/98 RK v2.01 Add workaround for full duplex problem
* of FEAST110/FD not receiving if no CRS
* present even in full duplex. change PHY CRS
* default behaviour when in ful;l duplex thru
* bit 24.5
* 08/07/98 RK v2.00 Add EPIC support.
* Change name to MIIPHY.EXE
* Add Q option.
* Add support to handle '/' prefixed commands
* 08/06/98 RK v1.20 Add N, R , I options
* Add support for 83C180
* 11/07/97 RK v1.00 Initial FEASTPHY.EXE version.
*/
// HEADERS
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <stdio.h>
#include <conio.h>
// TYPES
typedef unsigned char uchar;
// DEFINES
#define MAJOR_VER 2
#define MINOR_VER 21
#define DATE_STR "991123"
#define TRUE 1==1
#define FALSE 0==1
#define DBG FALSE
//#define DBG TRUE
#define outword(addr,val) outport(addr,val)
#define inword(addr) inport(addr)
#define MGMT port+0x08 // FEAST Registers
#define BANKSEL port+0x0E
#define CONTROL port+0x0C
#define NV_CONTROL port+0x10
#define TEST port+0x1C
#define MIICTRL port+0x30
#define MIIDATA port+0x34
#define MIICFG port+0x38
#define MIIREAD 0x0001
#define MIIWRITE 0x0002
#define MDO 0x01 // MII Resgiter bits
#define MDI 0x02
#define MCLK 0x04
#define MDOE 0x08
#define MALL 0x0F
#define OPWrite 0x01
#define OPRead 0x02
#define PHY_CR 0 //PHY Registers and bits
#define PHY_CR_Reset 0x8000
#define PHY_CR_Speed 0x2000
#define PHY_CR_Duplex 0x0100
#define PHY_SR 1
#define PHY_ID1 2
#define PHY_ID2 3
// PHY propietary registers
#define PHY_NATIONAL_PAR 0x19
#define PHY_NATIONAL_PAR_DUPLEX 0x0080
#define PHY_NATIONAL_PAR_SPEED_10 0x0040
#define PHY_TDK_DIAG 0x12
#define PHY_TDK_DIAG_DUPLEX 0x0800
#define PHY_TDK_DIAG_RATE 0x0400
#define PHY_QSI_BASETX 0x1F
#define PHY_QSI_BASETX_OPMODE_MASK 0x001c
#define PHY_QSI_BASETX_OPMODE_10HD (2<<0x1)
#define PHY_QSI_BASETX_OPMODE_100HD (2<<0x2)
#define PHY_QSI_BASETX_OPMODE_10FD (2<<0x5)
#define PHY_QSI_BASETX_OPMODE_100FD (2<<0x6)
#define PHY_SEEQ_STATUS_OUTPUT 0x12
#define PHY_SEEQ_SPD_DET 0x80
#define PHY_SEEQ_DPLX_DET 0x40
#define PHY_OUI_QSI 0x006051
#define PHY_OUI_TDK 0x00C039
#define PHY_OUI_MITELSMSC 0x00A087
#define PHY_OUI_NATIONAL 0x080017
#define PHY_OUI_SEEQSMSC 0x0005BE
#define NWAY_TIMEOUT 10
// GLOBAL VARIABLES
unsigned int port=0x0;
unsigned long OUI;
unsigned char Model, Revision;
unsigned char MACType = 'F'; // 'F' for FEAST, 'E' for EPIC
// FUNCTIONS
int hextoi(char *buffer)
{
int i,j,value,result=0;
for (i=(strlen(buffer)-1),j=1;i>=0;i--,j=j*16)
{
value = *(buffer+i);
if ( (value >= 0x30) && (value <= 0x39) )
result += ( (value-'0') * j );
if ( (value >= 0x41) && (value <= 0x46) )
result += ( (value-'A'+10) * j );
if ( (value >= 0x61) && (value <= 0x66) )
result += ( (value-'a'+10) * j );
}
return (result);
}
int dectoi(char *buffer)
{
int i,j,value,result=0;
for (i=(strlen(buffer)-1),j=1;i>=0;i--,j=j*10)
{
value = *(buffer+i);
if ( (value >= 0x30) && (value <= 0x39) )
result += ( (value-'0') * j );
}
return (result);
}
void clkmdio(unsigned MGMTData)
{
outword(MGMT, MGMTData);
outword(MGMT, MGMTData | MCLK);
}
// ---------- Routine that actually generates the MII frames ----------
unsigned PHYAccess(uchar PHYAdd, uchar RegAdd, uchar OPCode, unsigned wData)
{
// Local variables
int i;
unsigned MGMTval;
// Filter unused bits from input variables.
PHYAdd &= 0x1F;
RegAdd &= 0x1F;
OPCode &= 0x03;
if (MACType == 'F')
{
MGMTval = inword(MGMT) & (MALL ^ 0xFFFF);
// Output Preamble (32 '1's)
for (i=0;i<32;i++)
clkmdio(MGMTval | MDOE | MDO);
// Output Start of Frame ('01')
for (i=0;i<2;i++)
clkmdio(MGMTval | MDOE | i);
// Output OPCode ('01' for write or '10' for Read)
for (i=1;i>=0;i--)
clkmdio(MGMTval | MDOE | ((OPCode>>i) & 0x01) );
// Output PHY Address
for (i=4;i>=0;i--)
clkmdio(MGMTval | MDOE | ((PHYAdd>>i) & 0x01) );
// Output Register Address
for (i=4;i>=0;i--)
clkmdio(MGMTval | MDOE | ((RegAdd>>i) & 0x01) );
if (OPCode == OPRead)
{
// Read Operation
// Implement Turnaround ('Z0')
clkmdio(MGMTval);
// clkmdio(MGMTval | MDOE);
// Read Data
wData = 0;
for (i=15;i>=0;i--)
{
clkmdio(MGMTval);
wData |= (((inword(MGMT) & MDI) >> 1) << i);
}
// Add Idle state
clkmdio(MGMTval);
return (wData);
}
else
{
// Write Operation
// Implement Turnaround ('10')
for (i=1;i>=0;i--)
clkmdio(MGMTval | MDOE | ((2>>i) & 0x01));
// Write Data
for (i=15;i>=0;i--)
clkmdio(MGMTval | MDOE | ((wData>>i) & 0x01));
// Add Idle state
clkmdio(MGMTval);
return (1);
}
}
if (MACType == 'E')
{
if (OPCode == OPRead)
{
// Read Operation
outport(MIICTRL, (((unsigned) PHYAdd) << 9) | (((unsigned) RegAdd) << 4) | MIIREAD);
delay(1);
wData = inport(MIIDATA);
#if DBG
printf("For PHYAdd = %02X, RegAdd = %02X, OPCode = %02X, wData = %04X\n\r", PHYAdd, RegAdd, OPCode, wData);
printf("PHY register read = %04X\n\r",wData);
#endif
return(wData);
}
else
{
// Write Operation
#if DBG
printf("Writing to PHYAdd = %02X, RegAdd = %02X, OPCode = %02X, wData = %04X\n\r", PHYAdd, RegAdd, OPCode, wData);
#endif
outport(MIIDATA, wData);
outport(MIICTRL, (((unsigned) PHYAdd) << 9) | (((unsigned) RegAdd) << 4) | MIIWRITE);
delay(1);
return(1);
}
}
return(1);
} // End of Routine
unsigned char DetectPHY(void)
{
unsigned int PhyId1, PhyId2;
unsigned char PhyAdd=0xff;
int Count;
for (Count=31;Count>=0;Count--)
{
PhyId1 = PHYAccess(Count, PHY_ID1, OPRead, 0);
PhyId1 = PHYAccess(Count, PHY_ID1, OPRead, 0);
PhyId2 = PHYAccess(Count, PHY_ID2, OPRead, 0);
PhyId2 = PHYAccess(Count, PHY_ID2, OPRead, 0);
if(
(PhyId1 > 0x0000) &&
(PhyId1 < 0xffff) &&
(PhyId2 > 0x0000) &&
(PhyId2 < 0xffff) &&
((PhyId1 != 0x8000) && (PhyId1 != 0x8000))
)
{
PhyAdd = (unsigned char) Count;
break;
}
delay(1);
}
OUI = (((unsigned long) PhyId1) << 6) | ((PhyId2 & 0xfc00) >> 10);
Model = (unsigned char) ( (PhyId2 & 0x03f0) >> 4 );
Revision = (unsigned char) (PhyId2 & 0x000f);
return(PhyAdd);
}
unsigned char EpicIsThere(void)
{
int i;
#if DBG
unsigned int temp;
#endif
#if DBG
if( (temp = inport(port)) == 0xffff) return(FALSE); //Assume no board if read 0xffff
printf("Read %04X from port %04X\n\r", temp, port);
#else
if( inport(port) == 0xffff) return(FALSE); //Assume no board if read 0xffff
#endif
outport(CONTROL, 0x0001); //Reset EPIC
delay(10); //Wait for Reset complete
for (i=0;i<10;i++) outport(TEST, 0x0008); // Fix flakiness
#if DBG
if((temp = (inport(CONTROL) & 0xefff)) == 0x0100)
#else
if((inport(CONTROL) & 0xefff) == 0x0100)
#endif
{
#if DBG
printf("Read %04X from port %04X\n\r", temp, CONTROL);
#endif
MACType = 'E';
outport(MIICFG, 0x0010); // Enable MII management interface
return(TRUE);
}
else
{
#if DBG
printf("Read %04X from port %04X\n\r", temp, CONTROL);
#endif
return(FALSE);
}
}
unsigned char DetectMAC(void)
{
if(!port)
{
// No port specified, so lets search for a MAC.
// Look for FEAST type MAC @ 300h. This test looks for the 0x33
// signature pattern in the upper byte of the Bankselect register.
port = 0x0300;
if((inword(BANKSEL) & 0xff00) == 0x3300) return(TRUE);
// Look for EPIC type MAC @ 0fc00h, 6000 or 7000h
// A good test would search EPIC using PCI config space.
// The search mechanism used does not, it's just a small
// dummy verification only that checks on the default of
// the Control register after a Reset.
port = 0xfc00;
if(EpicIsThere()) return(TRUE);
port = 0x6000;
if(EpicIsThere()) return(TRUE);
port = 0x7000;
if(EpicIsThere()) return(TRUE);
}
else
{
if((inword(BANKSEL) & 0xff00) == 0x3300) return(TRUE);
if(EpicIsThere()) return(TRUE);
}
// could not find any MAC, report failure.
return(FALSE);
}
// MAIN PROGRAM
void main(int argc, char *argv[])
{
unsigned int i, speed = 10, Address = 0xffff, PHYConfig, PHYConfig2, offset=0xffff, data;
char duplex = 'H';
unsigned char PHYAdd, ReadPort=0, PhyAddrRead=0, ForcedSpeed=0, ForcedDuplex = 0, NWAY=0, quiet = 0,ositech = 0;
char report[100];
// Get parameters and verify they are valid
for (i=1;i<argc;i++)
{
// Skip the first character if not a letter or '?'
if (
(argv[i][0] != '?') &&
(
(argv[i][0] < 'A') ||
(argv[i][0] > 'z') ||
((argv[i][0] > 'Z') && (argv[i][0] <'a'))
)
)
argv[i]++;
if ((argv[i][0] == 'P') || (argv[i][0] == 'p'))
{
// Skip ':' or '=' for numeric inputs as well.
if ((argv[i][1] == ':') || (argv[i][1] == '=')) argv[i]++;
port = hextoi(argv[i]+1);
ReadPort=1;
}
if ((argv[i][0] == 'S') || (argv[i][0] == 's'))
{
// Skip ':' or '=' for numeric inputs as well.
if ((argv[i][1] == ':') || (argv[i][1] == '=')) argv[i]++;
speed = dectoi(argv[i]+1);
ForcedSpeed=1;
}
if ((argv[i][0] == 'D') || (argv[i][0] == 'd'))
{
// Skip ':' or '=' for numeric inputs as well.
if ((argv[i][1] == ':') || (argv[i][1] == '=')) argv[i]++;
duplex = argv[i][1];
if(duplex == 'f') duplex = 'F';
if(duplex == 'h') duplex = 'H';
ForcedDuplex=1;
}
if ((argv[i][0] == 'I') || (argv[i][0] == 'i'))
{
// Skip ':' or '=' for numeric inputs as well.
if ((argv[i][1] == ':') || (argv[i][1] == '=')) argv[i]++;
Address = dectoi(argv[i]+1);
PhyAddrRead = 1;
}
if ((argv[i][0] == 'N') || (argv[i][0] == 'n'))
{
NWAY = 1;
}
if ((argv[i][0] == 'R') || (argv[i][0] == 'r'))
{
argv[i][3]=0;
offset = hextoi(argv[i]+1);
data = hextoi(argv[i]+4);
}
if ((argv[i][0] == 'Q') || (argv[i][0] == 'q'))
quiet = 1;
//PG 11/23/99 91C110 ositech dual function design support
if((argv[i][0] == 'A') || (argv[i][0] == 'a'))
ositech = 1;
}
clrscr();
textcolor(GREEN);
highvideo();
printf("\n\r");
cprintf(" MIIPHY.EXE v%d.%02d (%s)\n\r",MAJOR_VER, MINOR_VER, DATE_STR);
cprintf(" PHY programming utility for SMSC boards.\n\r");
if (argv[1][0] == '?')
{
textcolor(CYAN);
highvideo();
cprintf("\n\rSyntax:\n\r");
cprintf("MIIPHY [P=p] [I=i] [D=d] [S=s] [N] [Roo=xxxx] [Q] [A]\n\r");
printf("\n\r");
printf("p: MAC IO port (hex. If not present will search at 300h, 6000h & 7000h)\n\r");
printf("i: PHY Address (dec 0-31. Default is Autodetect)\n\r");
printf("d: Force Duplex Mode ('F' or 'H')\n\r");
printf("s: Force Speed Selection (10 or 100)\n\r");
printf("N: Perform Autonegotiation (NWAY) and display results\n\r");
printf("R: Write data xxxx into the register offset oo (both values in hex)\n\r");
printf("Q: Run in quiet mode. Does not display the PHY register map\n\r");
printf("A: Reset the PHY (EVB110G-PC-D)\n\r");
printf("\n\r");
printf("Example: MIIPHY P=320 S=100 D=H -> this sets the PHY to operate in 100\n\r");
printf(" Mbps and half duplex modes using the MAC located at IO=320h.\n\r");
printf("\n\r");
printf("All parameters are optional. When using D, S or N a reset will be\n\r");
printf("performed to the PHY before the operation. Unless Q is used the\n\r");
printf("the PHY's register map will be displayed after performing any\n\r");
printf("operation (this does no alteration to the registers). The groups\n\r");
printf("of parameters N, R and (S and/or D) are mutually exclusive.\n\r");
return;
}
else cprintf(" (For Help run: MIIPHY ?)\n\r\n\r");
textcolor(WHITE);
if(
((ForcedSpeed || ForcedDuplex) && NWAY) ||
((ForcedSpeed || ForcedDuplex) && (offset != 0xffff)) ||
(NWAY && (offset != 0xffff))
)
{
textcolor(YELLOW);
highvideo();
cprintf("\n\r\n\rUNRECOVERABLE ERROR: Incompatible options selected together. Type MIIPHY ? \n\r\n\r");
exit(1);
}
if (ReadPort && ((port < 0x100) || (port > 0xff00)))
{
textcolor(YELLOW+BLINK);
highvideo();
cprintf ("INVALID PARAMETER: Port %Xh. MAC will be searched @ 300h, 6000h & 7000h.",port);
delay(3000);
printf("\r \r");
port = 0x300;
}
if ((duplex != 'F') && (duplex !='H'))
{
textcolor(YELLOW+BLINK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -