mii.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
- /*
- mii.c: MII interface library
- Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
- Copyright 2001 Jeff Garzik
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/ethtool.h>
- #include <linux/mii.h>
- int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
- {
- struct net_device *dev = mii->dev;
- u32 advert, bmcr, lpa, nego;
- ecmd->supported =
- (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
- SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
- /* only supports twisted-pair */
- ecmd->port = PORT_MII;
- /* only supports internal transceiver */
- ecmd->transceiver = XCVR_INTERNAL;
- /* this isn't fully supported at higher layers */
- ecmd->phy_address = mii->phy_id;
- ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
- advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
- if (advert & ADVERTISE_10HALF)
- ecmd->advertising |= ADVERTISED_10baseT_Half;
- if (advert & ADVERTISE_10FULL)
- ecmd->advertising |= ADVERTISED_10baseT_Full;
- if (advert & ADVERTISE_100HALF)
- ecmd->advertising |= ADVERTISED_100baseT_Half;
- if (advert & ADVERTISE_100FULL)
- ecmd->advertising |= ADVERTISED_100baseT_Full;
- bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
- lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
- if (bmcr & BMCR_ANENABLE) {
- ecmd->advertising |= ADVERTISED_Autoneg;
- ecmd->autoneg = AUTONEG_ENABLE;
-
- nego = mii_nway_result(advert & lpa);
- if (nego == LPA_100FULL || nego == LPA_100HALF)
- ecmd->speed = SPEED_100;
- else
- ecmd->speed = SPEED_10;
- if (nego == LPA_100FULL || nego == LPA_10FULL) {
- ecmd->duplex = DUPLEX_FULL;
- mii->full_duplex = 1;
- } else {
- ecmd->duplex = DUPLEX_HALF;
- mii->full_duplex = 0;
- }
- } else {
- ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
- ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
- }
- /* ignore maxtxpkt, maxrxpkt for now */
- return 0;
- }
- int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
- {
- struct net_device *dev = mii->dev;
- if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
- return -EINVAL;
- if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
- return -EINVAL;
- if (ecmd->port != PORT_MII)
- return -EINVAL;
- if (ecmd->transceiver != XCVR_INTERNAL)
- return -EINVAL;
- if (ecmd->phy_address != mii->phy_id)
- return -EINVAL;
- if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
- return -EINVAL;
-
- /* ignore supported, maxtxpkt, maxrxpkt */
-
- if (ecmd->autoneg == AUTONEG_ENABLE) {
- u32 bmcr, advert, tmp;
- if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full)) == 0)
- return -EINVAL;
- /* advertise only what has been requested */
- advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
- tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
- if (ADVERTISED_10baseT_Half)
- tmp |= ADVERTISE_10HALF;
- if (ADVERTISED_10baseT_Full)
- tmp |= ADVERTISE_10FULL;
- if (ADVERTISED_100baseT_Half)
- tmp |= ADVERTISE_100HALF;
- if (ADVERTISED_100baseT_Full)
- tmp |= ADVERTISE_100FULL;
- if (advert != tmp) {
- mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
- mii->advertising = tmp;
- }
-
- /* turn on autonegotiation, and force a renegotiate */
- bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
- bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
- mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
- mii->duplex_lock = 0;
- } else {
- u32 bmcr, tmp;
- /* turn off auto negotiation, set speed and duplexity */
- bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
- tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
- if (ecmd->speed == SPEED_100)
- bmcr |= BMCR_SPEED100;
- if (ecmd->duplex == DUPLEX_FULL) {
- bmcr |= BMCR_FULLDPLX;
- mii->full_duplex = 1;
- } else
- mii->full_duplex = 0;
- if (bmcr != tmp)
- mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
- mii->duplex_lock = 1;
- }
- return 0;
- }
- int mii_link_ok (struct mii_if_info *mii)
- {
- if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
- return 1;
- return 0;
- }
- int mii_nway_restart (struct mii_if_info *mii)
- {
- int bmcr;
- int r = -EINVAL;
- /* if autoneg is off, it's an error */
- bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
- if (bmcr & BMCR_ANENABLE) {
- bmcr |= BMCR_ANRESTART;
- mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
- r = 0;
- }
- return r;
- }
- MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
- MODULE_DESCRIPTION ("MII hardware support library");
- MODULE_LICENSE("GPL");
- EXPORT_SYMBOL(mii_link_ok);
- EXPORT_SYMBOL(mii_nway_restart);
- EXPORT_SYMBOL(mii_ethtool_gset);
- EXPORT_SYMBOL(mii_ethtool_sset);