mii.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2. mii.c: MII interface library
  3. Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
  4. Copyright 2001 Jeff Garzik
  5.  */
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/netdevice.h>
  9. #include <linux/ethtool.h>
  10. #include <linux/mii.h>
  11. int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
  12. {
  13. struct net_device *dev = mii->dev;
  14. u32 advert, bmcr, lpa, nego;
  15. ecmd->supported =
  16.     (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
  17.      SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
  18.      SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
  19. /* only supports twisted-pair */
  20. ecmd->port = PORT_MII;
  21. /* only supports internal transceiver */
  22. ecmd->transceiver = XCVR_INTERNAL;
  23. /* this isn't fully supported at higher layers */
  24. ecmd->phy_address = mii->phy_id;
  25. ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
  26. advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
  27. if (advert & ADVERTISE_10HALF)
  28. ecmd->advertising |= ADVERTISED_10baseT_Half;
  29. if (advert & ADVERTISE_10FULL)
  30. ecmd->advertising |= ADVERTISED_10baseT_Full;
  31. if (advert & ADVERTISE_100HALF)
  32. ecmd->advertising |= ADVERTISED_100baseT_Half;
  33. if (advert & ADVERTISE_100FULL)
  34. ecmd->advertising |= ADVERTISED_100baseT_Full;
  35. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  36. lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
  37. if (bmcr & BMCR_ANENABLE) {
  38. ecmd->advertising |= ADVERTISED_Autoneg;
  39. ecmd->autoneg = AUTONEG_ENABLE;
  40. nego = mii_nway_result(advert & lpa);
  41. if (nego == LPA_100FULL || nego == LPA_100HALF)
  42. ecmd->speed = SPEED_100;
  43. else
  44. ecmd->speed = SPEED_10;
  45. if (nego == LPA_100FULL || nego == LPA_10FULL) {
  46. ecmd->duplex = DUPLEX_FULL;
  47. mii->full_duplex = 1;
  48. } else {
  49. ecmd->duplex = DUPLEX_HALF;
  50. mii->full_duplex = 0;
  51. }
  52. } else {
  53. ecmd->autoneg = AUTONEG_DISABLE;
  54. ecmd->speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
  55. ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
  56. }
  57. /* ignore maxtxpkt, maxrxpkt for now */
  58. return 0;
  59. }
  60. int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
  61. {
  62. struct net_device *dev = mii->dev;
  63. if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
  64. return -EINVAL;
  65. if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
  66. return -EINVAL;
  67. if (ecmd->port != PORT_MII)
  68. return -EINVAL;
  69. if (ecmd->transceiver != XCVR_INTERNAL)
  70. return -EINVAL;
  71. if (ecmd->phy_address != mii->phy_id)
  72. return -EINVAL;
  73. if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
  74. return -EINVAL;
  75.   
  76. /* ignore supported, maxtxpkt, maxrxpkt */
  77. if (ecmd->autoneg == AUTONEG_ENABLE) {
  78. u32 bmcr, advert, tmp;
  79. if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
  80.   ADVERTISED_10baseT_Full |
  81.   ADVERTISED_100baseT_Half |
  82.   ADVERTISED_100baseT_Full)) == 0)
  83. return -EINVAL;
  84. /* advertise only what has been requested */
  85. advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
  86. tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
  87. if (ADVERTISED_10baseT_Half)
  88. tmp |= ADVERTISE_10HALF;
  89. if (ADVERTISED_10baseT_Full)
  90. tmp |= ADVERTISE_10FULL;
  91. if (ADVERTISED_100baseT_Half)
  92. tmp |= ADVERTISE_100HALF;
  93. if (ADVERTISED_100baseT_Full)
  94. tmp |= ADVERTISE_100FULL;
  95. if (advert != tmp) {
  96. mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
  97. mii->advertising = tmp;
  98. }
  99. /* turn on autonegotiation, and force a renegotiate */
  100. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  101. bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
  102. mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
  103. mii->duplex_lock = 0;
  104. } else {
  105. u32 bmcr, tmp;
  106. /* turn off auto negotiation, set speed and duplexity */
  107. bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
  108. tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
  109. if (ecmd->speed == SPEED_100)
  110. bmcr |= BMCR_SPEED100;
  111. if (ecmd->duplex == DUPLEX_FULL) {
  112. bmcr |= BMCR_FULLDPLX;
  113. mii->full_duplex = 1;
  114. } else
  115. mii->full_duplex = 0;
  116. if (bmcr != tmp)
  117. mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
  118. mii->duplex_lock = 1;
  119. }
  120. return 0;
  121. }
  122. int mii_link_ok (struct mii_if_info *mii)
  123. {
  124. if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
  125. return 1;
  126. return 0;
  127. }
  128. int mii_nway_restart (struct mii_if_info *mii)
  129. {
  130. int bmcr;
  131. int r = -EINVAL;
  132. /* if autoneg is off, it's an error */
  133. bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
  134. if (bmcr & BMCR_ANENABLE) {
  135. bmcr |= BMCR_ANRESTART;
  136. mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
  137. r = 0;
  138. }
  139. return r;
  140. }
  141. MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
  142. MODULE_DESCRIPTION ("MII hardware support library");
  143. MODULE_LICENSE("GPL");
  144. EXPORT_SYMBOL(mii_link_ok);
  145. EXPORT_SYMBOL(mii_nway_restart);
  146. EXPORT_SYMBOL(mii_ethtool_gset);
  147. EXPORT_SYMBOL(mii_ethtool_sset);