patch-2.4.20 linux-2.4.20/drivers/net/3c509.c

Next file: linux-2.4.20/drivers/net/3c59x.c
Previous file: linux-2.4.20/drivers/net/3c505.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/drivers/net/3c509.c linux-2.4.20/drivers/net/3c509.c
@@ -49,11 +49,13 @@
 			- Power Management support
                 v1.18c 1Mar2002 David Ruggiero <jdr@farfalle.com>
                         - Full duplex support
-*/
+		v1.19  16Oct2002 Zwane Mwaikambo <zwane@linuxpower.ca>
+			- Additional ethtool features
+  */
 
 #define DRV_NAME	"3c509"
-#define DRV_VERSION	"1.18c"
-#define DRV_RELDATE	"1Mar2002"
+#define DRV_VERSION	"1.19"
+#define DRV_RELDATE	"16Oct2002"
 
 /* A few values that may be tweaked. */
 
@@ -140,9 +142,11 @@
 #define TX_STATUS 	0x0B
 #define TX_FREE		0x0C		/* Remaining free bytes in Tx buffer. */
 
+#define WN0_CONF_CTRL	0x04		/* Window 0: Configuration control register */
+#define WN0_ADDR_CONF	0x06		/* Window 0: Address configuration register */
 #define WN0_IRQ		0x08		/* Window 0: Set IRQ line in bits 12-15. */
 #define WN4_MEDIA	0x0A		/* Window 4: Various transcvr/media bits. */
-#define  MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
+#define	MEDIA_TP	0x00C0		/* Enable link beat and jabber for 10baseT. */
 #define WN4_NETDIAG	0x06		/* Window 4: Net diagnostic */
 #define FD_ENABLE	0x8000		/* Enable full-duplex ("external loopback") */  
 
@@ -230,12 +234,10 @@
 };
 
 MODULE_DEVICE_TABLE(isapnp, el3_isapnp_adapters);
-MODULE_LICENSE("GPL");
-
 
 static u16 el3_isapnp_phys_addr[8][3];
-#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 static int nopnp;
+#endif /* CONFIG_ISAPNP || CONFIG_ISAPNP_MODULE */
 
 int __init el3_probe(struct net_device *dev, int card_idx)
 {
@@ -696,7 +698,7 @@
 	outw(0x00, ioaddr + TX_FIFO);
 	/* ... and the packet rounded to a doubleword. */
 #ifdef  __powerpc__
-	outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+	outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #else
 	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
@@ -907,7 +909,7 @@
 
 				/* 'skb->data' points to the start of sk_buff data area. */
 #ifdef  __powerpc__
-				insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
+				insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
 							   (pkt_len + 3) >> 2);
 #else
 				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
@@ -985,6 +987,119 @@
 	return 0;
 }
 
+static int 
+el3_link_ok(struct net_device *dev)
+{
+	int ioaddr = dev->base_addr;
+	u16 tmp;
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_MEDIA);
+	EL3WINDOW(1);
+	return tmp & (1<<11);
+}
+
+static int
+el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+	
+	EL3WINDOW(0);
+	/* obtain current tranceiver via WN4_MEDIA? */	
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	ecmd->transceiver = XCVR_INTERNAL;
+	switch (tmp >> 14) {
+	case 0:
+		ecmd->port = PORT_TP;
+		break;
+	case 1:
+		ecmd->port = PORT_AUI;
+		ecmd->transceiver = XCVR_EXTERNAL;
+		break;
+	case 3:
+		ecmd->port = PORT_BNC;
+	default:
+		break;
+	}
+
+	ecmd->duplex = DUPLEX_HALF;
+	ecmd->supported = 0;
+	tmp = inw(ioaddr + WN0_CONF_CTRL);
+	if (tmp & (1<<13))
+		ecmd->supported |= SUPPORTED_AUI;
+	if (tmp & (1<<12))
+		ecmd->supported |= SUPPORTED_BNC;
+	if (tmp & (1<<9)) {
+		ecmd->supported |= SUPPORTED_TP | SUPPORTED_10baseT_Half |
+				SUPPORTED_10baseT_Full;	/* hmm... */
+		EL3WINDOW(4);
+		tmp = inw(ioaddr + WN4_NETDIAG);
+		if (tmp & FD_ENABLE)
+			ecmd->duplex = DUPLEX_FULL;
+	}
+
+	ecmd->speed = SPEED_10;
+	EL3WINDOW(1);
+	return 0;
+}
+
+static int
+el3_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	u16 tmp;
+	int ioaddr = dev->base_addr;
+
+	if (ecmd->speed != SPEED_10)
+		return -EINVAL;
+	if ((ecmd->duplex != DUPLEX_HALF) && (ecmd->duplex != DUPLEX_FULL))
+		return -EINVAL;
+	if ((ecmd->transceiver != XCVR_INTERNAL) && (ecmd->transceiver != XCVR_EXTERNAL))
+		return -EINVAL;
+
+	/* change XCVR type */
+	EL3WINDOW(0);
+	tmp = inw(ioaddr + WN0_ADDR_CONF);
+	switch (ecmd->port) {
+	case PORT_TP:
+		tmp &= ~(3<<14);
+		dev->if_port = 0;
+		break;
+	case PORT_AUI:
+		tmp |= (1<<14);
+		dev->if_port = 1;
+		break;
+	case PORT_BNC:
+		tmp |= (3<<14);
+		dev->if_port = 3;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	outw(tmp, ioaddr + WN0_ADDR_CONF);
+	if (dev->if_port == 3) {
+		/* fire up the DC-DC convertor if BNC gets enabled */
+		tmp = inw(ioaddr + WN0_ADDR_CONF);
+		if (tmp & (3 << 14)) {
+			outw(StartCoax, ioaddr + EL3_CMD);
+			udelay(800);
+		} else
+			return -EIO;
+	}
+
+	EL3WINDOW(4);
+	tmp = inw(ioaddr + WN4_NETDIAG);
+	if (ecmd->duplex == DUPLEX_FULL)
+		tmp |= FD_ENABLE;
+	else
+		tmp &= ~FD_ENABLE;
+	outw(tmp, ioaddr + WN4_NETDIAG);
+	EL3WINDOW(1);
+
+	return 0;
+}
+
 /**
  * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
  * @dev: network interface on which out-of-band action is to be performed
@@ -993,9 +1108,11 @@
  * Process the various commands of the SIOCETHTOOL interface.
  */
 
-static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+static int
+netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
 {
 	u32 ethcmd;
+	struct el3_private *lp = dev->priv;
 
 	/* dev_ioctl() in ../../net/core/dev.c has already checked
 	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
@@ -1014,6 +1131,41 @@
 		return 0;
 	}
 
+	/* get settings */
+	case ETHTOOL_GSET: {
+		int ret;
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_get_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+			return -EFAULT;
+		return ret;
+	}
+
+	/* set settings */
+	case ETHTOOL_SSET: {
+		int ret;
+		struct ethtool_cmd ecmd;
+		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+			return -EFAULT;
+		spin_lock_irq(&lp->lock);
+		ret = el3_netdev_set_ecmd(dev, &ecmd);
+		spin_unlock_irq(&lp->lock);
+		return ret;
+	}
+
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		spin_lock_irq(&lp->lock);
+		edata.data = el3_link_ok(dev);
+		spin_unlock_irq(&lp->lock);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
 	/* get message-level */
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
@@ -1047,7 +1199,8 @@
  * Process the various out-of-band ioctls passed to this driver.
  */
 
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+static int
+netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int rc = 0;
 
@@ -1064,7 +1217,8 @@
 	return rc;
 }
 
-static void el3_down(struct net_device *dev)
+static void
+el3_down(struct net_device *dev)
 {
 	int ioaddr = dev->base_addr;
 
@@ -1081,7 +1235,7 @@
 		/* Turn off thinnet power.  Green! */
 		outw(StopCoax, ioaddr + EL3_CMD);
 	else if (dev->if_port == 0) {
-		/* Disable link beat and jabber, if_port may change ere next open(). */
+		/* Disable link beat and jabber, if_port may change here next open(). */
 		EL3WINDOW(4);
 		outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA);
 	}
@@ -1091,7 +1245,8 @@
 	update_stats(dev);
 }
 
-static void el3_up(struct net_device *dev)
+static void
+el3_up(struct net_device *dev)
 {
 	int i, sw_info, net_diag;
 	int ioaddr = dev->base_addr;
@@ -1180,7 +1335,8 @@
 /* Power Management support functions */
 #ifdef CONFIG_PM
 
-static int el3_suspend(struct pm_dev *pdev)
+static int
+el3_suspend(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1206,7 +1362,8 @@
 	return 0;
 }
 
-static int el3_resume(struct pm_dev *pdev)
+static int
+el3_resume(struct pm_dev *pdev)
 {
 	unsigned long flags;
 	struct net_device *dev;
@@ -1232,7 +1389,8 @@
 	return 0;
 }
 
-static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
+static int
+el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
 {
 	switch (rqst) {
 		case PM_SUSPEND:
@@ -1265,6 +1423,7 @@
 MODULE_PARM_DESC(nopnp, "disable ISA PnP support (0-1)");
 #endif	/* CONFIG_ISAPNP */
 MODULE_DESCRIPTION("3Com Etherlink III (3c509, 3c509B) ISA/PnP ethernet driver");
+MODULE_LICENSE("GPL");
 
 int
 init_module(void)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)