⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phy_device.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	ctl = phy_read(phydev, MII_BMCR);	if (ctl < 0)		return ctl;	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);	/* Don't isolate the PHY if we're negotiating */	ctl &= ~(BMCR_ISOLATE);	ctl = phy_write(phydev, MII_BMCR, ctl);	return ctl;}/* genphy_config_aneg * * description: If auto-negotiation is enabled, we configure the *   advertising, and then restart auto-negotiation.  If it is not *   enabled, then we write the BMCR */int genphy_config_aneg(struct phy_device *phydev){	int err = 0;	if (AUTONEG_ENABLE == phydev->autoneg) {		err = genphy_config_advert(phydev);		if (err < 0)			return err;		err = genphy_restart_aneg(phydev);	} else		err = genphy_setup_forced(phydev);	return err;}EXPORT_SYMBOL(genphy_config_aneg);/* genphy_update_link * * description: Update the value in phydev->link to reflect the *   current link value.  In order to do this, we need to read *   the status register twice, keeping the second value */int genphy_update_link(struct phy_device *phydev){	int status;	/* Do a fake read */	status = phy_read(phydev, MII_BMSR);	if (status < 0)		return status;	/* Read link and autonegotiation status */	status = phy_read(phydev, MII_BMSR);	if (status < 0)		return status;	if ((status & BMSR_LSTATUS) == 0)		phydev->link = 0;	else		phydev->link = 1;	return 0;}/* genphy_read_status * * description: Check the link, then figure out the current state *   by comparing what we advertise with what the link partner *   advertises.  Start by checking the gigabit possibilities, *   then move on to 10/100. */int genphy_read_status(struct phy_device *phydev){	int adv;	int err;	int lpa;	int lpagb = 0;	/* Update the link, but return if there	 * was an error */	err = genphy_update_link(phydev);	if (err)		return err;	if (AUTONEG_ENABLE == phydev->autoneg) {		if (phydev->supported & (SUPPORTED_1000baseT_Half					| SUPPORTED_1000baseT_Full)) {			lpagb = phy_read(phydev, MII_STAT1000);			if (lpagb < 0)				return lpagb;			adv = phy_read(phydev, MII_CTRL1000);			if (adv < 0)				return adv;			lpagb &= adv << 2;		}		lpa = phy_read(phydev, MII_LPA);		if (lpa < 0)			return lpa;		adv = phy_read(phydev, MII_ADVERTISE);		if (adv < 0)			return adv;		lpa &= adv;		phydev->speed = SPEED_10;		phydev->duplex = DUPLEX_HALF;		phydev->pause = phydev->asym_pause = 0;		if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {			phydev->speed = SPEED_1000;			if (lpagb & LPA_1000FULL)				phydev->duplex = DUPLEX_FULL;		} else if (lpa & (LPA_100FULL | LPA_100HALF)) {			phydev->speed = SPEED_100;						if (lpa & LPA_100FULL)				phydev->duplex = DUPLEX_FULL;		} else			if (lpa & LPA_10FULL)				phydev->duplex = DUPLEX_FULL;		if (phydev->duplex == DUPLEX_FULL){			phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;			phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;		}	} else {		int bmcr = phy_read(phydev, MII_BMCR);		if (bmcr < 0)			return bmcr;		if (bmcr & BMCR_FULLDPLX)			phydev->duplex = DUPLEX_FULL;		else			phydev->duplex = DUPLEX_HALF;		if (bmcr & BMCR_SPEED1000)			phydev->speed = SPEED_1000;		else if (bmcr & BMCR_SPEED100)			phydev->speed = SPEED_100;		else			phydev->speed = SPEED_10;		phydev->pause = phydev->asym_pause = 0;	}	return 0;}EXPORT_SYMBOL(genphy_read_status);static int genphy_config_init(struct phy_device *phydev){	u32 val;	u32 features;	/* For now, I'll claim that the generic driver supports	 * all possible port types */	features = (SUPPORTED_TP | SUPPORTED_MII			| SUPPORTED_AUI | SUPPORTED_FIBRE |			SUPPORTED_BNC);	/* Do we support autonegotiation? */	val = phy_read(phydev, MII_BMSR);	if (val < 0)		return val;	if (val & BMSR_ANEGCAPABLE)		features |= SUPPORTED_Autoneg;	if (val & BMSR_100FULL)		features |= SUPPORTED_100baseT_Full;	if (val & BMSR_100HALF)		features |= SUPPORTED_100baseT_Half;	if (val & BMSR_10FULL)		features |= SUPPORTED_10baseT_Full;	if (val & BMSR_10HALF)		features |= SUPPORTED_10baseT_Half;	if (val & BMSR_ESTATEN) {		val = phy_read(phydev, MII_ESTATUS);		if (val < 0)			return val;		if (val & ESTATUS_1000_TFULL)			features |= SUPPORTED_1000baseT_Full;		if (val & ESTATUS_1000_THALF)			features |= SUPPORTED_1000baseT_Half;	}	phydev->supported = features;	phydev->advertising = features;	return 0;}/* phy_probe * * description: Take care of setting up the phy_device structure, *   set the state to READY (the driver's init function should *   set it to STARTING if needed). */static int phy_probe(struct device *dev){	struct phy_device *phydev;	struct phy_driver *phydrv;	struct device_driver *drv;	int err = 0;	phydev = to_phy_device(dev);	/* Make sure the driver is held.	 * XXX -- Is this correct? */	drv = get_driver(phydev->dev.driver);	phydrv = to_phy_driver(drv);	phydev->drv = phydrv;	/* Disable the interrupt if the PHY doesn't support it */	if (!(phydrv->flags & PHY_HAS_INTERRUPT))		phydev->irq = PHY_POLL;	spin_lock(&phydev->lock);	/* Start out supporting everything. Eventually,	 * a controller will attach, and may modify one	 * or both of these values */	phydev->supported = phydrv->features;	phydev->advertising = phydrv->features;	/* Set the state to READY by default */	phydev->state = PHY_READY;	if (phydev->drv->probe)		err = phydev->drv->probe(phydev);	spin_unlock(&phydev->lock);	if (err < 0)		return err;	if (phydev->drv->config_init)		err = phydev->drv->config_init(phydev);	return err;}static int phy_remove(struct device *dev){	struct phy_device *phydev;	phydev = to_phy_device(dev);	spin_lock(&phydev->lock);	phydev->state = PHY_DOWN;	spin_unlock(&phydev->lock);	if (phydev->drv->remove)		phydev->drv->remove(phydev);	put_driver(dev->driver);	phydev->drv = NULL;	return 0;}int phy_driver_register(struct phy_driver *new_driver){	int retval;	memset(&new_driver->driver, 0, sizeof(new_driver->driver));	new_driver->driver.name = new_driver->name;	new_driver->driver.bus = &mdio_bus_type;	new_driver->driver.probe = phy_probe;	new_driver->driver.remove = phy_remove;	retval = driver_register(&new_driver->driver);	if (retval) {		printk(KERN_ERR "%s: Error %d in registering driver\n",				new_driver->name, retval);		return retval;	}	pr_info("%s: Registered new driver\n", new_driver->name);	return 0;}EXPORT_SYMBOL(phy_driver_register);void phy_driver_unregister(struct phy_driver *drv){	driver_unregister(&drv->driver);}EXPORT_SYMBOL(phy_driver_unregister);static struct phy_driver genphy_driver = {	.phy_id		= 0xffffffff,	.phy_id_mask	= 0xffffffff,	.name		= "Generic PHY",	.config_init	= genphy_config_init,	.features	= 0,	.config_aneg	= genphy_config_aneg,	.read_status	= genphy_read_status,	.driver		= {.owner= THIS_MODULE, },};static int __init phy_init(void){	int rc;	rc = mdio_bus_init();	if (rc)		return rc;	rc = phy_driver_register(&genphy_driver);	if (rc)		mdio_bus_exit();	return rc;}static void __exit phy_exit(void){	phy_driver_unregister(&genphy_driver);	mdio_bus_exit();}subsys_initcall(phy_init);module_exit(phy_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -