# --------------------------------------------
# 02/09/29	jgarzik@mandrakesoft.com	1.701
# Add MII lib helper func generic_mii_ioctl, use it in 8139cp net drvr
# --------------------------------------------
#
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Sun Sep 29 19:35:45 2002
+++ b/drivers/net/8139cp.c	Sun Sep 29 19:35:45 2002
@@ -27,8 +27,6 @@
 	TODO, in rough priority order:
 	* Test Tx checksumming thoroughly
 	* dev->tx_timeout
-	* Support forcing media type with a module parameter,
-	  like dl2k.c/sundance.c
 	* Constants (module parms?) for Rx work limit
 	* Complete reset on PciErr
 	* Consider Rx interrupt mitigation using TimerIntr
@@ -49,8 +47,8 @@
  */
 
 #define DRV_NAME		"8139cp"
-#define DRV_VERSION		"0.2.1"
-#define DRV_RELDATE		"Aug 9, 2002"
+#define DRV_VERSION		"0.3.0"
+#define DRV_RELDATE		"Sep 29, 2002"
 
 
 #include <linux/config.h>
@@ -1657,35 +1655,18 @@
 static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct cp_private *cp = dev->priv;
-	struct mii_ioctl_data *mii;
-	int rc = 0;
+	struct mii_ioctl_data *mii = (struct mii_ioctl_data *) &rq->ifr_data;
+	int rc;
 
-	mii = (struct mii_ioctl_data *) &rq->ifr_data;
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd != SIOCETHTOOL) 
-		mii->reg_num &= 0x1f;
-	
-	switch (cmd) {
-	case SIOCETHTOOL:
+	if (cmd == SIOCETHTOOL)
 		return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
-		
- 	case SIOCGMIIPHY:	/* Get the address of the PHY in use. */
-	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
-		mii->phy_id = CP_INTERNAL_PHY;
-		/* Fall Through */
-
-	case SIOCGMIIREG:	/* Read the specified MII register. */
-	case SIOCDEVPRIVATE+1:	/* binary compat, remove in 2.5 */
-		mii->val_out = mdio_read (dev, CP_INTERNAL_PHY, mii->reg_num);
-		break;
-
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
 
+	rc = generic_mii_ioctl(dev, &cp->mii_if, mii, cmd);
+	if (rc == 1)	/* we don't care about duplex change, fixup rc */
+		rc = 0;
 	return rc;
 }
 
@@ -1823,6 +1804,8 @@
 	cp->mii_if.mdio_read = mdio_read;
 	cp->mii_if.mdio_write = mdio_write;
 	cp->mii_if.phy_id = CP_INTERNAL_PHY;
+	cp->mii_if.phy_id_mask = 0x1f;
+	cp->mii_if.reg_num_mask = 0x1f;
 	cp_set_rxbufsize(cp);
 
 	rc = pci_enable_device(pdev);
diff -Nru a/drivers/net/mii.c b/drivers/net/mii.c
--- a/drivers/net/mii.c	Sun Sep 29 19:35:45 2002
+++ b/drivers/net/mii.c	Sun Sep 29 19:35:45 2002
@@ -5,6 +5,26 @@
 	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
 	Copyright 2001,2002 Jeff Garzik
 
+	Various code came from myson803.c and other files by
+	Donald Becker.  Copyright:
+
+		Written 1998-2002 by Donald Becker.
+
+		This software may be used and distributed according
+		to the terms of the GNU General Public License (GPL),
+		incorporated herein by reference.  Drivers based on
+		or derived from this code fall under the GPL and must
+		retain the authorship, copyright and license notice.
+		This file is not a complete program and may only be
+		used when the entire operating system is licensed
+		under the GPL.
+
+		The author may be reached as becker@scyld.com, or C/O
+		Scyld Computing Corporation
+		410 Severn Ave., Suite 210
+		Annapolis MD 21403
+
+
  */
 
 #include <linux/kernel.h>
@@ -241,6 +261,76 @@
 	return 0; /* duplex did not change */
 }
 
+int generic_mii_ioctl(struct net_device *dev, struct mii_if_info *mii_if,
+		      struct mii_ioctl_data *mii_data, int cmd)
+{
+	int rc = 0;
+	unsigned int duplex_changed = 0;
+
+	mii_data->phy_id &= mii_if->phy_id_mask;
+	mii_data->reg_num &= mii_if->reg_num_mask;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:	/* binary compat, remove in 2.5 */
+	case SIOCGMIIPHY:
+		mii_data->phy_id = mii_if->phy_id;
+		/* fall through */
+
+	case SIOCDEVPRIVATE + 1:/* binary compat, remove in 2.5 */
+	case SIOCGMIIREG:
+		mii_data->val_out =
+			mii_if->mdio_read(dev, mii_data->phy_id,
+					  mii_data->reg_num);
+		break;
+
+	case SIOCDEVPRIVATE + 2:/* binary compat, remove in 2.5 */
+	case SIOCSMIIREG: {
+		u16 val = mii_data->val_in;
+
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		if (mii_data->phy_id == mii_if->phy_id) {
+			switch(mii_data->reg_num) {
+			case MII_BMCR: {
+				unsigned int new_duplex = 0;
+				if (val & (BMCR_RESET|BMCR_ANENABLE))
+					mii_if->force_media = 1;
+				else
+					mii_if->force_media = 0;
+				if (mii_if->force_media &&
+				    (val & BMCR_FULLDPLX))
+					new_duplex = 1;
+				if (mii_if->full_duplex != new_duplex) {
+					duplex_changed = 1;
+					mii_if->full_duplex = new_duplex;
+				}
+				break;
+			}
+			case MII_ADVERTISE:
+				mii_if->advertising = val;
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+
+		mii_if->mdio_write(dev, mii_data->phy_id,
+				   mii_data->reg_num, val);
+		break;
+	}
+
+	default:
+		rc = -EOPNOTSUPP;
+		break;
+	}
+
+	if ((rc == 0) && (duplex_changed))
+		rc = 1;
+	return rc;
+}
+
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@mandrakesoft.com>");
 MODULE_DESCRIPTION ("MII hardware support library");
 MODULE_LICENSE("GPL");
@@ -251,4 +341,5 @@
 EXPORT_SYMBOL(mii_ethtool_sset);
 EXPORT_SYMBOL(mii_check_link);
 EXPORT_SYMBOL(mii_check_media);
+EXPORT_SYMBOL(generic_mii_ioctl);
 
diff -Nru a/include/linux/mii.h b/include/linux/mii.h
--- a/include/linux/mii.h	Sun Sep 29 19:35:45 2002
+++ b/include/linux/mii.h	Sun Sep 29 19:35:45 2002
@@ -107,6 +107,8 @@
 struct mii_if_info {
 	int phy_id;
 	int advertising;
+	int phy_id_mask;
+	int reg_num_mask;
 
 	unsigned int full_duplex : 1;	/* is full duplex? */
 	unsigned int force_media : 1;	/* is autoneg. disabled? */
@@ -117,6 +119,7 @@
 };
 
 struct ethtool_cmd;
+struct mii_ioctl_data;
 
 extern int mii_link_ok (struct mii_if_info *mii);
 extern int mii_nway_restart (struct mii_if_info *mii);
@@ -126,6 +129,9 @@
 extern unsigned int mii_check_media (struct mii_if_info *mii,
 				     unsigned int ok_to_print,
 				     unsigned int init_media);
+extern int generic_mii_ioctl(struct net_device *dev, struct mii_if_info *mii_if,
+                      	     struct mii_ioctl_data *mii_data, int cmd);
+
 
 
 /* This structure is used in all SIOCxMIIxxx ioctl calls */
