📄 miilib.c
字号:
/**************************************************************************
*
* miiPhyUnInit - uninitialize a PHY
*
* This routine uninitializes the PHY specified in <pPhyInfo>. It brings it
* in low-power mode, and electrically isolate it from the MII management
* interface to which it is attached. In addition, it frees resources
* previously allocated.
*
* RETURNS: OK, ERROR in case of fatal errors.
*
*/
STATUS miiPhyUnInit
(
PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */
)
{
if (pPhyInfo == NULL)
return (ERROR);
MII_LOG (MII_DBG_ANY, ("miiPhyUnInit \n"),
0, 0, 0, 0, 0, 0);
/* this counts also for isolate */
if (miiProbe (pPhyInfo, pPhyInfo->phyAddr) == ERROR)
return (ERROR);
if (miiPhyPwrDown (pPhyInfo, pPhyInfo->phyAddr) == ERROR)
return (ERROR);
MII_PHY_FLAGS_CLEAR (MII_PHY_INIT);
/* protect it from other MII routines */
MII_SEM_TAKE (WAIT_FOREVER);
lstDelete (&miiList, (NODE *) pPhyInfo->pMiiPhyNode);
/* we're done, release the mutex */
MII_SEM_GIVE ();
/* free memory */
free ((char *) pPhyInfo->pMiiPhyNode);
free ((char *) pPhyInfo->miiPhyPresent);
pPhyInfo->pMiiPhyNode = NULL;
/* stop the monitor if necessary */
if (miiList.count == 0)
return (wdCancel (miiWd));
return (OK);
}
/**************************************************************************
*
* miiProbe - probe the PHY device
*
* This routine probes the PHY device by reading its control register.
* It also checks the PHY can be successfully electrically isolated from its
* MII interface.
*
* RETURNS: OK, ERROR in case of fatal errors.
*
* ERRNO: S_miiLib_PHY_NULL
*
*/
LOCAL STATUS miiProbe
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* the PHY being read */
)
{
UINT8 regAddr; /* the PHY's register being read */
UINT16 data; /* data to be written to the PHY's reg */
int retVal; /* convenient holder for return value */
MII_LOG (MII_DBG_ANY, "miiProbe for addr %#x starts\n",phyAddr,0,0,0,0,0);
regAddr = MII_CTRL_REG;
MII_READ (phyAddr, regAddr, &data, retVal);
if (retVal == ERROR)
return (ERROR);
/* check the reserved bits, and the ability to isolate the PHY */
MII_LOG (MII_DBG_ANY, "miiProbe checking addr %#x\n",phyAddr,0,0,0,0,0);
if (((data & MII_CR_RES_MASK) > 0x0) ||
((miiPhyIsolate (pPhyInfo, phyAddr) != OK)))
{
errnoSet (S_miiLib_PHY_NULL);
return (ERROR);
}
MII_LOG (MII_DBG_ANY, ("miiProbe... ends\n"),
0, 0, 0, 0, 0, 0);
return (OK);
}
/*******************************************************************************
*
* miiDiag - run some diagnostics
*
* This routine runs some diagnostics on the PHY whose address is
* specified in the parameter <phyAddr>.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiDiag
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* address of a PHY */
)
{
UINT16 data; /* data to be written to the control reg */
UINT8 regAddr; /* PHY register */
UINT16 ix = 0; /* a counter */
int retVal; /* convenient holder for return value */
/* reset the PHY */
regAddr = MII_CTRL_REG;
data = MII_CR_RESET;
MII_WRITE (phyAddr, regAddr, data, retVal);
if (retVal != OK)
return (ERROR);
while (ix++ < pPhyInfo->phyMaxDelay)
{
MII_SYS_DELAY (pPhyInfo->phyDelayParm);
MII_READ (phyAddr, regAddr, &data, retVal);
if (retVal == ERROR)
return (ERROR);
if (!(data & MII_CR_RESET))
break;
}
if (ix >= pPhyInfo->phyMaxDelay)
{
MII_LOG (MII_DBG_ANY, ("miiDiag reset fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
/* re-enable the chip */
data = MII_CR_NORM_EN;
MII_WRITE (phyAddr, regAddr, data, retVal);
if (retVal != OK)
{
MII_LOG (MII_DBG_ANY, ("miiDiag write fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
#if !defined(PHY_RTL8201BL)
/* check isolate bit is deasserted */
ix = 0;
while (ix++ < pPhyInfo->phyMaxDelay)
{
MII_SYS_DELAY (pPhyInfo->phyDelayParm);
MII_READ (phyAddr, regAddr, &data, retVal);
if (retVal != OK)
{
MII_LOG (MII_DBG_ANY, ("miiDiag read fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
if (!(data & MII_CR_ISOLATE))
break;
}
if (ix >= pPhyInfo->phyMaxDelay)
{
MII_LOG (MII_DBG_ANY, ("miiDiag de-isolate fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
#endif /* !defined(PHY_RTL8201BL) */
MII_LOG (MII_DBG_ANY, ("miiDiag... ends\n"),
0, 0, 0, 0, 0, 0);
return (OK);
}
/*******************************************************************************
*
* miiPhyIsolate - isolate the PHY device
*
* This routine isolates the PHY device whose address is specified in
* the parameter <isoPhyAddr>.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiPhyIsolate
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 isoPhyAddr /* address of a PHY to be isolated */
)
{
UINT8 regAddr; /* PHY register */
#if !defined(PHY_RTL8201BL)
UINT16 ix = 0; /* a counter */
#endif /* !defined(PHY_RTL8201BL) */
UINT16 data; /* data to be written to the control reg */
int retVal; /* convenient holder for return value */
if (isoPhyAddr == MII_PHY_NULL)
return (OK);
data = MII_CR_ISOLATE;
regAddr = MII_CTRL_REG;
MII_WRITE (isoPhyAddr, regAddr, data, retVal);
if (retVal != OK)
return (ERROR);
#if !defined(PHY_RTL8201BL)
/* check isolate bit is asserted */
while (ix++ < pPhyInfo->phyMaxDelay)
{
MII_SYS_DELAY (pPhyInfo->phyDelayParm);
MII_READ (isoPhyAddr, regAddr, &data, retVal);
if (retVal != OK)
return (ERROR);
if ((data & MII_CR_ISOLATE))
break;
}
if (ix >= pPhyInfo->phyMaxDelay)
{
MII_LOG (MII_DBG_ANY, ("miiPhyIsolate fail\n"),
0, 0, 0, 0, 0, 0);
return (ERROR);
}
#endif /* !defined(PHY_RTL8201BL) */
MII_LOG (MII_DBG_ANY, ("miiPhyIsolate... ends\n"),
0, 0, 0, 0, 0, 0);
return (OK);
}
/*******************************************************************************
*
* miiPhyPwrDown - put the PHY in power down mode
*
* This routine puts the PHY specified in <phyAddr> in power down mode.
*
* RETURNS: OK or ERROR.
*/
LOCAL STATUS miiPhyPwrDown
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* phy to be put in power down mode */
)
{
int retVal; /* convenient holder for return value */
UINT8 regAddr; /* PHY register */
UINT16 data; /* data to be written to the control reg */
if (phyAddr == MII_PHY_NULL)
return (OK);
data = MII_CR_POWER_DOWN;
regAddr = MII_CTRL_REG;
MII_WRITE (phyAddr, regAddr, data, retVal);
return (retVal);
}
/*******************************************************************************
*
* miiPhyBusScan - scan the MII bus
*
* This routine scans the MII bus, in the search for an MII-compliant PHY.
* If it succeeds, and if the flag MII_ALL_BUS_SCAN is not set, it returns
* OK. Otherwise, it keeps scanning the bus and storing relevant information
* in the miiPhyPresent field of the structure referenced to by <pPhyInfo>.
* Other PHYs than the first one found, will be put in
* low-power mode and electrically isolated from the MII interface.
*
* SEE ALSO: miiAutoNegotiate (), miiModeForce ().
*
* RETURNS: OK or ERROR.
*
*/
LOCAL STATUS miiPhyBusScan
(
PHY_INFO * pPhyInfo /* pointer to PHY_INFO structure */
)
{
UINT16 ix; /* a counter */
int retVal; /* holder for return value */
UINT8 phyAddr; /* address of a PHY */
if ((pPhyInfo->miiPhyPresent = (MII_PHY_BUS *)
calloc (1, sizeof (MII_PHY_BUS)))
== NULL)
return (ERROR);
/*
* there may be as many as 32 PHYs, with distinct logical addresses
* Start with the one the user suggested and, in case of failure in
* probing the device, scan the whole range.
*/
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
{
phyAddr = (ix + pPhyInfo->phyAddr) % MII_MAX_PHY_NUM;
MII_LOG (MII_DBG_ANY,
("miiPhyBusScan trying phyAddr=0x%x phyInfo=0x%x \n"),
phyAddr, pPhyInfo, 0, 0, 0, 0);
/* check the PHY is there */
retVal = miiProbe (pPhyInfo, phyAddr);
/* deal with the error condition if possible */
if (retVal == ERROR)
{
if (errno != S_miiLib_PHY_NULL)
return (ERROR);
else
{
if (ix == (MII_MAX_PHY_NUM - 1))
return (ERROR);
/* no PHY was found with this address: keep scanning */
MII_LOG (MII_DBG_ANY, "No PHY at address %#x\n", phyAddr,
0,0,0,0,0);
errno = 0;
continue;
}
}
else
{
/* run some diagnostics */
if (miiDiag (pPhyInfo, phyAddr) != OK)
{
MII_LOG (MII_DBG_ANY, "miiDiag failed for addr %#x\n",
phyAddr,0,0,0,0,0);
return (ERROR);
}
/* record this information */
* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) = TRUE;
/* should we scan the whole bus? */
if (!(MII_PHY_FLAGS_ARE_SET (MII_ALL_BUS_SCAN)))
{
MII_LOG (MII_DBG_ANY, "Not scanning whole bus\n", 0,0,0,0,0,0);
return (OK);
}
MII_LOG (MII_DBG_ANY, ("miiPhyBusScan phyAddr=0x%x \n"),
phyAddr, 0, 0, 0, 0, 0);
}
}
/* set optional features for the other PHYs */
for (ix = 0; ix < MII_MAX_PHY_NUM; ix++)
{
/* check the PHY is there */
if (* ((BOOL *) pPhyInfo->miiPhyPresent + phyAddr) == TRUE)
{
/* set it in power down mode */
if (MII_PHY_FLAGS_ARE_SET (MII_PHY_PWR_DOWN))
{
MII_LOG (MII_DBG_ANY, "Powering down PHY %#x\n", ix,
0,0,0,0,0);
if (miiPhyPwrDown (pPhyInfo, ix) == ERROR)
return (ERROR);
}
/* eletrically isolate it from the MII interface */
if (MII_PHY_FLAGS_ARE_SET (MII_PHY_ISO))
{
MII_LOG (MII_DBG_ANY, "miiPhyBusScan isolating phyAddr=0x%x\n",
ix, 0, 0, 0, 0, 0);
if (miiPhyIsolate (pPhyInfo, ix) == ERROR)
return (ERROR);
}
}
}
return (OK);
}
/*******************************************************************************
*
* miiPhyBestModeSet - set the best operating mode for a PHY
*
* This routine sets the best operating mode for a PHY looking at the
* parameters in <pPhyInfo>. It may call miiAutoNegotiate (), and/or
* miiModeForce (). Upon success, it stores the <phyAddr> in the relevant
* field of the structure pointed to by <pPhyInfo>.
*
* SEE ALSO: miiAutoNegotiate (), miiModeForce ().
*
* RETURNS: OK or ERROR.
*
*/
LOCAL STATUS miiPhyBestModeSet
(
PHY_INFO * pPhyInfo, /* pointer to PHY_INFO structure */
UINT8 phyAddr /* PHY's address */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -