Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/arch/cris/arch-v10/drivers/ethernet.c     |  140 ++--
 25-akpm/drivers/ieee1394/eth1394.c                |   95 +--
 25-akpm/drivers/media/dvb/dvb-core/dvb_net.c      |    9 
 25-akpm/drivers/net/3c509.c                       |  151 +----
 25-akpm/drivers/net/8139cp.c                      |   75 +-
 25-akpm/drivers/net/8139too.c                     |   14 
 25-akpm/drivers/net/Kconfig                       |    9 
 25-akpm/drivers/net/amd8111e.c                    |  248 +++-----
 25-akpm/drivers/net/defxx.c                       |  144 ++---
 25-akpm/drivers/net/defxx.h                       |    2 
 25-akpm/drivers/net/dl2k.c                        |  267 ++++-----
 25-akpm/drivers/net/eepro100.c                    |  132 ++--
 25-akpm/drivers/net/ewrk3.c                       |  326 +++++------
 25-akpm/drivers/net/forcedeth.c                   |  111 +--
 25-akpm/drivers/net/hamachi.c                     |  155 ++---
 25-akpm/drivers/net/ibmlana.c                     |    9 
 25-akpm/drivers/net/iseries_veth.c                |   83 +-
 25-akpm/drivers/net/ixgb/ixgb_ethtool.c           |  494 +++++------------
 25-akpm/drivers/net/ixgb/ixgb_main.c              |   24 
 25-akpm/drivers/net/mac8390.c                     |    4 
 25-akpm/drivers/net/meth.c                        |   26 
 25-akpm/drivers/net/natsemi.c                     |  273 ++++-----
 25-akpm/drivers/net/ns83820.c                     |   61 --
 25-akpm/drivers/net/pcmcia/smc91c92_cs.c          |  181 +++---
 25-akpm/drivers/net/r8169.c                       |  564 ++++++++++++++-----
 25-akpm/drivers/net/sk_mca.c                      |    9 
 25-akpm/drivers/net/starfire.c                    |  191 +++---
 25-akpm/drivers/net/sundance.c                    |  187 ++----
 25-akpm/drivers/net/tulip/de4x5.c                 |    2 
 25-akpm/drivers/net/tulip/tulip_core.c            |   32 -
 25-akpm/drivers/net/tulip/xircom_tulip_cb.c       |  194 +++---
 25-akpm/drivers/net/typhoon.c                     |  145 +----
 25-akpm/drivers/net/wan/lmc/lmc_main.c            |    9 
 25-akpm/drivers/net/wireless/airo.c               |   45 +
 25-akpm/drivers/net/wireless/netwave_cs.c         |   12 
 25-akpm/drivers/net/wireless/prism54/isl_38xx.c   |   15 
 25-akpm/drivers/net/wireless/prism54/isl_38xx.h   |    4 
 25-akpm/drivers/net/wireless/prism54/isl_ioctl.c  |  629 +++++++++++++++++++---
 25-akpm/drivers/net/wireless/prism54/isl_ioctl.h  |    2 
 25-akpm/drivers/net/wireless/prism54/isl_oid.h    |    9 
 25-akpm/drivers/net/wireless/prism54/islpci_dev.c |   35 -
 25-akpm/drivers/net/wireless/prism54/islpci_dev.h |    4 
 25-akpm/drivers/net/wireless/prism54/islpci_eth.c |    5 
 25-akpm/drivers/net/wireless/prism54/oid_mgt.c    |  121 +++-
 25-akpm/drivers/net/wireless/prism54/oid_mgt.h    |    3 
 25-akpm/drivers/net/wireless/wavelan.c            |   19 
 25-akpm/drivers/net/wireless/wavelan.p.h          |    3 
 25-akpm/drivers/net/wireless/wavelan_cs.c         |  181 ++----
 25-akpm/drivers/net/wireless/wavelan_cs.p.h       |    3 
 25-akpm/drivers/net/wireless/wl3501_cs.c          |   53 -
 25-akpm/drivers/net/yellowfin.c                   |   62 --
 25-akpm/drivers/usb/gadget/ether.c                |   73 --
 25-akpm/drivers/usb/net/catc.c                    |  122 +---
 25-akpm/drivers/usb/net/kaweth.c                  |   34 -
 25-akpm/drivers/usb/net/pegasus.c                 |  293 +++-------
 25-akpm/drivers/usb/net/rtl8150.c                 |  186 ++----
 25-akpm/include/linux/netdevice.h                 |    4 
 25-akpm/include/linux/wireless.h                  |   64 +-
 25-akpm/include/net/iw_handler.h                  |   60 +-
 25-akpm/net/core/dev.c                            |    2 
 25-akpm/net/core/wireless.c                       |  212 +++++--
 25-akpm/net/irda/irlan/irlan_client.c             |    2 
 62 files changed, 3329 insertions(+), 3294 deletions(-)

diff -puN arch/cris/arch-v10/drivers/ethernet.c~bk-netdev arch/cris/arch-v10/drivers/ethernet.c
--- 25/arch/cris/arch-v10/drivers/ethernet.c~bk-netdev	2004-09-06 18:43:15.597899144 -0700
+++ 25-akpm/arch/cris/arch-v10/drivers/ethernet.c	2004-09-06 18:43:15.754875280 -0700
@@ -401,7 +401,6 @@ static irqreturn_t e100nw_interrupt(int 
 static void e100_rx(struct net_device *dev);
 static int e100_close(struct net_device *dev);
 static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr);
 static int e100_set_config(struct net_device* dev, struct ifmap* map);
 static void e100_tx_timeout(struct net_device *dev);
 static struct net_device_stats *e100_get_stats(struct net_device *dev);
@@ -410,6 +409,7 @@ static void e100_hardware_send_packet(ch
 static void update_rx_stats(struct net_device_stats *);
 static void update_tx_stats(struct net_device_stats *);
 static int e100_probe_transceiver(void);
+static struct ethtool_ops ethtool_ops;
 
 static void e100_check_speed(unsigned long dummy);
 static void e100_set_speed(unsigned long speed);
@@ -483,6 +483,7 @@ etrax_ethernet_init(void)
 	dev->do_ioctl           = e100_ioctl;
 	dev->set_config		= e100_set_config;
 	dev->tx_timeout         = e100_tx_timeout;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
 	/* Initialise the list of Etrax DMA-descriptors */
 
@@ -1401,8 +1402,6 @@ e100_ioctl(struct net_device *dev, struc
 
 	spin_lock(&np->lock); /* Preempt protection */
 	switch (cmd) {
-		case SIOCETHTOOL:
-			return e100_ethtool_ioctl(dev,ifr);
 		case SIOCGMIIPHY: /* Get PHY address */
 			data->phy_id = mdio_phy_addr;
 			break;
@@ -1439,88 +1438,71 @@ e100_ioctl(struct net_device *dev, struc
 	return 0;
 }
 
-static int
-e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int e100_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct ethtool_cmd ecmd;
-
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
+	ecmd->supported = 
+	  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
+	  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
+	  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
+	ecmd->port = PORT_TP;
+	ecmd->transceiver = XCVR_EXTERNAL;
+	ecmd->phy_address = mdio_phy_addr;
+	ecmd->speed = current_speed;
+	ecmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	ecmd->advertising = ADVERTISED_TP;
+	if (current_duplex == autoneg && current_speed_selection == 0)
+		ecmd->advertising |= ADVERTISED_Autoneg;
+	else {
+		ecmd->advertising |= 
+		  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+		  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
+		if (current_speed_selection == 10)
+			ecmd->advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
+		else if (current_speed_selection == 100)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
+		if (current_duplex == half)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
+		else if (current_duplex == full)
+			ecmd->advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
+	}
+	ecmd->autoneg = AUTONEG_ENABLE;
+	return 0;
+}
 
-	switch (ecmd.cmd) {
-		case ETHTOOL_GSET:
-		{
-			memset((void *) &ecmd, 0, sizeof (ecmd));
-			ecmd.supported = 
-			  SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |
-			  SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 
-			  SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
-			ecmd.port = PORT_TP;
-			ecmd.transceiver = XCVR_EXTERNAL;
-			ecmd.phy_address = mdio_phy_addr;
-			ecmd.speed = current_speed;
-			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-			ecmd.advertising = ADVERTISED_TP;
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				ecmd.advertising |= ADVERTISED_Autoneg;
-			else {
-				ecmd.advertising |= 
-				  ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
-				  ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
-				if (current_speed_selection == 10)
-					ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
-				else if (current_speed_selection == 100)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
-				if (current_duplex == half)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
-				else if (current_duplex == full)
-					ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
-			}
-			ecmd.autoneg = AUTONEG_ENABLE;
-			if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_SSET:
-		{
-			if (!capable(CAP_NET_ADMIN)) {
-				return -EPERM;
-			}
-			if (ecmd.autoneg == AUTONEG_ENABLE) {
-				e100_set_duplex(autoneg);
-				e100_set_speed(0);
-			} else {
-				e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full);
-				e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100);
-			}
-		}
-		break;
-		case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info;
-			memset((void *) &info, 0, sizeof (info));
-			strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
-			strncpy(info.version, "$Revision: 1.22 $", sizeof(info.version) - 1);
-			strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
-			strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
-			info.regdump_len = 0;
-			info.eedump_len = 0;
-			info.testinfo_len = 0;
-			if (copy_to_user(ifr->ifr_data, &info, sizeof (info)))
-				return -EFAULT;
-		}
-		break;
-		case ETHTOOL_NWAY_RST:
-			if (current_duplex == autoneg && current_speed_selection == 0)
-				e100_negotiate();
-		break;
-		default:
-			return -EOPNOTSUPP;
-		break;
+static int e100_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		e100_set_duplex(autoneg);
+		e100_set_speed(0);
+	} else {
+		e100_set_duplex(ecmd->duplex == DUPLEX_HALF ? half : full);
+		e100_set_speed(ecmd->speed == SPEED_10 ? 10: 100);
 	}
 	return 0;
 }
 
+static void e100_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strncpy(info->driver, "ETRAX 100LX", sizeof(info->driver) - 1);
+	strncpy(info->version, "$Revision: 1.22 $", sizeof(info->version) - 1);
+	strncpy(info->fw_version, "N/A", sizeof(info->fw_version) - 1);
+	strncpy(info->bus_info, "N/A", sizeof(info->bus_info) - 1);
+}
+
+static int e100_nway_reset(struct net_device *dev)
+{
+	if (current_duplex == autoneg && current_speed_selection == 0)
+		e100_negotiate();
+	return 0;
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.get_settings = e100_get_settings,
+	.set_settings = e100_set_settings,
+	.get_drvinfo = e100_get_drvinfo,
+	.nway_reset = e100_nway_reset,
+};
+
 static int
 e100_set_config(struct net_device *dev, struct ifmap *map)
 {
diff -puN drivers/ieee1394/eth1394.c~bk-netdev drivers/ieee1394/eth1394.c
--- 25/drivers/ieee1394/eth1394.c~bk-netdev	2004-09-06 18:43:15.599898840 -0700
+++ 25-akpm/drivers/ieee1394/eth1394.c	2004-09-06 18:43:52.672262984 -0700
@@ -190,8 +190,7 @@ static inline void purge_partial_datagra
 static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
-static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ether1394_ethtool_ioctl(struct net_device *dev, void __user *useraddr);
+static struct ethtool_ops ethtool_ops;
 
 static int ether1394_write(struct hpsb_host *host, int srcid, int destid,
 			   quadlet_t *data, u64 addr, size_t len, u16 flags);
@@ -216,7 +215,7 @@ static struct hpsb_highlevel eth1394_hig
 /* This is called after an "ifup" */
 static int ether1394_open (struct net_device *dev)
 {
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 	int ret = 0;
 
 	/* Something bad happened, don't even try */
@@ -261,7 +260,7 @@ static int ether1394_stop (struct net_de
 /* Return statistics to the caller */
 static struct net_device_stats *ether1394_stats (struct net_device *dev)
 {
-	return &(((struct eth1394_priv *)dev->priv)->stats);
+	return &(((struct eth1394_priv *)netdev_priv(dev))->stats);
 }
 
 /* What to do if we timeout. I think a host reset is probably in order, so
@@ -269,16 +268,16 @@ static struct net_device_stats *ether139
 static void ether1394_tx_timeout (struct net_device *dev)
 {
 	ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n",
-		       ((struct eth1394_priv *)(dev->priv))->host->driver->name);
+		       ((struct eth1394_priv *)netdev_priv(dev))->host->driver->name);
 
-	highlevel_host_reset (((struct eth1394_priv *)(dev->priv))->host);
+	highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host);
 
 	netif_wake_queue (dev);
 }
 
 static int ether1394_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 
 	if ((new_mtu < 68) ||
 	    (new_mtu > min(ETH1394_DATA_LEN,
@@ -379,7 +378,7 @@ static int eth1394_probe(struct device *
 	ud->device.driver_data = node_info;
 	new_node->ud = ud;
 
-	priv = (struct eth1394_priv *)hi->dev->priv;
+	priv = netdev_priv(hi->dev);
 	list_add_tail(&new_node->list, &priv->ip_node_list);
 
 	return 0;
@@ -400,7 +399,7 @@ static int eth1394_remove(struct device 
 	if (!hi)
 		return -ENOENT;
 
-	priv = (struct eth1394_priv *)hi->dev->priv;
+	priv = netdev_priv(hi->dev);
 
 	old_node = eth1394_find_node(&priv->ip_node_list, ud);
 
@@ -435,7 +434,7 @@ static int eth1394_update(struct unit_di
 	if (!hi)
 		return -ENOENT;
 
-	priv = (struct eth1394_priv *)hi->dev->priv;
+	priv = netdev_priv(hi->dev);
 
 	node = eth1394_find_node(&priv->ip_node_list, ud);
 
@@ -459,7 +458,7 @@ static int eth1394_update(struct unit_di
 		ud->device.driver_data = node_info;
 		node->ud = ud;
 
-		priv = (struct eth1394_priv *)hi->dev->priv;
+		priv = netdev_priv(hi->dev);
 		list_add_tail(&node->list, &priv->ip_node_list);
 	}
 
@@ -496,7 +495,7 @@ static void ether1394_reset_priv (struct
 {
 	unsigned long flags;
 	int i;
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 	struct hpsb_host *host = priv->host;
 	u64 guid = *((u64*)&(host->csr.rom->bus_info_data[3]));
 	u16 maxpayload = 1 << (host->csr.max_rec + 1);
@@ -547,7 +546,7 @@ static void ether1394_init_dev (struct n
 	dev->header_cache_update= ether1394_header_cache_update;
 	dev->hard_header_parse	= ether1394_header_parse;
 	dev->set_mac_address	= ether1394_mac_addr;
-	dev->do_ioctl		= ether1394_do_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
 	/* Some constants */
 	dev->watchdog_timeo	= ETHER1394_TIMEOUT;
@@ -602,7 +601,7 @@ static void ether1394_add_host (struct h
 
 	SET_MODULE_OWNER(dev);
 
-	priv = (struct eth1394_priv *)dev->priv;
+	priv = netdev_priv(dev);
 
 	INIT_LIST_HEAD(&priv->ip_node_list);
 
@@ -672,7 +671,7 @@ static void ether1394_remove_host (struc
 
 	hi = hpsb_get_hostinfo(&eth1394_highlevel, host);
 	if (hi != NULL) {
-		struct eth1394_priv *priv = (struct eth1394_priv *)hi->dev->priv;
+		struct eth1394_priv *priv = netdev_priv(hi->dev);
 
 		hpsb_unregister_addrspace(&eth1394_highlevel, host,
 					  priv->local_fifo);
@@ -707,7 +706,7 @@ static void ether1394_host_reset (struct
 		return;
 
 	dev = hi->dev;
-	priv = (struct eth1394_priv *)dev->priv;
+	priv = netdev_priv(dev);
 
 	/* Reset our private host data, but not our mtu */
 	netif_stop_queue (dev);
@@ -882,7 +881,7 @@ static inline u16 ether1394_parse_encap(
 					nodeid_t srcid, nodeid_t destid,
 					u16 ether_type)
 {
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 	u64 dest_hw;
 	unsigned short ret = 0;
 
@@ -1112,7 +1111,7 @@ static int ether1394_data_handler(struct
 {
 	struct sk_buff *skb;
 	unsigned long flags;
-	struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 	union eth1394_hdr *hdr = (union eth1394_hdr *)buf;
 	u16 ether_type = 0;  /* initialized to clear warning */
 	int hdr_len;
@@ -1350,7 +1349,7 @@ static void ether1394_iso(struct hpsb_is
 				((be32_to_cpu(data[1]) & 0xff000000) >> 24));
 		source_id = be32_to_cpu(data[0]) >> 16;
 
-		priv = (struct eth1394_priv *)dev->priv;
+		priv = netdev_priv(dev);
 
 		if (info->channel != (iso->host->csr.broadcast_channel & 0x3f) ||
 		   specifier_id != ETHER1394_GASP_SPECIFIER_ID) {
@@ -1384,7 +1383,7 @@ static void ether1394_iso(struct hpsb_is
 static inline void ether1394_arp_to_1394arp(struct sk_buff *skb,
 					    struct net_device *dev)
 {
-	struct eth1394_priv *priv = (struct eth1394_priv *)(dev->priv);
+	struct eth1394_priv *priv = netdev_priv(dev);
 
 	struct arphdr *arp = (struct arphdr *)skb->data;
 	unsigned char *arp_ptr = (unsigned char *)(arp + 1);
@@ -1582,7 +1581,7 @@ static inline void ether1394_dg_complete
 {
 	struct sk_buff *skb = ptask->skb;
 	struct net_device *dev = skb->dev;
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
         unsigned long flags;
 
 	/* Statistics */
@@ -1635,7 +1634,7 @@ static int ether1394_tx (struct sk_buff 
 {
 	int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 	struct eth1394hdr *eth;
-	struct eth1394_priv *priv = dev->priv;
+	struct eth1394_priv *priv = netdev_priv(dev);
 	int proto;
 	unsigned long flags;
 	nodeid_t dest_node;
@@ -1768,53 +1767,17 @@ fail:
 	return 0;  /* returning non-zero causes serious problems */
 }
 
-static int ether1394_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	switch(cmd) {
-		case SIOCETHTOOL:
-			return ether1394_ethtool_ioctl(dev, ifr->ifr_data);
-
-		case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
-		case SIOCGMIIREG:		/* Read MII PHY register. */
-		case SIOCSMIIREG:		/* Write MII PHY register. */
-		default:
-			return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-static int ether1394_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
-{
-	u32 ethcmd;
-
-	if (get_user(ethcmd, (u32 __user *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-		case ETHTOOL_GDRVINFO: {
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy (info.driver, driver_name);
-			strcpy (info.version, "$Rev: 1231 $");
-			/* FIXME XXX provide sane businfo */
-			strcpy (info.bus_info, "ieee1394");
-			if (copy_to_user (useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			break;
-		}
-		case ETHTOOL_GSET:
-		case ETHTOOL_SSET:
-		case ETHTOOL_NWAY_RST:
-		case ETHTOOL_GLINK:
-		case ETHTOOL_GMSGLVL:
-		case ETHTOOL_SMSGLVL:
-		default:
-			return -EOPNOTSUPP;
-	}
-
-	return 0;
+	strcpy (info->driver, driver_name);
+	strcpy (info->version, "$Rev: 1224 $");
+	/* FIXME XXX provide sane businfo */
+	strcpy (info->bus_info, "ieee1394");
 }
 
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = ether1394_get_drvinfo
+};
 
 static int __init ether1394_init_module (void)
 {
diff -puN drivers/media/dvb/dvb-core/dvb_net.c~bk-netdev drivers/media/dvb/dvb-core/dvb_net.c
--- 25/drivers/media/dvb/dvb-core/dvb_net.c~bk-netdev	2004-09-06 18:43:15.601898536 -0700
+++ 25-akpm/drivers/media/dvb/dvb-core/dvb_net.c	2004-09-06 18:43:15.759874520 -0700
@@ -919,14 +919,6 @@ static void dvb_net_set_multicast_list (
 }
 
 
-static int dvb_net_set_config(struct net_device *dev, struct ifmap *map)
-{
-	if (netif_running(dev))
-		return -EBUSY;
-	return 0;
-}
-
-
 static void wq_restart_net_feed (void *data)
 {
 	struct net_device *dev = data;
@@ -985,7 +977,6 @@ static void dvb_net_setup(struct net_dev
 	dev->hard_start_xmit	= dvb_net_tx;
 	dev->get_stats		= dvb_net_get_stats;
 	dev->set_multicast_list = dvb_net_set_multicast_list;
-	dev->set_config         = dvb_net_set_config;
 	dev->set_mac_address    = dvb_net_set_mac;
 	dev->mtu		= 4096;
 	dev->mc_count           = 0;
diff -puN drivers/net/3c509.c~bk-netdev drivers/net/3c509.c
--- 25/drivers/net/3c509.c~bk-netdev	2004-09-06 18:43:15.603898232 -0700
+++ 25-akpm/drivers/net/3c509.c	2004-09-06 18:43:15.761874216 -0700
@@ -197,9 +197,9 @@ static int el3_rx(struct net_device *dev
 static int el3_close(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void el3_tx_timeout (struct net_device *dev);
-static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static void el3_down(struct net_device *dev);
 static void el3_up(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
 #ifdef CONFIG_PM
 static int el3_suspend(struct pm_dev *pdev);
 static int el3_resume(struct pm_dev *pdev);
@@ -321,7 +321,7 @@ static int __init el3_common_init(struct
 	dev->set_multicast_list = &set_multicast_list;
 	dev->tx_timeout = el3_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->do_ioctl = netdev_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
 	err = register_netdev(dev);
 	if (err) {
@@ -1285,123 +1285,64 @@ el3_netdev_set_ecmd(struct net_device *d
 	return 0;
 }
 
-/**
- * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @useraddr: userspace address to which data is to be read and returned
- *
- * Process the various commands of the SIOCETHTOOL interface.
- */
+static void el3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+}
 
-static int
-netdev_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
+static int el3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	u32 ethcmd;
 	struct el3_private *lp = netdev_priv(dev);
+	int ret;
 
-	/* dev_ioctl() in ../../net/core/dev.c has already checked
-	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
-
-	if (get_user(ethcmd, (u32 __user *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, DRV_NAME);
-		strcpy (info.version, DRV_VERSION);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		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};
-		edata.data = el3_debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		el3_debug = edata.data;
-		return 0;
-	}
+	spin_lock_irq(&lp->lock);
+	ret = el3_netdev_get_ecmd(dev, ecmd);
+	spin_unlock_irq(&lp->lock);
+	return ret;
+}
 
-	default:
-		break;
-	}
+static int el3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct el3_private *lp = netdev_priv(dev);
+	int ret;
 
-	return -EOPNOTSUPP;
+	spin_lock_irq(&lp->lock);
+	ret = el3_netdev_set_ecmd(dev, ecmd);
+	spin_unlock_irq(&lp->lock);
+	return ret;
 }
 
-/**
- * netdev_ioctl: Handle network interface ioctls
- * @dev: network interface on which out-of-band action is to be performed
- * @rq: user request data
- * @cmd: command issued by user
- *
- * 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 u32 el3_get_link(struct net_device *dev)
 {
-	int rc = 0;
+	struct el3_private *lp = netdev_priv(dev);
+	u32 ret;
 
-	switch (cmd) {
-	case SIOCETHTOOL:
-		rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
-		break;
+	spin_lock_irq(&lp->lock);
+	ret = el3_link_ok(dev);
+	spin_unlock_irq(&lp->lock);
+	return ret;
+}
 
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
+static u32 el3_get_msglevel(struct net_device *dev)
+{
+	return el3_debug;
+}
 
-	return rc;
+static void el3_set_msglevel(struct net_device *dev, u32 v)
+{
+	el3_debug = v;
 }
 
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = el3_get_drvinfo,
+	.get_settings = el3_get_settings,
+	.set_settings = el3_set_settings,
+	.get_link = el3_get_link,
+	.get_msglevel = el3_get_msglevel,
+	.set_msglevel = el3_set_msglevel,
+};
+
 static void
 el3_down(struct net_device *dev)
 {
diff -puN drivers/net/8139cp.c~bk-netdev drivers/net/8139cp.c
--- 25/drivers/net/8139cp.c~bk-netdev	2004-09-06 18:43:15.604898080 -0700
+++ 25-akpm/drivers/net/8139cp.c	2004-09-06 18:43:15.763873912 -0700
@@ -185,6 +185,9 @@ enum {
 	RingEnd		= (1 << 30), /* End of descriptor ring */
 	FirstFrag	= (1 << 29), /* First segment of a packet */
 	LastFrag	= (1 << 28), /* Final segment of a packet */
+	LargeSend	= (1 << 27), /* TCP Large Send Offload (TSO) */
+	MSSShift	= 16,	     /* MSS value position */
+	MSSMask		= 0xfff,     /* MSS value: 11 bits */
 	TxError		= (1 << 23), /* Tx error summary */
 	RxError		= (1 << 20), /* Rx error summary */
 	IPCS		= (1 << 18), /* Calculate IP checksum */
@@ -311,7 +314,7 @@ struct cp_desc {
 struct ring_info {
 	struct sk_buff		*skb;
 	dma_addr_t		mapping;
-	unsigned		frag;
+	u32			len;
 };
 
 struct cp_dma_stats {
@@ -705,7 +708,7 @@ static void cp_tx (struct cp_private *cp
 			BUG();
 
 		pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
-					skb->len, PCI_DMA_TODEVICE);
+				 cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE);
 
 		if (status & LastFrag) {
 			if (status & (TxError | TxFIFOUnder)) {
@@ -747,10 +750,11 @@ static int cp_start_xmit (struct sk_buff
 {
 	struct cp_private *cp = netdev_priv(dev);
 	unsigned entry;
-	u32 eor;
+	u32 eor, flags;
 #if CP_VLAN_TAG_USED
 	u32 vlan_tag = 0;
 #endif
+	int mss = 0;
 
 	spin_lock_irq(&cp->lock);
 
@@ -770,6 +774,9 @@ static int cp_start_xmit (struct sk_buff
 
 	entry = cp->tx_head;
 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+	if (dev->features & NETIF_F_TSO)
+		mss = skb_shinfo(skb)->tso_size;
+
 	if (skb_shinfo(skb)->nr_frags == 0) {
 		struct cp_desc *txd = &cp->tx_ring[entry];
 		u32 len;
@@ -781,26 +788,26 @@ static int cp_start_xmit (struct sk_buff
 		txd->addr = cpu_to_le64(mapping);
 		wmb();
 
-		if (skb->ip_summed == CHECKSUM_HW) {
+		flags = eor | len | DescOwn | FirstFrag | LastFrag;
+
+		if (mss)
+			flags |= LargeSend | ((mss & MSSMask) << MSSShift);
+		else if (skb->ip_summed == CHECKSUM_HW) {
 			const struct iphdr *ip = skb->nh.iph;
 			if (ip->protocol == IPPROTO_TCP)
-				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-							 FirstFrag | LastFrag |
-							 IPCS | TCPCS);
+				flags |= IPCS | TCPCS;
 			else if (ip->protocol == IPPROTO_UDP)
-				txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-							 FirstFrag | LastFrag |
-							 IPCS | UDPCS);
+				flags |= IPCS | UDPCS;
 			else
-				BUG();
-		} else
-			txd->opts1 = cpu_to_le32(eor | len | DescOwn |
-						 FirstFrag | LastFrag);
+				WARN_ON(1);	/* we need a WARN() */
+		}
+
+		txd->opts1 = cpu_to_le32(flags);
 		wmb();
 
 		cp->tx_skb[entry].skb = skb;
 		cp->tx_skb[entry].mapping = mapping;
-		cp->tx_skb[entry].frag = 0;
+		cp->tx_skb[entry].len = len;
 		entry = NEXT_TX(entry);
 	} else {
 		struct cp_desc *txd;
@@ -818,7 +825,7 @@ static int cp_start_xmit (struct sk_buff
 					       first_len, PCI_DMA_TODEVICE);
 		cp->tx_skb[entry].skb = skb;
 		cp->tx_skb[entry].mapping = first_mapping;
-		cp->tx_skb[entry].frag = 1;
+		cp->tx_skb[entry].len = first_len;
 		entry = NEXT_TX(entry);
 
 		for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -834,16 +841,19 @@ static int cp_start_xmit (struct sk_buff
 						 len, PCI_DMA_TODEVICE);
 			eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 
-			if (skb->ip_summed == CHECKSUM_HW) {
-				ctrl = eor | len | DescOwn | IPCS;
+			ctrl = eor | len | DescOwn;
+
+			if (mss)
+				ctrl |= LargeSend |
+					((mss & MSSMask) << MSSShift);
+			else if (skb->ip_summed == CHECKSUM_HW) {
 				if (ip->protocol == IPPROTO_TCP)
-					ctrl |= TCPCS;
+					ctrl |= IPCS | TCPCS;
 				else if (ip->protocol == IPPROTO_UDP)
-					ctrl |= UDPCS;
+					ctrl |= IPCS | UDPCS;
 				else
 					BUG();
-			} else
-				ctrl = eor | len | DescOwn;
+			}
 
 			if (frag == skb_shinfo(skb)->nr_frags - 1)
 				ctrl |= LastFrag;
@@ -858,7 +868,7 @@ static int cp_start_xmit (struct sk_buff
 
 			cp->tx_skb[entry].skb = skb;
 			cp->tx_skb[entry].mapping = mapping;
-			cp->tx_skb[entry].frag = frag + 2;
+			cp->tx_skb[entry].len = len;
 			entry = NEXT_TX(entry);
 		}
 
@@ -1072,7 +1082,6 @@ static int cp_refill_rx (struct cp_priva
 		cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
 			skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		cp->rx_skb[i].skb = skb;
-		cp->rx_skb[i].frag = 0;
 
 		cp->rx_ring[i].opts2 = 0;
 		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
@@ -1124,9 +1133,6 @@ static void cp_clean_rings (struct cp_pr
 {
 	unsigned i;
 
-	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
-	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
-
 	for (i = 0; i < CP_RX_RING_SIZE; i++) {
 		if (cp->rx_skb[i].skb) {
 			pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
@@ -1138,13 +1144,18 @@ static void cp_clean_rings (struct cp_pr
 	for (i = 0; i < CP_TX_RING_SIZE; i++) {
 		if (cp->tx_skb[i].skb) {
 			struct sk_buff *skb = cp->tx_skb[i].skb;
+
 			pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
-					 skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb(skb);
+				 	 cp->tx_skb[i].len, PCI_DMA_TODEVICE);
+			if (le32_to_cpu(cp->tx_ring[i].opts1) & LastFrag)
+				dev_kfree_skb(skb);
 			cp->net_stats.tx_dropped++;
 		}
 	}
 
+	memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+	memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+
 	memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
 	memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
 }
@@ -1536,6 +1547,8 @@ static struct ethtool_ops cp_ethtool_ops
 	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
 	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
 	.set_wol		= cp_set_wol,
@@ -1766,6 +1779,10 @@ static int cp_init_one (struct pci_dev *
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
 
+#if 0 /* disabled by default until verified */
+	dev->features |= NETIF_F_TSO;
+#endif
+
 	dev->irq = pdev->irq;
 
 	rc = register_netdev(dev);
diff -puN drivers/net/8139too.c~bk-netdev drivers/net/8139too.c
--- 25/drivers/net/8139too.c~bk-netdev	2004-09-06 18:43:15.606897776 -0700
+++ 25-akpm/drivers/net/8139too.c	2004-09-06 18:43:15.766873456 -0700
@@ -390,8 +390,14 @@ enum rx_mode_bits {
 
 /* Bits in TxConfig. */
 enum tx_config_bits {
-	TxIFG1 = (1 << 25),	/* Interframe Gap Time */
-	TxIFG0 = (1 << 24),	/* Enabling these bits violates IEEE 802.3 */
+
+        /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
+        TxIFGShift = 24,
+        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
+        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
+        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
+        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+
 	TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
 	TxCRC = (1 << 16),	/* DISABLE appending CRC to end of Tx packets */
 	TxClearAbt = (1 << 0),	/* Clear abort (WO) */
@@ -724,7 +730,7 @@ static const unsigned int rtl8139_rx_con
 #endif
 
 static const unsigned int rtl8139_tx_config =
-	(TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
+	TxIFG96 | (TX_DMA_BURST << TxDMAShift) | (TX_RETRY << TxRetryShift);
 
 static void __rtl8139_cleanup_dev (struct net_device *dev)
 {
@@ -1400,8 +1406,6 @@ static void rtl8139_hw_start (struct net
 
 	tp->rx_config = rtl8139_rx_config | AcceptBroadcast | AcceptMyPhys;
 	RTL_W32 (RxConfig, tp->rx_config);
-
-	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, rtl8139_tx_config);
 
 	tp->cur_rx = 0;
diff -puN drivers/net/amd8111e.c~bk-netdev drivers/net/amd8111e.c
--- 25/drivers/net/amd8111e.c~bk-netdev	2004-09-06 18:43:15.608897472 -0700
+++ 25-akpm/drivers/net/amd8111e.c	2004-09-06 18:43:15.771872696 -0700
@@ -1464,32 +1464,25 @@ static int amd8111e_start_xmit(struct sk
 /*
 This function returns all the memory mapped registers of the device.
 */
-static char* amd8111e_read_regs(struct amd8111e_priv* lp)
+static void amd8111e_read_regs(struct amd8111e_priv *lp, u32 *buf)
 {    	
-	void * mmio = lp->mmio;
-        u32 * reg_buff;
-
-     	reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL);
-	if(NULL == reg_buff)
-		return NULL;
-
+	void *mmio = lp->mmio;
 	/* Read only necessary registers */
-	reg_buff[0] = readl(mmio + XMT_RING_BASE_ADDR0);
-	reg_buff[1] = readl(mmio + XMT_RING_LEN0);
-	reg_buff[2] = readl(mmio + RCV_RING_BASE_ADDR0);
-	reg_buff[3] = readl(mmio + RCV_RING_LEN0);
-	reg_buff[4] = readl(mmio + CMD0);
-	reg_buff[5] = readl(mmio + CMD2);
-	reg_buff[6] = readl(mmio + CMD3);
-	reg_buff[7] = readl(mmio + CMD7);
-	reg_buff[8] = readl(mmio + INT0);
-	reg_buff[9] = readl(mmio + INTEN0);
-	reg_buff[10] = readl(mmio + LADRF);
-	reg_buff[11] = readl(mmio + LADRF+4);
-	reg_buff[12] = readl(mmio + STAT0);
-
-	return (char *)reg_buff;
+	buf[0] = readl(mmio + XMT_RING_BASE_ADDR0);
+	buf[1] = readl(mmio + XMT_RING_LEN0);
+	buf[2] = readl(mmio + RCV_RING_BASE_ADDR0);
+	buf[3] = readl(mmio + RCV_RING_LEN0);
+	buf[4] = readl(mmio + CMD0);
+	buf[5] = readl(mmio + CMD2);
+	buf[6] = readl(mmio + CMD3);
+	buf[7] = readl(mmio + CMD7);
+	buf[8] = readl(mmio + INT0);
+	buf[9] = readl(mmio + INTEN0);
+	buf[10] = readl(mmio + LADRF);
+	buf[11] = readl(mmio + LADRF+4);
+	buf[12] = readl(mmio + STAT0);
 }
+
 /*
 amd8111e crc generator implementation is different from the kernel
 ether_crc() function.
@@ -1567,131 +1560,101 @@ static void amd8111e_set_multicast_list(
 
 }
 
-/*
-This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
-*/
-	
-static int amd8111e_ethtool_ioctl(struct net_device* dev, void __user *useraddr)
+static void amd8111e_get_drvinfo(struct net_device* dev, struct ethtool_drvinfo *info)
 {
 	struct amd8111e_priv *lp = netdev_priv(dev);
 	struct pci_dev *pci_dev = lp->pci_dev;
-	u32 ethcmd;
-	
-	if( useraddr == NULL) 
-		return -EINVAL;
-	if(copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-	
-	switch(ethcmd){
-	
-	case ETHTOOL_GDRVINFO:{
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy (info.driver, MODULE_NAME);
-		strcpy (info.version, MODULE_VERS);
-		memset(&info.fw_version, 0, sizeof(info.fw_version));
-		sprintf(info.fw_version,"%u",chip_version);
-		strcpy (info.bus_info, pci_name(pci_dev));
-		info.eedump_len = 0;
-		info.regdump_len = AMD8111E_REG_DUMP_LEN;
-		if (copy_to_user (useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&lp->lock);
-		mii_ethtool_gset(&lp->mii_if, &ecmd);
-		spin_unlock_irq(&lp->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
+	strcpy (info->driver, MODULE_NAME);
+	strcpy (info->version, MODULE_VERS);
+	sprintf(info->fw_version,"%u",chip_version);
+	strcpy (info->bus_info, pci_name(pci_dev));
+}
 
-		spin_lock_irq(&lp->lock);
-		r = mii_ethtool_sset(&lp->mii_if, &ecmd);
-		spin_unlock_irq(&lp->lock);
-		return r;
-	}
-	case ETHTOOL_GREGS: {
-		struct ethtool_regs regs;
-		u8 *regbuf;
-		int ret;
-
-		if (copy_from_user(&regs, useraddr, sizeof(regs)))
-			return -EFAULT;
-		if (regs.len > AMD8111E_REG_DUMP_LEN)
-			regs.len = AMD8111E_REG_DUMP_LEN;
-		regs.version = 0;
-		if (copy_to_user(useraddr, &regs, sizeof(regs)))
-			return -EFAULT;
-
-		regbuf = amd8111e_read_regs(lp);
-		if (!regbuf)
-			return -ENOMEM;
-
-		useraddr += offsetof(struct ethtool_regs, data);
-		ret = 0;
-		if (copy_to_user(useraddr, regbuf, regs.len))
-			ret = -EFAULT;
-		kfree(regbuf);
-		return ret;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&lp->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value val = {ETHTOOL_GLINK};
-		val.data = mii_link_ok(&lp->mii_if);
-		if (copy_to_user(useraddr, &val, sizeof(val)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GWOL: {
-		struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL };
+static int amd8111e_get_regs_len(struct net_device *dev)
+{
+	return AMD8111E_REG_DUMP_LEN;
+}
 
-		wol_info.supported = WAKE_MAGIC|WAKE_PHY;
-		wol_info.wolopts = 0;
-		if (lp->options & OPTION_WOL_ENABLE)
-			wol_info.wolopts = WAKE_MAGIC;
-		memset(&wol_info.sopass, 0, sizeof(wol_info.sopass));
-		if (copy_to_user(useraddr, &wol_info, sizeof(wol_info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SWOL: {
-		struct ethtool_wolinfo wol_info;
+static void amd8111e_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	regs->version = 0;
+	amd8111e_read_regs(lp, buf);
+}
 
-		if (copy_from_user(&wol_info, useraddr, sizeof(wol_info)))
-			return -EFAULT;
-		if (wol_info.wolopts & ~(WAKE_MAGIC |WAKE_PHY))
-			return -EINVAL;
-		spin_lock_irq(&lp->lock);
-		if(wol_info.wolopts & WAKE_MAGIC)
-			lp->options |= 
-				(OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
-		else if(wol_info.wolopts & WAKE_PHY)
-			lp->options |= 
-				(OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
-		else
-			lp->options &= ~OPTION_WOL_ENABLE; 
-		spin_unlock_irq(&lp->lock);
-		return 0;
-	}
-	
-	default:
-		break;
-	}
-		return -EOPNOTSUPP;
+static int amd8111e_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	spin_lock_irq(&lp->lock);
+	mii_ethtool_gset(&lp->mii_if, ecmd);
+	spin_unlock_irq(&lp->lock);
+	return 0;
+}
+
+static int amd8111e_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&lp->lock);
+	res = mii_ethtool_sset(&lp->mii_if, ecmd);
+	spin_unlock_irq(&lp->lock);
+	return res;
+}
+
+static int amd8111e_nway_reset(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	return mii_nway_restart(&lp->mii_if);
+}
+
+static u32 amd8111e_get_link(struct net_device *dev)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	return mii_link_ok(&lp->mii_if);
 }
+
+static void amd8111e_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	wol_info->supported = WAKE_MAGIC|WAKE_PHY;
+	if (lp->options & OPTION_WOL_ENABLE)
+		wol_info->wolopts = WAKE_MAGIC;
+}
+
+static int amd8111e_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol_info)
+{
+	struct amd8111e_priv *lp = netdev_priv(dev);
+	if (wol_info->wolopts & ~(WAKE_MAGIC|WAKE_PHY))
+		return -EINVAL;
+	spin_lock_irq(&lp->lock);
+	if (wol_info->wolopts & WAKE_MAGIC)
+		lp->options |= 
+			(OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
+	else if(wol_info->wolopts & WAKE_PHY)
+		lp->options |= 
+			(OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
+	else
+		lp->options &= ~OPTION_WOL_ENABLE; 
+	spin_unlock_irq(&lp->lock);
+	return 0;
+}
+
+static struct ethtool_ops ops = {
+	.get_drvinfo = amd8111e_get_drvinfo,
+	.get_regs_len = amd8111e_get_regs_len,
+	.get_regs = amd8111e_get_regs,
+	.get_settings = amd8111e_get_settings,
+	.set_settings = amd8111e_set_settings,
+	.nway_reset = amd8111e_nway_reset,
+	.get_link = amd8111e_get_link,
+	.get_wol = amd8111e_get_wol,
+	.set_wol = amd8111e_set_wol,
+};
+
+/*
+This function handles all the  ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. 
+*/
+	
 static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
 {
 	struct mii_ioctl_data *data = if_mii(ifr);
@@ -1703,8 +1666,6 @@ static int amd8111e_ioctl(struct net_dev
 		return -EPERM;
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return amd8111e_ethtool_ioctl(dev, ifr->ifr_data);
 	case SIOCGMIIPHY:
 		data->phy_id = PHY_ID;
 
@@ -2085,6 +2046,7 @@ static int __devinit amd8111e_probe_one(
 	dev->set_mac_address = amd8111e_set_mac_address;
 	dev->do_ioctl = amd8111e_ioctl;
 	dev->change_mtu = amd8111e_change_mtu;
+	SET_ETHTOOL_OPS(dev, &ops);
 	dev->irq =pdev->irq;
 	dev->tx_timeout = amd8111e_tx_timeout; 
 	dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; 
diff -puN drivers/net/defxx.c~bk-netdev drivers/net/defxx.c
--- 25/drivers/net/defxx.c~bk-netdev	2004-09-06 18:43:15.609897320 -0700
+++ 25-akpm/drivers/net/defxx.c	2004-09-06 18:43:15.775872088 -0700
@@ -19,7 +19,7 @@
  *   LVS	Lawrence V. Stefani <lstefani@yahoo.com>
  *
  * Maintainers:
- *   macro	Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ *   macro	Maciej W. Rozycki <macro@linux-mips.org>
  *
  * Credits:
  *   I'd like to thank Patricia Cross for helping me get started with
@@ -190,6 +190,7 @@
  *		Feb 2001			Skb allocation fixes
  *		Feb 2001	davej		PCI enable cleanups.
  *		04 Aug 2003	macro		Converted to the DMA API.
+ *		14 Aug 2004	macro		Fix device names reported.
  */
 
 /* Include files */
@@ -214,12 +215,14 @@
 
 #include "defxx.h"
 
-/* Version information string - should be updated prior to each new release!!! */
+/* Version information string should be updated prior to each new release!  */
+#define DRV_NAME "defxx"
+#define DRV_VERSION "v1.07"
+#define DRV_RELDATE "2004/08/14"
 
 static char version[] __devinitdata =
-	"defxx.c:v1.06 2003/08/04  Lawrence V. Stefani and others\n";
-
-#define DRV_NAME "defxx"
+	DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
+	"  Lawrence V. Stefani and others\n";
 
 #define DYNAMIC_BUFFERS 1
 
@@ -235,7 +238,7 @@ static char version[] __devinitdata =
 static void		dfx_bus_init(struct net_device *dev);
 static void		dfx_bus_config_check(DFX_board_t *bp);
 
-static int		dfx_driver_init(struct net_device *dev);
+static int		dfx_driver_init(struct net_device *dev, const char *print_name);
 static int		dfx_adap_init(DFX_board_t *bp, int get_buffers);
 
 static int		dfx_open(struct net_device *dev);
@@ -404,24 +407,25 @@ static inline void dfx_port_read_long(
  */
 static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
 {
+	static int version_disp;
+	char *print_name = DRV_NAME;
 	struct net_device *dev;
 	DFX_board_t	  *bp;			/* board pointer */
 	int alloc_size;				/* total buffer size used */
 	int err;
 
-#ifndef MODULE
-	static int version_disp;
-
-	if (!version_disp)	/* display version info if adapter is found */
-	{
+	if (!version_disp) {	/* display version info if adapter is found */
 		version_disp = 1;	/* set display flag to TRUE so that */
 		printk(version);	/* we only display this string ONCE */
 	}
-#endif
+
+	if (pdev != NULL)
+		print_name = pdev->slot_name;
 
 	dev = alloc_fddidev(sizeof(*bp));
 	if (!dev) {
-		printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n");
+		printk(KERN_ERR "%s: unable to allocate fddidev, aborting\n",
+		       print_name);
 		return -ENOMEM;
 	}
 
@@ -437,9 +441,12 @@ static int __devinit dfx_init_one_pci_or
 
 	bp = dev->priv;
 
-	if (!request_region (ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, DRV_NAME)) {
-		printk (KERN_ERR "%s: Cannot reserve I/O resource 0x%x @ 0x%lx, aborting\n",
-			DRV_NAME, PFI_K_CSR_IO_LEN, ioaddr);
+	if (!request_region(ioaddr,
+			    pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN,
+			    print_name)) {
+		printk(KERN_ERR "%s: Cannot reserve I/O resource "
+		       "0x%x @ 0x%lx, aborting\n", print_name,
+		       pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN, ioaddr);
 		err = -EBUSY;
 		goto err_out;
 	}
@@ -468,7 +475,7 @@ static int __devinit dfx_init_one_pci_or
 		pci_set_master (pdev);
 	}
 
-	if (dfx_driver_init(dev) != DFX_K_SUCCESS) {
+	if (dfx_driver_init(dev, print_name) != DFX_K_SUCCESS) {
 		err = -ENODEV;
 		goto err_out_region;
 	}
@@ -477,6 +484,7 @@ static int __devinit dfx_init_one_pci_or
 	if (err)
 		goto err_out_kfree;
 
+	printk("%s: registered as %s\n", print_name, dev->name);
 	return 0;
 
 err_out_kfree:
@@ -770,6 +778,7 @@ static void __devinit dfx_bus_config_che
  *       
  * Arguments:
  *   dev - pointer to device information
+ *   print_name - printable device name
  *
  * Functional Description:
  *   This function allocates additional resources such as the host memory
@@ -792,7 +801,8 @@ static void __devinit dfx_bus_config_che
  *   returning from this routine.
  */
 
-static int __devinit dfx_driver_init(struct net_device *dev)
+static int __devinit dfx_driver_init(struct net_device *dev,
+				     const char *print_name)
 {
 	DFX_board_t *bp = dev->priv;
 	int			alloc_size;			/* total buffer size needed */
@@ -841,26 +851,20 @@ static int __devinit dfx_driver_init(str
 
 	/*  Read the factory MAC address from the adapter then save it */
 
-	if (dfx_hw_port_ctrl_req(bp,
-							PI_PCTRL_M_MLA,
-							PI_PDATA_A_MLA_K_LO,
-							0,
-							&data) != DFX_K_SUCCESS)
-		{
-		printk("%s: Could not read adapter factory MAC address!\n", dev->name);
+	if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_LO, 0,
+				 &data) != DFX_K_SUCCESS) {
+		printk("%s: Could not read adapter factory MAC address!\n",
+		       print_name);
 		return(DFX_K_FAILURE);
-		}
+	}
 	memcpy(&bp->factory_mac_addr[0], &data, sizeof(u32));
 
-	if (dfx_hw_port_ctrl_req(bp,
-							PI_PCTRL_M_MLA,
-							PI_PDATA_A_MLA_K_HI,
-							0,
-							&data) != DFX_K_SUCCESS)
-		{
-		printk("%s: Could not read adapter factory MAC address!\n", dev->name);
+	if (dfx_hw_port_ctrl_req(bp, PI_PCTRL_M_MLA, PI_PDATA_A_MLA_K_HI, 0,
+				 &data) != DFX_K_SUCCESS) {
+		printk("%s: Could not read adapter factory MAC address!\n",
+		       print_name);
 		return(DFX_K_FAILURE);
-		}
+	}
 	memcpy(&bp->factory_mac_addr[4], &data, sizeof(u16));
 
 	/*
@@ -872,27 +876,19 @@ static int __devinit dfx_driver_init(str
 
 	memcpy(dev->dev_addr, bp->factory_mac_addr, FDDI_K_ALEN);
 	if (bp->bus_type == DFX_BUS_TYPE_EISA)
-		printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
-				dev->name,
-				dev->base_addr,
-				dev->irq,
-				dev->dev_addr[0],
-				dev->dev_addr[1],
-				dev->dev_addr[2],
-				dev->dev_addr[3],
-				dev->dev_addr[4],
-				dev->dev_addr[5]);
+		printk("%s: DEFEA at I/O addr = 0x%lX, IRQ = %d, "
+		       "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+		       print_name, dev->base_addr, dev->irq,
+		       dev->dev_addr[0], dev->dev_addr[1],
+		       dev->dev_addr[2], dev->dev_addr[3],
+		       dev->dev_addr[4], dev->dev_addr[5]);
 	else
-		printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
-				dev->name,
-				dev->base_addr,
-				dev->irq,
-				dev->dev_addr[0],
-				dev->dev_addr[1],
-				dev->dev_addr[2],
-				dev->dev_addr[3],
-				dev->dev_addr[4],
-				dev->dev_addr[5]);
+		printk("%s: DEFPA at I/O addr = 0x%lX, IRQ = %d, "
+		       "Hardware addr = %02X-%02X-%02X-%02X-%02X-%02X\n",
+		       print_name, dev->base_addr, dev->irq,
+		       dev->dev_addr[0], dev->dev_addr[1],
+		       dev->dev_addr[2], dev->dev_addr[3],
+		       dev->dev_addr[4], dev->dev_addr[5]);
 
 	/*
 	 * Get memory for descriptor block, consumer block, and other buffers
@@ -909,11 +905,11 @@ static int __devinit dfx_driver_init(str
 					(PI_ALIGN_K_DESC_BLK - 1);
 	bp->kmalloced = top_v = pci_alloc_consistent(bp->pci_dev, alloc_size,
 						     &bp->kmalloced_dma);
-	if (top_v == NULL)
-		{
-		printk("%s: Could not allocate memory for host buffers and structures!\n", dev->name);
+	if (top_v == NULL) {
+		printk("%s: Could not allocate memory for host buffers "
+		       "and structures!\n", print_name);
 		return(DFX_K_FAILURE);
-		}
+	}
 	memset(top_v, 0, alloc_size);	/* zero out memory before continuing */
 	top_p = bp->kmalloced_dma;	/* get physical address of buffer */
 
@@ -970,14 +966,20 @@ static int __devinit dfx_driver_init(str
 
 	/* Display virtual and physical addresses if debug driver */
 
-	DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n",				dev->name, (long)bp->descr_block_virt,	bp->descr_block_phys);
-	DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n",			dev->name, (long)bp->cmd_req_virt,		bp->cmd_req_phys);
-	DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n",			dev->name, (long)bp->cmd_rsp_virt,		bp->cmd_rsp_phys);
-	DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n",			dev->name, (long)bp->rcv_block_virt,	bp->rcv_block_phys);
-	DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",				dev->name, (long)bp->cons_block_virt,	bp->cons_block_phys);
+	DBG_printk("%s: Descriptor block virt = %0lX, phys = %0X\n",
+		   print_name,
+		   (long)bp->descr_block_virt, bp->descr_block_phys);
+	DBG_printk("%s: Command Request buffer virt = %0lX, phys = %0X\n",
+		   print_name, (long)bp->cmd_req_virt, bp->cmd_req_phys);
+	DBG_printk("%s: Command Response buffer virt = %0lX, phys = %0X\n",
+		   print_name, (long)bp->cmd_rsp_virt, bp->cmd_rsp_phys);
+	DBG_printk("%s: Receive buffer block virt = %0lX, phys = %0X\n",
+		   print_name, (long)bp->rcv_block_virt, bp->rcv_block_phys);
+	DBG_printk("%s: Consumer block virt = %0lX, phys = %0X\n",
+		   print_name, (long)bp->cons_block_virt, bp->cons_block_phys);
 
 	return(DFX_K_SUCCESS);
-	}
+}
 
 
 /*
@@ -2666,12 +2668,12 @@ static int dfx_hw_dma_uninit(DFX_board_t
  
 static void my_skb_align(struct sk_buff *skb, int n)
 {
-	unsigned long x=(unsigned long)skb->data;	
+	unsigned long x = (unsigned long)skb->data;
 	unsigned long v;
 	
-	v=(x+n-1)&~(n-1);	/* Where we want to be */
+	v = ALIGN(x, n);	/* Where we want to be */
 	
-	skb_reserve(skb, v-x);
+	skb_reserve(skb, v - x);
 }
 
 
@@ -3426,11 +3428,6 @@ static int __init dfx_init(void)
 {
 	int rc_pci, rc_eisa;
 
-/* when a module, this is printed whether or not devices are found in probe */
-#ifdef MODULE
-	printk(version);
-#endif
-
 	rc_pci = pci_module_init(&dfx_driver);
 	if (rc_pci >= 0) dfx_have_pci = 1;
 	
@@ -3451,6 +3448,9 @@ static void __exit dfx_cleanup(void)
 
 module_init(dfx_init);
 module_exit(dfx_cleanup);
+MODULE_AUTHOR("Lawrence V. Stefani");
+MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
+		   DRV_VERSION " " DRV_RELDATE);
 MODULE_LICENSE("GPL");
 
 
diff -puN drivers/net/defxx.h~bk-netdev drivers/net/defxx.h
--- 25/drivers/net/defxx.h~bk-netdev	2004-09-06 18:43:15.611897016 -0700
+++ 25-akpm/drivers/net/defxx.h	2004-09-06 18:43:15.777871784 -0700
@@ -16,7 +16,7 @@
  *   LVS	Lawrence V. Stefani <lstefani@yahoo.com>
  *
  * Maintainers:
- *   macro	Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ *   macro	Maciej W. Rozycki <macro@linux-mips.org>
  *
  * Modification History:
  *		Date		Name	Description
diff -puN drivers/net/dl2k.c~bk-netdev drivers/net/dl2k.c
--- 25/drivers/net/dl2k.c~bk-netdev	2004-09-06 18:43:15.613896712 -0700
+++ 25-akpm/drivers/net/dl2k.c	2004-09-06 18:43:15.780871328 -0700
@@ -107,7 +107,6 @@ static int change_mtu (struct net_device
 static void set_multicast (struct net_device *dev);
 static struct net_device_stats *get_stats (struct net_device *dev);
 static int clear_stats (struct net_device *dev);
-static int rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr);
 static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int rio_close (struct net_device *dev);
 static int find_miiphy (struct net_device *dev);
@@ -122,6 +121,8 @@ static int mii_read (struct net_device *
 static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
 		      u16 data);
 
+static struct ethtool_ops ethtool_ops;
+
 static int __devinit
 rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
 {
@@ -168,7 +169,7 @@ rio_probe1 (struct pci_dev *pdev, const 
 #endif
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
-	np = dev->priv;
+	np = netdev_priv(dev);
 	np->chip_id = chip_idx;
 	np->pdev = pdev;
 	spin_lock_init (&np->tx_lock);
@@ -244,6 +245,7 @@ rio_probe1 (struct pci_dev *pdev, const 
 	dev->tx_timeout = &rio_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->change_mtu = &change_mtu;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 #if 0
 	dev->features = NETIF_F_IP_CSUM;
 #endif
@@ -335,7 +337,7 @@ find_miiphy (struct net_device *dev)
 	int i, phy_found = 0;
 	struct netdev_private *np;
 	long ioaddr;
-	np = dev->priv;
+	np = netdev_priv(dev);
 	ioaddr = dev->base_addr;
 	np->phy_addr = 1;
 
@@ -362,7 +364,7 @@ parse_eeprom (struct net_device *dev)
 	u8 *psib;
 	u32 crc;
 	PSROM_t psrom = (PSROM_t) sromdata;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	int cid, next;
 
@@ -432,7 +434,7 @@ parse_eeprom (struct net_device *dev)
 static int
 rio_open (struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 	u16 macctrl;
@@ -516,7 +518,7 @@ static void 
 rio_timer (unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned int entry;
 	int next_tick = 1*HZ;
 	unsigned long flags;
@@ -574,7 +576,7 @@ rio_tx_timeout (struct net_device *dev)
 static void
 alloc_list (struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int i;
 
 	np->cur_rx = np->cur_tx = 0;
@@ -631,7 +633,7 @@ alloc_list (struct net_device *dev)
 static int
 start_xmit (struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct netdev_desc *txdesc;
 	unsigned entry;
 	u32 ioaddr;
@@ -711,7 +713,7 @@ rio_interrupt (int irq, void *dev_instan
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	np = dev->priv;
+	np = netdev_priv(dev);
 	while (1) {
 		int_status = readw (ioaddr + IntStatus); 
 		writew (int_status, ioaddr + IntStatus);
@@ -745,7 +747,7 @@ rio_interrupt (int irq, void *dev_instan
 static void 
 rio_free_tx (struct net_device *dev, int irq) 
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int entry = np->old_tx % TX_RING_SIZE;
 	int tx_use = 0;
 	unsigned long flag = 0;
@@ -798,7 +800,7 @@ tx_error (struct net_device *dev, int tx
 	int frame_id;
 	int i;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 
 	frame_id = (tx_status & 0xffff0000);
 	printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n",
@@ -855,7 +857,7 @@ tx_error (struct net_device *dev, int tx
 static int
 receive_packet (struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int cnt = 30;
 
@@ -965,7 +967,7 @@ static void
 rio_error (struct net_device *dev, int int_status)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	u16 macctrl;
 
 	/* Link change event */
@@ -1016,7 +1018,7 @@ static struct net_device_stats *
 get_stats (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 #ifdef MEM_MAPPING
 	int i;
 #endif
@@ -1132,7 +1134,7 @@ clear_stats (struct net_device *dev)
 int
 change_mtu (struct net_device *dev, int new_mtu)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int max = (np->jumbo) ? MAX_JUMBO : 1536;
 
 	if ((new_mtu < 68) || (new_mtu > max)) {
@@ -1150,7 +1152,7 @@ set_multicast (struct net_device *dev)
 	long ioaddr = dev->base_addr;
 	u32 hash_table[2];
 	u16 rx_mode = 0;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	
 	hash_table[0] = hash_table[1] = 0;
 	/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
@@ -1194,137 +1196,118 @@ set_multicast (struct net_device *dev)
 	writew (rx_mode, ioaddr + ReceiveMode);
 }
 
-static int
-rio_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
+static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	strcpy(info->driver, "DL2K");
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pdev));
+}	
+
+static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	struct netdev_private *np = dev->priv;
-       	u32 ethcmd;
+	struct netdev_private *np = netdev_priv(dev);
+	if (np->phy_media) {
+		/* fiber device */
+		cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
+		cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
+		cmd->port = PORT_FIBRE;
+		cmd->transceiver = XCVR_INTERNAL;	
+	} else {
+		/* copper device */
+		cmd->supported = SUPPORTED_10baseT_Half | 
+			SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+			| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+			SUPPORTED_Autoneg | SUPPORTED_MII;
+		cmd->advertising = ADVERTISED_10baseT_Half |
+			ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+			ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+			ADVERTISED_Autoneg | ADVERTISED_MII;
+		cmd->port = PORT_MII;
+		cmd->transceiver = XCVR_INTERNAL;
+	}
+	if ( np->link_status ) { 
+		cmd->speed = np->speed;
+		cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	} else {
+		cmd->speed = -1;
+		cmd->duplex = -1;
+	}
+	if ( np->an_enable)
+		cmd->autoneg = AUTONEG_ENABLE;
+	else
+		cmd->autoneg = AUTONEG_DISABLE;
 	
-	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-	switch (ethcmd) {
-		case ETHTOOL_GDRVINFO: {
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy(info.driver, "DL2K");
-			strcpy(info.version, DRV_VERSION);
-			strcpy(info.bus_info, pci_name(np->pdev));
-			memset(&info.fw_version, 0, sizeof(info.fw_version));
-			if (copy_to_user(useraddr, &info, sizeof(info)))
-				return -EFAULT;
+	cmd->phy_address = np->phy_addr;
+	return 0;				   
+}
+
+static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	netif_carrier_off(dev);
+	if (cmd->autoneg == AUTONEG_ENABLE) {
+		if (np->an_enable)
 			return 0;
+		else {
+			np->an_enable = 1;
+			mii_set_media(dev);
+			return 0;	
 		}	
- 	
-		case ETHTOOL_GSET: {
-			struct ethtool_cmd cmd = { ETHTOOL_GSET };
-			if (np->phy_media) {
-				/* fiber device */
-				cmd.supported = SUPPORTED_Autoneg | 
-							SUPPORTED_FIBRE;
-				cmd.advertising= ADVERTISED_Autoneg |
-							ADVERTISED_FIBRE;
-				cmd.port = PORT_FIBRE;
-				cmd.transceiver = XCVR_INTERNAL;	
-			} else {
-				/* copper device */
-				cmd.supported = SUPPORTED_10baseT_Half | 
-					SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
-					| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
-					SUPPORTED_Autoneg | SUPPORTED_MII;
-				cmd.advertising = ADVERTISED_10baseT_Half |
-					ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
-					ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
-					ADVERTISED_Autoneg | ADVERTISED_MII;
-				cmd.port = PORT_MII;
-				cmd.transceiver = XCVR_INTERNAL;
-			}
-			if ( np->link_status ) { 
-				cmd.speed = np->speed;
-				cmd.duplex = np->full_duplex ? 
-						    DUPLEX_FULL : DUPLEX_HALF;
-			} else {
-				cmd.speed = -1;
-				cmd.duplex = -1;
-			}
-			if ( np->an_enable)
-				cmd.autoneg = AUTONEG_ENABLE;
-			else
-				cmd.autoneg = AUTONEG_DISABLE;
-			
-			cmd.phy_address = np->phy_addr;
-
-			if (copy_to_user(useraddr, &cmd,
-					sizeof(cmd)))
-				return -EFAULT;
-			return 0;				   
-		}
-		case ETHTOOL_SSET: {
-			struct ethtool_cmd cmd;
-			if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
-				return -EFAULT;
-			netif_carrier_off(dev);
-			if (cmd.autoneg == AUTONEG_ENABLE) {
-				if (np->an_enable)
-					return 0;
-				else {
-					np->an_enable = 1;
-					mii_set_media(dev);
-					return 0;	
-				}	
-			} else {
-				np->an_enable = 0;
-				if (np->speed == 1000){
-					cmd.speed = SPEED_100;			
-					cmd.duplex = DUPLEX_FULL;
-					printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.\n");
-					}
-				switch(cmd.speed + cmd.duplex){
-				
-				case SPEED_10 + DUPLEX_HALF:
-					np->speed = 10;
-					np->full_duplex = 0;
-					break;
-				
-				case SPEED_10 + DUPLEX_FULL:
-					np->speed = 10;
-					np->full_duplex = 1;
-					break;
-				case SPEED_100 + DUPLEX_HALF:
-					np->speed = 100;
-					np->full_duplex = 0;
-					break;
-				case SPEED_100 + DUPLEX_FULL:
-					np->speed = 100;
-					np->full_duplex = 1;
-					break;
-				case SPEED_1000 + DUPLEX_HALF:/* not supported */
-				case SPEED_1000 + DUPLEX_FULL:/* not supported */
-				default:
-					return -EINVAL;	
-				}
-				mii_set_media(dev);
-			}
-		return 0;		   
+	} else {
+		np->an_enable = 0;
+		if (np->speed == 1000) {
+			cmd->speed = SPEED_100;			
+			cmd->duplex = DUPLEX_FULL;
+			printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
 		}
-#ifdef ETHTOOL_GLINK		
-		case ETHTOOL_GLINK:{
-		struct ethtool_value link = { ETHTOOL_GLINK };
-		link.data = np->link_status;
-		if (copy_to_user(useraddr, &link, sizeof(link)))
-			return -EFAULT;
-		return 0;
-		}			   
-#endif
+		switch(cmd->speed + cmd->duplex) {
+		
+		case SPEED_10 + DUPLEX_HALF:
+			np->speed = 10;
+			np->full_duplex = 0;
+			break;
+		
+		case SPEED_10 + DUPLEX_FULL:
+			np->speed = 10;
+			np->full_duplex = 1;
+			break;
+		case SPEED_100 + DUPLEX_HALF:
+			np->speed = 100;
+			np->full_duplex = 0;
+			break;
+		case SPEED_100 + DUPLEX_FULL:
+			np->speed = 100;
+			np->full_duplex = 1;
+			break;
+		case SPEED_1000 + DUPLEX_HALF:/* not supported */
+		case SPEED_1000 + DUPLEX_FULL:/* not supported */
 		default:
-		return -EOPNOTSUPP;
-	}	
+			return -EINVAL;	
+		}
+		mii_set_media(dev);
+	}
+	return 0;
+}
+
+static u32 rio_get_link(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return np->link_status;
 }
 
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = rio_get_drvinfo,
+	.get_settings = rio_get_settings,
+	.set_settings = rio_set_settings,
+	.get_link = rio_get_link,
+};
 
 static int
 rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int phy_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
 	
 	struct netdev_desc *desc;
@@ -1332,8 +1315,6 @@ rio_ioctl (struct net_device *dev, struc
 
 	phy_addr = np->phy_addr;
 	switch (cmd) {
-	case SIOCETHTOOL:
-		return rio_ethtool_ioctl(dev, rq->ifr_data);		
 	case SIOCDEVPRIVATE:
 		break;
 	
@@ -1490,7 +1471,7 @@ mii_wait_link (struct net_device *dev, i
 	int phy_addr;
 	struct netdev_private *np;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 	phy_addr = np->phy_addr;
 
 	do {
@@ -1512,7 +1493,7 @@ mii_get_media (struct net_device *dev)
 	int phy_addr;
 	struct netdev_private *np;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 	phy_addr = np->phy_addr;
 
 	bmsr.image = mii_read (dev, phy_addr, MII_BMSR);
@@ -1594,7 +1575,7 @@ mii_set_media (struct net_device *dev)
 	ANAR_t anar;
 	int phy_addr;
 	struct netdev_private *np;
-	np = dev->priv;
+	np = netdev_priv(dev);
 	phy_addr = np->phy_addr;
 
 	/* Does user set speed? */
@@ -1684,7 +1665,7 @@ mii_get_media_pcs (struct net_device *de
 	int phy_addr;
 	struct netdev_private *np;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 	phy_addr = np->phy_addr;
 
 	bmsr.image = mii_read (dev, phy_addr, PCS_BMSR);
@@ -1740,7 +1721,7 @@ mii_set_media_pcs (struct net_device *de
 	ANAR_PCS_t anar;
 	int phy_addr;
 	struct netdev_private *np;
-	np = dev->priv;
+	np = netdev_priv(dev);
 	phy_addr = np->phy_addr;
 
 	/* Auto-Negotiation? */
@@ -1794,7 +1775,7 @@ static int
 rio_close (struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct sk_buff *skb;
 	int i;
 
@@ -1840,7 +1821,7 @@ rio_remove1 (struct pci_dev *pdev)
 	struct net_device *dev = pci_get_drvdata (pdev);
 
 	if (dev) {
-		struct netdev_private *np = dev->priv;
+		struct netdev_private *np = netdev_priv(dev);
 
 		unregister_netdev (dev);
 		pci_free_consistent (pdev, RX_TOTAL_SIZE, np->rx_ring,
diff -puN drivers/net/eepro100.c~bk-netdev drivers/net/eepro100.c
--- 25/drivers/net/eepro100.c~bk-netdev	2004-09-06 18:43:15.615896408 -0700
+++ 25-akpm/drivers/net/eepro100.c	2004-09-06 18:43:15.783870872 -0700
@@ -541,6 +541,7 @@ static struct net_device_stats *speedo_g
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
 static void speedo_show_state(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
 
 
 
@@ -895,6 +896,7 @@ static int __devinit speedo_found1(struc
 	dev->get_stats = &speedo_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &speedo_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &poll_speedo;
 #endif
@@ -2010,82 +2012,68 @@ speedo_get_stats(struct net_device *dev)
 	return &sp->stats;
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void speedo_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
 	struct speedo_private *sp = netdev_priv(dev);
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-	
-        switch (ethcmd) {
-	/* get driver-specific version/etc. info */
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, "eepro100", sizeof(info.driver)-1);
-		strncpy(info.version, version, sizeof(info.version)-1);
-		if (sp && sp->pdev)
-			strcpy(info.bus_info, pci_name(sp->pdev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&sp->lock);
-		mii_ethtool_gset(&sp->mii_if, &ecmd);
-		spin_unlock_irq(&sp->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&sp->lock);
-		r = mii_ethtool_sset(&sp->mii_if, &ecmd);
-		spin_unlock_irq(&sp->lock);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&sp->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = mii_link_ok(&sp->mii_if);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = sp->msg_enable;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		sp->msg_enable = edata.data;
-		return 0;
-	}
+	strncpy(info->driver, "eepro100", sizeof(info->driver)-1);
+	strncpy(info->version, version, sizeof(info->version)-1);
+	if (sp->pdev)
+		strcpy(info->bus_info, pci_name(sp->pdev));
+}
 
-        }
-	
-	return -EOPNOTSUPP;
+static int speedo_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	spin_lock_irq(&sp->lock);
+	mii_ethtool_gset(&sp->mii_if, ecmd);
+	spin_unlock_irq(&sp->lock);
+	return 0;
+}
+
+static int speedo_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&sp->lock);
+	res = mii_ethtool_sset(&sp->mii_if, ecmd);
+	spin_unlock_irq(&sp->lock);
+	return res;
+}
+
+static int speedo_nway_reset(struct net_device *dev)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	return mii_nway_restart(&sp->mii_if);
+}
+
+static u32 speedo_get_link(struct net_device *dev)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	return mii_link_ok(&sp->mii_if);
 }
 
+static u32 speedo_get_msglevel(struct net_device *dev)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	return sp->msg_enable;
+}
+
+static void speedo_set_msglevel(struct net_device *dev, u32 v)
+{
+	struct speedo_private *sp = netdev_priv(dev);
+	sp->msg_enable = v;
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = speedo_get_drvinfo,
+	.get_settings = speedo_get_settings,
+	.set_settings = speedo_set_settings,
+	.nway_reset = speedo_nway_reset,
+	.get_link = speedo_get_link,
+	.get_msglevel = speedo_get_msglevel,
+	.set_msglevel = speedo_set_msglevel,
+};
+
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = netdev_priv(dev);
@@ -2121,8 +2109,6 @@ static int speedo_ioctl(struct net_devic
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
 		return 0;
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, rq->ifr_data);
 	default:
 		return -EOPNOTSUPP;
 	}
diff -puN drivers/net/ewrk3.c~bk-netdev drivers/net/ewrk3.c
--- 25/drivers/net/ewrk3.c~bk-netdev	2004-09-06 18:43:15.616896256 -0700
+++ 25-akpm/drivers/net/ewrk3.c	2004-09-06 18:43:15.787870264 -0700
@@ -305,6 +305,8 @@ static int ewrk3_close(struct net_device
 static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static struct ethtool_ops ethtool_ops_203;
+static struct ethtool_ops ethtool_ops;
 
 /*
    ** Private functions
@@ -532,7 +534,7 @@ ewrk3_hw_init(struct net_device *dev, u_
 		printk("      is in I/O only mode");
 	}
 
-	lp = (struct ewrk3_private *) dev->priv;
+	lp = netdev_priv(dev);
 	lp->shmem_base = mem_start;
 	lp->shmem_length = shmem_length;
 	lp->lemac = lemac;
@@ -610,6 +612,10 @@ ewrk3_hw_init(struct net_device *dev, u_
 	dev->get_stats = ewrk3_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->do_ioctl = ewrk3_ioctl;
+	if (lp->adapter_name[4] == '3')
+		SET_ETHTOOL_OPS(dev, &ethtool_ops_203);
+	else
+		SET_ETHTOOL_OPS(dev, &ethtool_ops);
 	dev->tx_timeout = ewrk3_timeout;
 	dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
 	
@@ -621,7 +627,7 @@ ewrk3_hw_init(struct net_device *dev, u_
 
 static int ewrk3_open(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	int i, status = 0;
 	u_char icr, csr;
@@ -684,7 +690,7 @@ static int ewrk3_open(struct net_device 
  */
 static void ewrk3_init(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_char csr, page;
 	u_long iobase = dev->base_addr;
 	int i;
@@ -725,7 +731,7 @@ static void ewrk3_init(struct net_device
  
 static void ewrk3_timeout(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_char icr, csr;
 	u_long iobase = dev->base_addr;
 	
@@ -761,7 +767,7 @@ static void ewrk3_timeout(struct net_dev
  */
 static int ewrk3_queue_pkt (struct sk_buff *skb, struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	u_long buf = 0;
 	u_char icr;
@@ -883,7 +889,7 @@ static irqreturn_t ewrk3_interrupt(int i
 	u_long iobase;
 	u_char icr, cr, csr;
 
-	lp = (struct ewrk3_private *) dev->priv;
+	lp = netdev_priv(dev);
 	iobase = dev->base_addr;
 
 	/* get the interrupt information */
@@ -931,7 +937,7 @@ static irqreturn_t ewrk3_interrupt(int i
 /* Called with lp->hw_lock held */
 static int ewrk3_rx(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	int i, status = 0;
 	u_char page;
@@ -1059,7 +1065,7 @@ static int ewrk3_rx(struct net_device *d
 */
 static int ewrk3_tx(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	u_char tx_status;
 
@@ -1095,7 +1101,7 @@ static int ewrk3_tx(struct net_device *d
 
 static int ewrk3_close(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	u_char icr, csr;
 
@@ -1130,7 +1136,7 @@ static int ewrk3_close(struct net_device
 
 static struct net_device_stats *ewrk3_get_stats(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 
 	/* Null body since there is no framing error counter */
 	return &lp->stats;
@@ -1141,7 +1147,7 @@ static struct net_device_stats *ewrk3_ge
  */
 static void set_multicast_list(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
 	u_char csr;
 
@@ -1174,7 +1180,7 @@ static void set_multicast_list(struct ne
  */
 static void SetMulticastFilter(struct net_device *dev)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	struct dev_mc_list *dmi = dev->mc_list;
 	u_long iobase = dev->base_addr;
 	int i;
@@ -1520,187 +1526,165 @@ static int __init EISA_signature(char *n
 	return status;		/* return the device name string */
 }
 
-static int ewrk3_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void ewrk3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
-	u_long iobase = dev->base_addr;
-	u32 ethcmd;
-
-	if (get_user(ethcmd, (u32 __user *)useraddr))
-		return -EFAULT;
-
-	switch (ethcmd) {
-
-	/* Get driver info */
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
-
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		sprintf(info.fw_version, "%d", fwrev);
-		strcpy(info.bus_info, "N/A");
-		info.eedump_len = EEPROM_MAX;
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* Get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		u_char cr = inb(EWRK3_CR);
-
-		switch (lp->adapter_name[4]) {
-		case '3': /* DE203 */
-			ecmd.supported = SUPPORTED_BNC;
-			ecmd.port = PORT_BNC;
-			break;
-
-		case '4': /* DE204 */
-			ecmd.supported = SUPPORTED_TP;
-			ecmd.port = PORT_TP;
-			break;
-
-		case '5': /* DE205 */
-			ecmd.supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
-			ecmd.autoneg = !(cr & CR_APD);
-			/*
-			** Port is only valid if autoneg is disabled
-			** and even then we don't know if AUI is jumpered.
-			*/
-			if (!ecmd.autoneg)
-				ecmd.port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
-			break;
-		}
+	int fwrev = Read_EEPROM(dev->base_addr, EEPROM_REVLVL);
 
-		ecmd.supported |= SUPPORTED_10baseT_Half;
-		ecmd.speed = SPEED_10;
-		ecmd.duplex = DUPLEX_HALF;
-
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-
-	/* Set settings */
-	case ETHTOOL_SSET: {
-		struct ethtool_cmd ecmd;
-		u_char cr;
-		u_long flags;
-
-		/* DE205 is the only card with anything to set */
-		if (lp->adapter_name[4] != '5')
-			return -EOPNOTSUPP;
-
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-
-		/* Sanity-check parameters */
-		if (ecmd.speed != SPEED_10)
-			return -EINVAL;
-		if (ecmd.port != PORT_TP && ecmd.port != PORT_BNC)
-			return -EINVAL; /* AUI is not software-selectable */
-		if (ecmd.transceiver != XCVR_INTERNAL)
-			return -EINVAL;
-		if (ecmd.duplex != DUPLEX_HALF)
-			return -EINVAL;
-		if (ecmd.phy_address != 0)
-			return -EINVAL;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	sprintf(info->fw_version, "%d", fwrev);
+	strcpy(info->bus_info, "N/A");
+	info->eedump_len = EEPROM_MAX;
+}
 
-		spin_lock_irqsave(&lp->hw_lock, flags);
-		cr = inb(EWRK3_CR);
+static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct ewrk3_private *lp = netdev_priv(dev);
+	unsigned long iobase = dev->base_addr;
+	u8 cr = inb(EWRK3_CR);
 
-		/* If Autoneg is set, change to Auto Port mode */
-		/* Otherwise, disable Auto Port and set port explicitly */
-		if (ecmd.autoneg) {
-			cr &= ~CR_APD;
-		} else {
-			cr |= CR_APD;
-			if (ecmd.port == PORT_TP)
-				cr &= ~CR_PSEL;		/* Force TP */
-			else
-				cr |= CR_PSEL;		/* Force BNC */
-		}
+	switch (lp->adapter_name[4]) {
+	case '3': /* DE203 */
+		ecmd->supported = SUPPORTED_BNC;
+		ecmd->port = PORT_BNC;
+		break;
 
-		/* Commit the changes */
-		outb(cr, EWRK3_CR);
+	case '4': /* DE204 */
+		ecmd->supported = SUPPORTED_TP;
+		ecmd->port = PORT_TP;
+		break;
 
-		spin_unlock_irqrestore(&lp->hw_lock, flags);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
+	case '5': /* DE205 */
+		ecmd->supported = SUPPORTED_TP | SUPPORTED_BNC | SUPPORTED_AUI;
+		ecmd->autoneg = !(cr & CR_APD);
+		/*
+		** Port is only valid if autoneg is disabled
+		** and even then we don't know if AUI is jumpered.
+		*/
+		if (!ecmd->autoneg)
+			ecmd->port = (cr & CR_PSEL) ? PORT_BNC : PORT_TP;
+		break;
 	}
 
-	/* Get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = { ETHTOOL_GLINK };
-		u_char cmr = inb(EWRK3_CMR);
+	ecmd->supported |= SUPPORTED_10baseT_Half;
+	ecmd->speed = SPEED_10;
+	ecmd->duplex = DUPLEX_HALF;
+	return 0;
+}
 
-		/* DE203 has BNC only and link status does not apply */
-		if (lp->adapter_name[4] == '3')
-			return -EOPNOTSUPP;
+static int ewrk3_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct ewrk3_private *lp = netdev_priv(dev);
+	unsigned long iobase = dev->base_addr;
+	unsigned long flags;
+	u8 cr;
 
-		/* On DE204 this is always valid since TP is the only port. */
-		/* On DE205 this reflects TP status even if BNC or AUI is selected. */
-		edata.data = !(cmr & CMR_LINK);
+	/* DE205 is the only card with anything to set */
+	if (lp->adapter_name[4] != '5')
+		return -EOPNOTSUPP;
 
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+	/* Sanity-check parameters */
+	if (ecmd->speed != SPEED_10)
+		return -EINVAL;
+	if (ecmd->port != PORT_TP && ecmd->port != PORT_BNC)
+		return -EINVAL; /* AUI is not software-selectable */
+	if (ecmd->transceiver != XCVR_INTERNAL)
+		return -EINVAL;
+	if (ecmd->duplex != DUPLEX_HALF)
+		return -EINVAL;
+	if (ecmd->phy_address != 0)
+		return -EINVAL;
 
-	/* Blink LED for identification */
-	case ETHTOOL_PHYS_ID: {
-		struct ethtool_value edata;
-		u_long flags;
-		u_char cr;
-		int count;
+	spin_lock_irqsave(&lp->hw_lock, flags);
+	cr = inb(EWRK3_CR);
 
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
+	/* If Autoneg is set, change to Auto Port mode */
+	/* Otherwise, disable Auto Port and set port explicitly */
+	if (ecmd->autoneg) {
+		cr &= ~CR_APD;
+	} else {
+		cr |= CR_APD;
+		if (ecmd->port == PORT_TP)
+			cr &= ~CR_PSEL;		/* Force TP */
+		else
+			cr |= CR_PSEL;		/* Force BNC */
+	}
 
-		/* Toggle LED 4x per second */
-		count = edata.data << 2;
+	/* Commit the changes */
+	outb(cr, EWRK3_CR);
+	spin_unlock_irqrestore(&lp->hw_lock, flags);
+	return 0;
+}
 
-		spin_lock_irqsave(&lp->hw_lock, flags);
+static u32 ewrk3_get_link(struct net_device *dev)
+{
+	unsigned long iobase = dev->base_addr;
+	u8 cmr = inb(EWRK3_CMR);
+	/* DE203 has BNC only and link status does not apply */
+	/* On DE204 this is always valid since TP is the only port. */
+	/* On DE205 this reflects TP status even if BNC or AUI is selected. */
+	return !(cmr & CMR_LINK);
+}
 
-		/* Bail if a PHYS_ID is already in progress */
-		if (lp->led_mask == 0) {
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-			return -EBUSY;
-		}
+static int ewrk3_phys_id(struct net_device *dev, u32 data)
+{
+	struct ewrk3_private *lp = netdev_priv(dev);
+	unsigned long iobase = dev->base_addr;
+	unsigned long flags;
+	u8 cr;
+	int count;
 
-		/* Prevent ISR from twiddling the LED */
-		lp->led_mask = 0;
+	/* Toggle LED 4x per second */
+	count = data << 2;
 
-		while (count--) {
-			/* Toggle the LED */
-			cr = inb(EWRK3_CR);
-			outb(cr ^ CR_LED, EWRK3_CR);
+	spin_lock_irqsave(&lp->hw_lock, flags);
 
-			/* Wait a little while */
-			spin_unlock_irqrestore(&lp->hw_lock, flags);
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ>>2);
-			spin_lock_irqsave(&lp->hw_lock, flags);
+	/* Bail if a PHYS_ID is already in progress */
+	if (lp->led_mask == 0) {
+		spin_unlock_irqrestore(&lp->hw_lock, flags);
+		return -EBUSY;
+	}
 
-			/* Exit if we got a signal */
-			if (signal_pending(current))
-				break;
-		}
+	/* Prevent ISR from twiddling the LED */
+	lp->led_mask = 0;
 
-		lp->led_mask = CR_LED;
+	while (count--) {
+		/* Toggle the LED */
 		cr = inb(EWRK3_CR);
-		outb(cr & ~CR_LED, EWRK3_CR);
+		outb(cr ^ CR_LED, EWRK3_CR);
+
+		/* Wait a little while */
 		spin_unlock_irqrestore(&lp->hw_lock, flags);
-		return signal_pending(current) ? -ERESTARTSYS : 0;
-	}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ>>2);
+		spin_lock_irqsave(&lp->hw_lock, flags);
 
+		/* Exit if we got a signal */
+		if (signal_pending(current))
+			break;
 	}
 
-	return -EOPNOTSUPP;
-}
+	lp->led_mask = CR_LED;
+	cr = inb(EWRK3_CR);
+	outb(cr & ~CR_LED, EWRK3_CR);
+	spin_unlock_irqrestore(&lp->hw_lock, flags);
+	return signal_pending(current) ? -ERESTARTSYS : 0;
+}
+
+static struct ethtool_ops ethtool_ops_203 = {
+	.get_drvinfo = ewrk3_get_drvinfo,
+	.get_settings = ewrk3_get_settings,
+	.set_settings = ewrk3_set_settings,
+	.phys_id = ewrk3_phys_id,
+};
+
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = ewrk3_get_drvinfo,
+	.get_settings = ewrk3_get_settings,
+	.set_settings = ewrk3_set_settings,
+	.get_link = ewrk3_get_link,
+	.phys_id = ewrk3_phys_id,
+};
 
 /*
    ** Perform IOCTL call functions here. Some are privileged operations and the
@@ -1708,7 +1692,7 @@ static int ewrk3_ethtool_ioctl(struct ne
  */
 static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+	struct ewrk3_private *lp = netdev_priv(dev);
 	struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_ifru;
 	u_long iobase = dev->base_addr;
 	int i, j, status = 0;
@@ -1721,11 +1705,7 @@ static int ewrk3_ioctl(struct net_device
 	
 	union ewrk3_addr *tmp;
 
-	/* ethtool IOCTLs are handled elsewhere */
-	if (cmd == SIOCETHTOOL)
-		return ewrk3_ethtool_ioctl(dev, rq->ifr_data);
-
-	/* Other than ethtool, all we handle are private IOCTLs */
+	/* All we handle are private IOCTLs */
 	if (cmd != EWRK3IOCTL)
 		return -EOPNOTSUPP;
 
diff -puN drivers/net/forcedeth.c~bk-netdev drivers/net/forcedeth.c
--- 25/drivers/net/forcedeth.c~bk-netdev	2004-09-06 18:43:15.618895952 -0700
+++ 25-akpm/drivers/net/forcedeth.c	2004-09-06 18:43:15.789869960 -0700
@@ -748,91 +748,50 @@ static struct net_device_stats *nv_get_s
 	return &np->stats;
 }
 
-static int nv_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct fe_priv *np = get_nvpriv(dev);
-	u8 *base = get_hwbase(dev);
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:
-	{
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-		strcpy(info.driver, "forcedeth");
-		strcpy(info.version, FORCEDETH_VERSION);
-		strcpy(info.bus_info, pci_name(np->pci_dev));
-		if (copy_to_user(useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GLINK:
-	{
-		struct ethtool_value edata = { ETHTOOL_GLINK };
-
-		edata.data = !!netif_carrier_ok(dev);
-
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_GWOL:
-	{
-		struct ethtool_wolinfo wolinfo;
-		memset(&wolinfo, 0, sizeof(wolinfo));
-		wolinfo.supported = WAKE_MAGIC;
-
-		spin_lock_irq(&np->lock);
-		if (np->wolenabled)
-			wolinfo.wolopts = WAKE_MAGIC;
-		spin_unlock_irq(&np->lock);
-
-		if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo)))
-			return -EFAULT;
-		return 0;
-	}
-	case ETHTOOL_SWOL:
-	{
-		struct ethtool_wolinfo wolinfo;
-		if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo)))
-			return -EFAULT;
-
-		spin_lock_irq(&np->lock);
-		if (wolinfo.wolopts == 0) {
-			writel(0, base + NvRegWakeUpFlags);
-			np->wolenabled = 0;
-		}
-		if (wolinfo.wolopts & WAKE_MAGIC) {
-			writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
-			np->wolenabled = 1;
-		}
-		spin_unlock_irq(&np->lock);
-		return 0;
-	}
+	strcpy(info->driver, "forcedeth");
+	strcpy(info->version, FORCEDETH_VERSION);
+	strcpy(info->bus_info, pci_name(np->pci_dev));
+}
 
-	default:
-		break;
-	}
+static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
+{
+	struct fe_priv *np = get_nvpriv(dev);
+	wolinfo->supported = WAKE_MAGIC;
 
-	return -EOPNOTSUPP;
+	spin_lock_irq(&np->lock);
+	if (np->wolenabled)
+		wolinfo->wolopts = WAKE_MAGIC;
+	spin_unlock_irq(&np->lock);
 }
-/*
- * nv_ioctl: dev->do_ioctl function
- * Called with rtnl_lock held.
- */
-static int nv_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+
+static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
 {
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return nv_ethtool_ioctl(dev, rq->ifr_data);
+	struct fe_priv *np = get_nvpriv(dev);
+	u8 *base = get_hwbase(dev);
 
-	default:
-		return -EOPNOTSUPP;
+	spin_lock_irq(&np->lock);
+	if (wolinfo->wolopts == 0) {
+		writel(0, base + NvRegWakeUpFlags);
+		np->wolenabled = 0;
+	}
+	if (wolinfo->wolopts & WAKE_MAGIC) {
+		writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags);
+		np->wolenabled = 1;
 	}
+	spin_unlock_irq(&np->lock);
+	return 0;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = nv_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+	.get_wol = nv_get_wol,
+	.set_wol = nv_set_wol,
+};
+
 /*
  * nv_alloc_rx: fill rx ring entries.
  * Return 1 if the allocations for the skbs failed and the
@@ -1777,7 +1736,7 @@ static int __devinit nv_probe(struct pci
 	dev->get_stats = nv_get_stats;
 	dev->change_mtu = nv_change_mtu;
 	dev->set_multicast_list = nv_set_multicast;
-	dev->do_ioctl = nv_ioctl;
+	SET_ETHTOOL_OPS(dev, &ops);
 	dev->tx_timeout = nv_tx_timeout;
 	dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
 
diff -puN drivers/net/hamachi.c~bk-netdev drivers/net/hamachi.c
--- 25/drivers/net/hamachi.c~bk-netdev	2004-09-06 18:43:15.619895800 -0700
+++ 25-akpm/drivers/net/hamachi.c	2004-09-06 18:43:15.792869504 -0700
@@ -565,7 +565,8 @@ static void hamachi_error(struct net_dev
 static int hamachi_close(struct net_device *dev);
 static struct net_device_stats *hamachi_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
-
+static struct ethtool_ops ethtool_ops;
+static struct ethtool_ops ethtool_ops_no_mii;
 
 static int __devinit hamachi_init_one (struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
@@ -631,7 +632,7 @@ static int __devinit hamachi_init_one (s
 				   read_eeprom(ioaddr, i), i % 16 != 15 ? " " : "\n");
 #endif
 
-	hmp = dev->priv;
+	hmp = netdev_priv(dev);
 	spin_lock_init(&hmp->lock);
 
 	hmp->mii_if.dev = dev;
@@ -725,6 +726,10 @@ static int __devinit hamachi_init_one (s
 	dev->get_stats = &hamachi_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &netdev_ioctl;
+	if (chip_tbl[hmp->chip_id].flags & CanHaveMII)
+		SET_ETHTOOL_OPS(dev, &ethtool_ops);
+	else
+		SET_ETHTOOL_OPS(dev, &ethtool_ops_no_mii);
 	dev->tx_timeout = &hamachi_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	if (mtu)
@@ -851,7 +856,7 @@ static void mdio_write(struct net_device
 
 static int hamachi_open(struct net_device *dev)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 	u32 rx_int_var, tx_int_var;
@@ -1000,7 +1005,7 @@ static int hamachi_open(struct net_devic
 
 static inline int hamachi_tx(struct net_device *dev)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 
 	/* Update the dirty pointer until we find an entry that is
 		still owned by the card */
@@ -1032,7 +1037,7 @@ static inline int hamachi_tx(struct net_
 static void hamachi_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 
@@ -1057,7 +1062,7 @@ static void hamachi_timer(unsigned long 
 static void hamachi_tx_timeout(struct net_device *dev)
 {
 	int i;
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Hamachi transmit timed out, status %8.8x,"
@@ -1163,7 +1168,7 @@ static void hamachi_tx_timeout(struct ne
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void hamachi_init_ring(struct net_device *dev)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	int i;
 
 	hmp->tx_full = 0;
@@ -1255,7 +1260,7 @@ do { \
 
 static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	unsigned entry;
 	u16 status;
 
@@ -1383,7 +1388,7 @@ static irqreturn_t hamachi_interrupt(int
 #endif
 
 	ioaddr = dev->base_addr;
-	hmp = dev->priv;
+	hmp = netdev_priv(dev);
 	spin_lock(&hmp->lock);
 
 	do {
@@ -1477,7 +1482,7 @@ static irqreturn_t hamachi_interrupt(int
    for clarity and better register allocation. */
 static int hamachi_rx(struct net_device *dev)
 {
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	int entry = hmp->cur_rx % RX_RING_SIZE;
 	int boguscnt = (hmp->dirty_rx + RX_RING_SIZE) - hmp->cur_rx;
 
@@ -1693,7 +1698,7 @@ static int hamachi_rx(struct net_device 
 static void hamachi_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 
 	if (intr_status & (LinkChange|NegotiationChange)) {
 		if (hamachi_debug > 1)
@@ -1727,7 +1732,7 @@ static void hamachi_error(struct net_dev
 static int hamachi_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 	struct sk_buff *skb;
 	int i;
 
@@ -1813,7 +1818,7 @@ static int hamachi_close(struct net_devi
 static struct net_device_stats *hamachi_get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct hamachi_private *hmp = dev->priv;
+	struct hamachi_private *hmp = netdev_priv(dev);
 
 	/* We should lock this segment of code for SMP eventually, although
 	   the vulnerability window is very small and statistics are
@@ -1867,84 +1872,76 @@ static void set_rx_mode(struct net_devic
 	}
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static int check_if_running(struct net_device *dev)
 {
-	struct hamachi_private *np = dev->priv;
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
+	if (!netif_running(dev))
+		return -EINVAL;
+	return 0;
+}
 
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, pci_name(np->pci_dev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
+static void hamachi_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct hamachi_private *np = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pci_dev));
+}
 
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
-			return -EINVAL;
-		spin_lock_irq(&np->lock);
-		mii_ethtool_gset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
-			return -EINVAL;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		r = mii_ethtool_sset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
-			return -EINVAL;
-		return mii_nway_restart(&np->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		if (!(chip_tbl[np->chip_id].flags & CanHaveMII))
-			return -EINVAL;
-		edata.data = mii_link_ok(&np->mii_if);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-        }
-	
-	return -EOPNOTSUPP;
+static int hamachi_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct hamachi_private *np = netdev_priv(dev);
+	spin_lock_irq(&np->lock);
+	mii_ethtool_gset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	return 0;
+}
+
+static int hamachi_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct hamachi_private *np = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&np->lock);
+	res = mii_ethtool_sset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	return res;
+}
+
+static int hamachi_nway_reset(struct net_device *dev)
+{
+	struct hamachi_private *np = netdev_priv(dev);
+	return mii_nway_restart(&np->mii_if);
 }
 
+static u32 hamachi_get_link(struct net_device *dev)
+{
+	struct hamachi_private *np = netdev_priv(dev);
+	return mii_link_ok(&np->mii_if);
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.begin = check_if_running,
+	.get_drvinfo = hamachi_get_drvinfo,
+	.get_settings = hamachi_get_settings,
+	.set_settings = hamachi_set_settings,
+	.nway_reset = hamachi_nway_reset,
+	.get_link = hamachi_get_link,
+};
+
+static struct ethtool_ops ethtool_ops_no_mii = {
+	.begin = check_if_running,
+	.get_drvinfo = hamachi_get_drvinfo,
+};
+
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct hamachi_private *np = dev->priv;
+	struct hamachi_private *np = netdev_priv(dev);
 	struct mii_ioctl_data *data = if_mii(rq);
 	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd == SIOCETHTOOL)
-		rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
-
-	else if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
+	if (cmd == (SIOCDEVPRIVATE+3)) { /* set rx,tx intr params */
 		u32 *d = (u32 *)&rq->ifr_ifru;
 		/* Should add this check here or an ordinary user can do nasty
 		 * things. -KDU
@@ -1976,7 +1973,7 @@ static void __devexit hamachi_remove_one
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct hamachi_private *hmp = dev->priv;
+		struct hamachi_private *hmp = netdev_priv(dev);
 
 		pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring, 
 			hmp->rx_ring_dma);
diff -puN drivers/net/ibmlana.c~bk-netdev drivers/net/ibmlana.c
--- 25/drivers/net/ibmlana.c~bk-netdev	2004-09-06 18:43:15.621895496 -0700
+++ 25-akpm/drivers/net/ibmlana.c	2004-09-06 18:43:15.793869352 -0700
@@ -885,14 +885,6 @@ static struct net_device_stats *ibmlana_
 	return &priv->stat;
 }
 
-/* we don't support runtime reconfiguration, since am MCA card can
-   be unambigously identified by its POS registers. */
-
-static int ibmlana_config(struct net_device *dev, struct ifmap *map)
-{
-	return 0;
-}
-
 /* switch receiver mode. */
 
 static void ibmlana_set_multicast_list(struct net_device *dev)
@@ -984,7 +976,6 @@ static int ibmlana_probe(struct net_devi
 
 	dev->open = ibmlana_open;
 	dev->stop = ibmlana_close;
-	dev->set_config = ibmlana_config;
 	dev->hard_start_xmit = ibmlana_tx;
 	dev->do_ioctl = NULL;
 	dev->get_stats = ibmlana_stats;
diff -puN drivers/net/iseries_veth.c~bk-netdev drivers/net/iseries_veth.c
--- 25/drivers/net/iseries_veth.c~bk-netdev	2004-09-06 18:43:15.622895344 -0700
+++ 25-akpm/drivers/net/iseries_veth.c	2004-09-06 18:43:15.795869048 -0700
@@ -747,60 +747,41 @@ static void veth_set_multicast_list(stru
 	write_unlock_irqrestore(&port->mcast_gate, flags);
 }
 
-static int veth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-#ifdef SIOCETHTOOL
-	struct ethtool_cmd ecmd;
-
-	if (cmd != SIOCETHTOOL)
-		return -EOPNOTSUPP;
-	if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd)))
-		return -EFAULT;
-	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported = (SUPPORTED_1000baseT_Full
-				  | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
-		ecmd.advertising = (SUPPORTED_1000baseT_Full
-				    | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
-
-		ecmd.port = PORT_FIBRE;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = 0;
-		ecmd.speed = SPEED_1000;
-		ecmd.duplex = DUPLEX_FULL;
-		ecmd.autoneg = AUTONEG_ENABLE;
-		ecmd.maxtxpkt = 120;
-		ecmd.maxrxpkt = 120;
-		if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strncpy(info.driver, "veth", sizeof(info.driver) - 1);
-			info.driver[sizeof(info.driver) - 1] = '\0';
-			strncpy(info.version, "1.0", sizeof(info.version) - 1);
-			if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
-		/* get link status */
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-			edata.data = 1;
-			if (copy_to_user(ifr->ifr_data, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-
-	default:
-		break;
-	}
+	strncpy(info->driver, "veth", sizeof(info->driver) - 1);
+	info->driver[sizeof(info->driver) - 1] = '\0';
+	strncpy(info->version, "1.0", sizeof(info->version) - 1);
+}
+
+static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	ecmd->supported = (SUPPORTED_1000baseT_Full
+			  | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+	ecmd->advertising = (SUPPORTED_1000baseT_Full
+			    | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+	ecmd->port = PORT_FIBRE;
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = 0;
+	ecmd->speed = SPEED_1000;
+	ecmd->duplex = DUPLEX_FULL;
+	ecmd->autoneg = AUTONEG_ENABLE;
+	ecmd->maxtxpkt = 120;
+	ecmd->maxrxpkt = 120;
+	return 0;
+}
 
-#endif
-	return -EOPNOTSUPP;
+static u32 veth_get_link(struct net_device *dev)
+{
+	return 1;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = veth_get_drvinfo,
+	.get_settings = veth_get_settings,
+	.get_link = veth_get_link,
+};
+
 static void veth_tx_timeout(struct net_device *dev)
 {
 	struct veth_port *port = (struct veth_port *)dev->priv;
@@ -889,7 +870,7 @@ static struct net_device * __init veth_p
 	dev->change_mtu = veth_change_mtu;
 	dev->set_mac_address = NULL;
 	dev->set_multicast_list = veth_set_multicast_list;
-	dev->do_ioctl = veth_ioctl;
+	SET_ETHTOOL_OPS(dev, &ops);
 
 	dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000);
 	dev->tx_timeout = veth_tx_timeout;
diff -puN drivers/net/ixgb/ixgb_ethtool.c~bk-netdev drivers/net/ixgb/ixgb_ethtool.c
--- 25/drivers/net/ixgb/ixgb_ethtool.c~bk-netdev	2004-09-06 18:43:15.624895040 -0700
+++ 25-akpm/drivers/net/ixgb/ixgb_ethtool.c	2004-09-06 18:43:15.798868592 -0700
@@ -38,12 +38,6 @@ extern char ixgb_driver_version[];
 extern int ixgb_up(struct ixgb_adapter *adapter);
 extern void ixgb_down(struct ixgb_adapter *adapter, boolean_t kill_watchdog);
 
-static inline int ixgb_eeprom_size(struct ixgb_hw *hw)
-{
-	/* return size in bytes */
-	return (IXGB_EEPROM_SIZE << 1);
-}
-
 struct ixgb_stats {
 	char stat_string[ETH_GSTRING_LEN];
 	int sizeof_stat;
@@ -94,9 +88,10 @@ static struct ixgb_stats ixgb_gstrings_s
 #define IXGB_STATS_LEN	\
 	sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats)
 
-static void
-ixgb_ethtool_gset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd)
+static int
+ixgb_ethtool_gset(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
+	struct ixgb_adapter *adapter = netdev->priv;
 	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	ecmd->port = PORT_FIBRE;
@@ -111,11 +106,13 @@ ixgb_ethtool_gset(struct ixgb_adapter *a
 	}
 
 	ecmd->autoneg = AUTONEG_DISABLE;
+	return 0;
 }
 
 static int
-ixgb_ethtool_sset(struct ixgb_adapter *adapter, struct ethtool_cmd *ecmd)
+ixgb_ethtool_sset(struct net_device *netdev, struct ethtool_cmd *ecmd)
 {
+	struct ixgb_adapter *adapter = netdev->priv;
 	if (ecmd->autoneg == AUTONEG_ENABLE ||
 	    ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
 		return -EINVAL;
@@ -123,14 +120,14 @@ ixgb_ethtool_sset(struct ixgb_adapter *a
 		ixgb_down(adapter, TRUE);
 		ixgb_up(adapter);
 	}
-
 	return 0;
 }
 
-static int
-ixgb_ethtool_gpause(struct ixgb_adapter *adapter,
+static void
+ixgb_ethtool_gpause(struct net_device *dev,
 		    struct ethtool_pauseparam *epause)
 {
+	struct ixgb_adapter *adapter = dev->priv;
 	struct ixgb_hw *hw = &adapter->hw;
 
 	epause->autoneg = AUTONEG_DISABLE;
@@ -143,14 +140,13 @@ ixgb_ethtool_gpause(struct ixgb_adapter 
 		epause->rx_pause = 1;
 		epause->tx_pause = 1;
 	}
-
-	return 0;
 }
 
 static int
-ixgb_ethtool_spause(struct ixgb_adapter *adapter,
+ixgb_ethtool_spause(struct net_device *dev,
 		    struct ethtool_pauseparam *epause)
 {
+	struct ixgb_adapter *adapter = dev->priv;
 	struct ixgb_hw *hw = &adapter->hw;
 
 	if (epause->autoneg == AUTONEG_ENABLE)
@@ -172,26 +168,23 @@ ixgb_ethtool_spause(struct ixgb_adapter 
 }
 
 static void
-ixgb_ethtool_gdrvinfo(struct ixgb_adapter *adapter,
+ixgb_ethtool_gdrvinfo(struct net_device *netdev,
 		      struct ethtool_drvinfo *drvinfo)
 {
+	struct ixgb_adapter *adapter = netdev->priv;
 	strncpy(drvinfo->driver, ixgb_driver_name, 32);
 	strncpy(drvinfo->version, ixgb_driver_version, 32);
 	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-	drvinfo->n_stats = IXGB_STATS_LEN;
-#define IXGB_REG_DUMP_LEN  136*sizeof(uint32_t)
-	drvinfo->regdump_len = IXGB_REG_DUMP_LEN;
-	drvinfo->eedump_len = ixgb_eeprom_size(&adapter->hw);
 }
 
 #define IXGB_GET_STAT(_A_, _R_) _A_->stats._R_
 static void
-ixgb_ethtool_gregs(struct ixgb_adapter *adapter,
-		   struct ethtool_regs *regs, uint32_t * regs_buff)
+ixgb_ethtool_gregs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
 {
+	struct ixgb_adapter *adapter = dev->priv;
 	struct ixgb_hw *hw = &adapter->hw;
-	uint32_t *reg = regs_buff;
+	uint32_t *reg = buf;
 	uint32_t *reg_start = reg;
 	uint8_t i;
 
@@ -323,69 +316,37 @@ ixgb_ethtool_gregs(struct ixgb_adapter *
 }
 
 static int
-ixgb_ethtool_geeprom(struct ixgb_adapter *adapter,
-		     struct ethtool_eeprom *eeprom, uint16_t * eeprom_buff)
+ixgb_ethtool_geeprom(struct net_device *dev,
+		     struct ethtool_eeprom *eeprom, u8 *data)
 {
+	struct ixgb_adapter *adapter = dev->priv;
 	struct ixgb_hw *hw = &adapter->hw;
-	int i, max_len, first_word, last_word;
-	int ret_val = 0;
-
-	if (eeprom->len == 0) {
-		ret_val = -EINVAL;
-		goto geeprom_error;
-	}
 
 	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
 
-	max_len = ixgb_eeprom_size(hw);
-
 	/* use our function to read the eeprom and update our cache */
 	ixgb_get_eeprom_data(hw);
-
-	if (eeprom->offset > eeprom->offset + eeprom->len) {
-		ret_val = -EINVAL;
-		goto geeprom_error;
-	}
-
-	if ((eeprom->offset + eeprom->len) > max_len)
-		eeprom->len = (max_len - eeprom->offset);
-
-	first_word = eeprom->offset >> 1;
-	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
-
-	for (i = 0; i <= (last_word - first_word); i++) {
-		eeprom_buff[i] = hw->eeprom[first_word + i];
-	}
-      geeprom_error:
-	return ret_val;
+	memcpy(data, (char *)hw->eeprom + eeprom->offset, eeprom->len);
+	return 0;
 }
 
 static int
-ixgb_ethtool_seeprom(struct ixgb_adapter *adapter,
-		     struct ethtool_eeprom *eeprom, void __user *user_data)
+ixgb_ethtool_seeprom(struct net_device *dev,
+		     struct ethtool_eeprom *eeprom, u8 *data)
 {
+	struct ixgb_adapter *adapter = dev->priv;
 	struct ixgb_hw *hw = &adapter->hw;
-	uint16_t eeprom_buff[256];
-	int i, max_len, first_word, last_word;
-	void *ptr;
+	/* We are under rtnl, so static is OK */
+	static uint16_t eeprom_buff[IXGB_EEPROM_SIZE];
+	int i, first_word, last_word;
+	char *ptr;
 
 	if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
 		return -EFAULT;
 
-	if (eeprom->len == 0)
-		return -EINVAL;
-
-	max_len = ixgb_eeprom_size(hw);
-
-	if (eeprom->offset > eeprom->offset + eeprom->len)
-		return -EINVAL;
-
-	if ((eeprom->offset + eeprom->len) > max_len)
-		eeprom->len = (max_len - eeprom->offset);
-
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
-	ptr = (void *)eeprom_buff;
+	ptr = (char *)eeprom_buff;
 
 	if (eeprom->offset & 1) {
 		/* need read/modify/write of first changed EEPROM word */
@@ -399,8 +360,7 @@ ixgb_ethtool_seeprom(struct ixgb_adapter
 		eeprom_buff[last_word - first_word]
 		    = ixgb_read_eeprom(hw, last_word);
 	}
-	if (copy_from_user(ptr, user_data, eeprom->len))
-		return -EFAULT;
+	memcpy(ptr, data, eeprom->len);
 
 	for (i = 0; i <= (last_word - first_word); i++)
 		ixgb_write_eeprom(hw, first_word + i, eeprom_buff[i]);
@@ -431,8 +391,9 @@ static void ixgb_led_blink_callback(unsi
 }
 
 static int
-ixgb_ethtool_led_blink(struct ixgb_adapter *adapter, struct ethtool_value *id)
+ixgb_ethtool_led_blink(struct net_device *netdev, u32 data)
 {
+	struct ixgb_adapter *adapter = netdev->priv;
 	if (!adapter->blink_timer.function) {
 		init_timer(&adapter->blink_timer);
 		adapter->blink_timer.function = ixgb_led_blink_callback;
@@ -442,8 +403,8 @@ ixgb_ethtool_led_blink(struct ixgb_adapt
 	mod_timer(&adapter->blink_timer, jiffies);
 
 	set_current_state(TASK_INTERRUPTIBLE);
-	if (id->data)
-		schedule_timeout(id->data * HZ);
+	if (data)
+		schedule_timeout(data * HZ);
 	else
 		schedule_timeout(MAX_SCHEDULE_TIMEOUT);
 
@@ -454,268 +415,141 @@ ixgb_ethtool_led_blink(struct ixgb_adapt
 	return 0;
 }
 
-int ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
+static int ixgb_nway_reset(struct net_device *netdev)
 {
-	struct ixgb_adapter *adapter = netdev->priv;
-	void __user *addr = ifr->ifr_data;
-	uint32_t cmd;
+	if (netif_running(netdev)) {
+		struct ixgb_adapter *adapter = netdev->priv;
+		ixgb_down(adapter, TRUE);
+		ixgb_up(adapter);
+	}
+	return 0;
+}
 
-	if (get_user(cmd, (uint32_t __user *) addr))
-		return -EFAULT;
+static int ixgb_get_stats_count(struct net_device *dev)
+{
+	return IXGB_STATS_LEN;
+}
 
-	switch (cmd) {
-	case ETHTOOL_GSET:{
-			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-			ixgb_ethtool_gset(adapter, &ecmd);
-			if (copy_to_user(addr, &ecmd, sizeof(ecmd)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SSET:{
-			struct ethtool_cmd ecmd;
-			if (copy_from_user(&ecmd, addr, sizeof(ecmd)))
-				return -EFAULT;
-			return ixgb_ethtool_sset(adapter, &ecmd);
-		}
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo drvinfo = { ETHTOOL_GDRVINFO };
-			ixgb_ethtool_gdrvinfo(adapter, &drvinfo);
-			if (copy_to_user(addr, &drvinfo, sizeof(drvinfo)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GSTRINGS:{
-			struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
-			char *strings = NULL;
-			int err = 0;
-
-			if (copy_from_user(&gstrings, addr, sizeof(gstrings)))
-				return -EFAULT;
-			switch (gstrings.string_set) {
-			case ETH_SS_STATS:{
-					int i;
-					gstrings.len = IXGB_STATS_LEN;
-					strings =
-					    kmalloc(IXGB_STATS_LEN *
-						    ETH_GSTRING_LEN,
-						    GFP_KERNEL);
-					if (!strings)
-						return -ENOMEM;
-					for (i = 0; i < IXGB_STATS_LEN; i++) {
-						memcpy(&strings
-						       [i * ETH_GSTRING_LEN],
-						       ixgb_gstrings_stats[i].
-						       stat_string,
-						       ETH_GSTRING_LEN);
-					}
-					break;
-				}
-			default:
-				return -EOPNOTSUPP;
-			}
-			if (copy_to_user(addr, &gstrings, sizeof(gstrings)))
-				err = -EFAULT;
-			addr += offsetof(struct ethtool_gstrings, data);
-			if (!err && copy_to_user(addr, strings,
-						 gstrings.len *
-						 ETH_GSTRING_LEN))
-				err = -EFAULT;
-
-			kfree(strings);
-			return err;
-		}
-	case ETHTOOL_GREGS:{
-			struct ethtool_regs regs = { ETHTOOL_GREGS };
-			uint32_t regs_buff[IXGB_REG_DUMP_LEN];
-
-			if (copy_from_user(&regs, addr, sizeof(regs)))
-				return -EFAULT;
-			ixgb_ethtool_gregs(adapter, &regs, regs_buff);
-			if (copy_to_user(addr, &regs, sizeof(regs)))
-				return -EFAULT;
-
-			addr += offsetof(struct ethtool_regs, data);
-			if (copy_to_user(addr, regs_buff, regs.len))
-				return -EFAULT;
-
-			return 0;
-		}
-	case ETHTOOL_NWAY_RST:{
-			if (netif_running(netdev)) {
-				ixgb_down(adapter, TRUE);
-				ixgb_up(adapter);
-			}
-			return 0;
-		}
-	case ETHTOOL_PHYS_ID:{
-			struct ethtool_value id;
-			if (copy_from_user(&id, addr, sizeof(id)))
-				return -EFAULT;
-			return ixgb_ethtool_led_blink(adapter, &id);
-		}
-	case ETHTOOL_GLINK:{
-			struct ethtool_value link = { ETHTOOL_GLINK };
-			link.data = netif_carrier_ok(netdev);
-			if (copy_to_user(addr, &link, sizeof(link)))
-				return -EFAULT;
-			return 0;
-		}
-
-	case ETHTOOL_GEEPROM:{
-			struct ethtool_eeprom eeprom = { ETHTOOL_GEEPROM };
-			uint16_t eeprom_buff[IXGB_EEPROM_SIZE];
-			void *ptr;
-			int err = 0;
-
-			if (copy_from_user(&eeprom, addr, sizeof(eeprom)))
-				return -EFAULT;
-
-			if ((err =
-			     ixgb_ethtool_geeprom(adapter, &eeprom,
-						  eeprom_buff)) < 0)
-				return err;
-
-			if (copy_to_user(addr, &eeprom, sizeof(eeprom)))
-				return -EFAULT;
-
-			addr += offsetof(struct ethtool_eeprom, data);
-			ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
-
-			if (copy_to_user(addr, ptr, eeprom.len))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SEEPROM:{
-			struct ethtool_eeprom eeprom;
-
-			if (copy_from_user(&eeprom, addr, sizeof(eeprom)))
-				return -EFAULT;
-
-			addr += offsetof(struct ethtool_eeprom, data);
-			return ixgb_ethtool_seeprom(adapter, &eeprom, addr);
-		}
-	case ETHTOOL_GPAUSEPARAM:{
-			struct ethtool_pauseparam epause =
-			    { ETHTOOL_GPAUSEPARAM };
-			ixgb_ethtool_gpause(adapter, &epause);
-			if (copy_to_user(addr, &epause, sizeof(epause)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SPAUSEPARAM:{
-			struct ethtool_pauseparam epause;
-			if (copy_from_user(&epause, addr, sizeof(epause)))
-				return -EFAULT;
-			return ixgb_ethtool_spause(adapter, &epause);
-		}
-	case ETHTOOL_GSTATS:{
-			struct {
-				struct ethtool_stats eth_stats;
-				uint64_t data[IXGB_STATS_LEN];
-			} stats = { {
-			ETHTOOL_GSTATS, IXGB_STATS_LEN}};
-			int i;
-
-			for (i = 0; i < IXGB_STATS_LEN; i++)
-				stats.data[i] =
-				    (ixgb_gstrings_stats[i].sizeof_stat ==
-				     sizeof(uint64_t)) ? *(uint64_t *) ((char *)
-									adapter
-									+
-									ixgb_gstrings_stats
-									[i].
-									stat_offset)
-				    : *(uint32_t *) ((char *)adapter +
-						     ixgb_gstrings_stats[i].
-						     stat_offset);
-			if (copy_to_user(addr, &stats, sizeof(stats)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GRXCSUM:{
-			struct ethtool_value edata = { ETHTOOL_GRXCSUM };
-
-			edata.data = adapter->rx_csum;
-			if (copy_to_user(addr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SRXCSUM:{
-			struct ethtool_value edata;
-
-			if (copy_from_user(&edata, addr, sizeof(edata)))
-				return -EFAULT;
-			adapter->rx_csum = edata.data;
-			ixgb_down(adapter, TRUE);
-			ixgb_up(adapter);
-			return 0;
-		}
-	case ETHTOOL_GTXCSUM:{
-			struct ethtool_value edata = { ETHTOOL_GTXCSUM };
-
-			edata.data = (netdev->features & NETIF_F_HW_CSUM) != 0;
-			if (copy_to_user(addr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_STXCSUM:{
-			struct ethtool_value edata;
-
-			if (copy_from_user(&edata, addr, sizeof(edata)))
-				return -EFAULT;
-
-			if (edata.data)
-				netdev->features |= NETIF_F_HW_CSUM;
-			else
-				netdev->features &= ~NETIF_F_HW_CSUM;
-
-			return 0;
-		}
-	case ETHTOOL_GSG:{
-			struct ethtool_value edata = { ETHTOOL_GSG };
-
-			edata.data = (netdev->features & NETIF_F_SG) != 0;
-			if (copy_to_user(addr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SSG:{
-			struct ethtool_value edata;
-
-			if (copy_from_user(&edata, addr, sizeof(edata)))
-				return -EFAULT;
-
-			if (edata.data)
-				netdev->features |= NETIF_F_SG;
-			else
-				netdev->features &= ~NETIF_F_SG;
+static void ixgb_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+	for (i = 0; i < IXGB_STATS_LEN; i++) {
+		memcpy(data + i * ETH_GSTRING_LEN,
+		       ixgb_gstrings_stats[i].stat_string,
+		       ETH_GSTRING_LEN);
+	}
+}
 
-			return 0;
-		}
-#ifdef NETIF_F_TSO
-	case ETHTOOL_GTSO:{
-			struct ethtool_value edata = { ETHTOOL_GTSO };
+static int ixgb_get_regs_len(struct net_device *dev)
+{
+	return 136*sizeof(uint32_t);
+}
+
+static int ixgb_get_eeprom_len(struct net_device *dev)
+{
+	/* return size in bytes */
+	return (IXGB_EEPROM_SIZE << 1);
+}
 
-			edata.data = (netdev->features & NETIF_F_TSO) != 0;
-			if (copy_to_user(addr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_STSO:{
-			struct ethtool_value edata;
-
-			if (copy_from_user(&edata, addr, sizeof(edata)))
-				return -EFAULT;
-
-			if (edata.data)
-				netdev->features |= NETIF_F_TSO;
-			else
-				netdev->features &= ~NETIF_F_TSO;
+static void get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+	struct ixgb_adapter *adapter = dev->priv;
+	int i;
 
-			return 0;
-		}
-#endif
-	default:
-		return -EOPNOTSUPP;
+	for (i = 0; i < IXGB_STATS_LEN; i++) {
+		void *p = (char *)adapter + ixgb_gstrings_stats[i].stat_offset;
+		stats->data[i] =
+		    (ixgb_gstrings_stats[i].sizeof_stat == sizeof(uint64_t))
+		    ? *(uint64_t *) p
+		    : *(uint32_t *) p;
 	}
 }
+
+static u32 ixgb_get_rx_csum(struct net_device *dev)
+{
+	struct ixgb_adapter *adapter = dev->priv;
+	return adapter->rx_csum;
+}
+
+static int ixgb_set_rx_csum(struct net_device *dev, u32 sum)
+{
+	struct ixgb_adapter *adapter = dev->priv;
+	adapter->rx_csum = sum;
+	ixgb_down(adapter, TRUE);
+	ixgb_up(adapter);
+	return 0;
+}
+
+static u32 ixgb_get_tx_csum(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int ixgb_set_tx_csum(struct net_device *dev, u32 sum)
+{
+	if (sum)
+		dev->features |= NETIF_F_HW_CSUM;
+	else
+		dev->features &= ~NETIF_F_HW_CSUM;
+	return 0;
+}
+
+static u32 ixgb_get_sg(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_SG) != 0;
+}
+
+static int ixgb_set_sg(struct net_device *dev, u32 sum)
+{
+	if (sum)
+		dev->features |= NETIF_F_SG;
+	else
+		dev->features &= ~NETIF_F_SG;
+	return 0;
+}
+
+#ifdef NETIF_F_TSO
+static u32 ixgb_get_tso(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_TSO) != 0;
+}
+
+static int ixgb_set_tso(struct net_device *dev, u32 sum)
+{
+	if (sum)
+		dev->features |= NETIF_F_TSO;
+	else
+		dev->features &= ~NETIF_F_TSO;
+	return 0;
+}
+#endif
+
+struct ethtool_ops ixgb_ethtool_ops = {
+	.get_settings = ixgb_ethtool_gset,
+	.set_settings = ixgb_ethtool_sset,
+	.get_drvinfo = ixgb_ethtool_gdrvinfo,
+	.nway_reset = ixgb_nway_reset,
+	.get_link = ethtool_op_get_link,
+	.phys_id = ixgb_ethtool_led_blink,
+	.get_strings = ixgb_get_strings,
+	.get_stats_count = ixgb_get_stats_count,
+	.get_regs = ixgb_ethtool_gregs,
+	.get_regs_len = ixgb_get_regs_len,
+	.get_eeprom_len = ixgb_get_eeprom_len,
+	.get_eeprom = ixgb_ethtool_geeprom,
+	.set_eeprom = ixgb_ethtool_seeprom,
+	.get_pauseparam = ixgb_ethtool_gpause,
+	.set_pauseparam = ixgb_ethtool_spause,
+	.get_ethtool_stats = get_ethtool_stats,
+	.get_rx_csum = ixgb_get_rx_csum,
+	.set_rx_csum = ixgb_set_rx_csum,
+	.get_tx_csum = ixgb_get_tx_csum,
+	.set_tx_csum = ixgb_set_tx_csum,
+	.get_sg = ixgb_get_sg,
+	.set_sg = ixgb_set_sg,
+#ifdef NETIF_F_TSO
+	.get_tso = ixgb_get_tso,
+	.set_tso = ixgb_set_tso,
+#endif
+};
diff -puN drivers/net/ixgb/ixgb_main.c~bk-netdev drivers/net/ixgb/ixgb_main.c
--- 25/drivers/net/ixgb/ixgb_main.c~bk-netdev	2004-09-06 18:43:15.625894888 -0700
+++ 25-akpm/drivers/net/ixgb/ixgb_main.c	2004-09-06 18:43:15.800868288 -0700
@@ -97,7 +97,6 @@ static boolean_t ixgb_clean_rx_irq(struc
 static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter);
 #endif
 static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter);
-static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
 static void ixgb_tx_timeout(struct net_device *dev);
 static void ixgb_tx_timeout_task(struct net_device *dev);
 static void ixgb_vlan_rx_register(struct net_device *netdev,
@@ -124,7 +123,7 @@ struct notifier_block ixgb_notifier_rebo
 /* Exported from other modules */
 
 extern void ixgb_check_options(struct ixgb_adapter *adapter);
-extern int ixgb_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
+extern struct ethtool_ops ixgb_ethtool_ops;
 
 static struct pci_driver ixgb_driver = {
 	.name = ixgb_driver_name,
@@ -372,9 +371,9 @@ ixgb_probe(struct pci_dev *pdev, const s
 	netdev->set_multicast_list = &ixgb_set_multi;
 	netdev->set_mac_address = &ixgb_set_mac;
 	netdev->change_mtu = &ixgb_change_mtu;
-	netdev->do_ioctl = &ixgb_ioctl;
 	netdev->tx_timeout = &ixgb_tx_timeout;
 	netdev->watchdog_timeo = HZ;
+	SET_ETHTOOL_OPS(netdev, &ixgb_ethtool_ops);
 #ifdef CONFIG_IXGB_NAPI
 	netdev->poll = &ixgb_clean;
 	netdev->weight = 64;
@@ -1970,25 +1969,6 @@ static void ixgb_alloc_rx_buffers(struct
 }
 
 /**
- * ixgb_ioctl - perform a command - e.g: ethtool:get_driver_info.
- * @param netdev network interface device structure
- * @param ifr data to be used/filled in by the ioctl command
- * @param cmd ioctl command to execute
- **/
-
-static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
-{
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return ixgb_ethtool_ioctl(netdev, ifr);
-	default:
-		return -EOPNOTSUPP;
-	}
-
-	return 0;
-}
-
-/**
  * ixgb_vlan_rx_register - enables or disables vlan tagging/stripping.
  * 
  * @param netdev network interface device structure
diff -puN drivers/net/Kconfig~bk-netdev drivers/net/Kconfig
--- 25/drivers/net/Kconfig~bk-netdev	2004-09-06 18:43:15.627894584 -0700
+++ 25-akpm/drivers/net/Kconfig	2004-09-06 18:43:15.768873152 -0700
@@ -2061,6 +2061,15 @@ config R8169_NAPI
 
 	  If in doubt, say N.
 
+config R8169_VLAN
+	bool "VLAN support"
+	depends on R8169 && VLAN_8021Q
+	---help---
+	  Say Y here for the r8169 driver to support the functions required
+	  by the kernel 802.1Q code.
+	  
+	  If in doubt, say Y.
+
 config SK98LIN
 	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support"
 	depends on PCI
diff -puN drivers/net/mac8390.c~bk-netdev drivers/net/mac8390.c
--- 25/drivers/net/mac8390.c~bk-netdev	2004-09-06 18:43:15.629894280 -0700
+++ 25-akpm/drivers/net/mac8390.c	2004-09-06 18:43:15.800868288 -0700
@@ -42,10 +42,6 @@
 
 #include "8390.h"
 
-#if (LINUX_VERSION_CODE < 0x02030e)
-#define net_device device
-#endif
-
 #define WD_START_PG			0x00	/* First page of TX buffer */
 #define CABLETRON_RX_START_PG		0x00    /* First page of RX buffer */
 #define CABLETRON_RX_STOP_PG		0x30    /* Last page +1 of RX ring */
diff -puN drivers/net/meth.c~bk-netdev drivers/net/meth.c
--- 25/drivers/net/meth.c~bk-netdev	2004-09-06 18:43:15.630894128 -0700
+++ 25-akpm/drivers/net/meth.c	2004-09-06 18:43:15.801868136 -0700
@@ -368,31 +368,6 @@ static int meth_release(struct net_devic
 }
 
 /*
- * Configuration changes (passed on by ifconfig)
- */
-static int meth_config(struct net_device *dev, struct ifmap *map)
-{
-	if (dev->flags & IFF_UP) /* can't act on a running interface */
-		return -EBUSY;
-
-	/* Don't allow changing the I/O address */
-	if (map->base_addr != dev->base_addr) {
-		printk(KERN_WARNING "meth: Can't change I/O address\n");
-		return -EOPNOTSUPP;
-	}
-
-	/* Don't allow changing the IRQ */
-	if (map->irq != dev->irq) {
-		printk(KERN_WARNING "meth: Can't change IRQ\n");
-		return -EOPNOTSUPP;
-	}
-	DPRINTK("Configured\n");
-
-	/* ignore other fields */
-	return 0;
-}
-
-/*
  * Receive a packet: retrieve, encapsulate and pass over to upper levels
  */
 static void meth_rx(struct net_device* dev, unsigned long int_status)
@@ -813,7 +788,6 @@ static struct net_device *meth_init(void
 
 	dev->open            = meth_open;
 	dev->stop            = meth_release;
-	dev->set_config      = meth_config;
 	dev->hard_start_xmit = meth_tx;
 	dev->do_ioctl        = meth_ioctl;
 	dev->get_stats       = meth_stats;
diff -puN drivers/net/natsemi.c~bk-netdev drivers/net/natsemi.c
--- 25/drivers/net/natsemi.c~bk-netdev	2004-09-06 18:43:15.632893824 -0700
+++ 25-akpm/drivers/net/natsemi.c	2004-09-06 18:43:15.805867528 -0700
@@ -768,6 +768,7 @@ static void enable_wol_mode(struct net_d
 static int netdev_close(struct net_device *dev);
 static int netdev_get_regs(struct net_device *dev, u8 *buf);
 static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
+static struct ethtool_ops ethtool_ops;
 
 static void move_int_phy(struct net_device *dev, int addr)
 {
@@ -926,6 +927,7 @@ static int __devinit natsemi_probe1 (str
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &natsemi_poll_controller;
 #endif
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
 	if (mtu)
 		dev->mtu = mtu;
@@ -2457,177 +2459,136 @@ static void set_rx_mode(struct net_devic
 	spin_unlock_irq(&np->lock);
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct netdev_private *np = netdev_priv(dev);
-	u32 cmd;
-
-	if (get_user(cmd, (u32 __user *)useraddr))
-		return -EFAULT;
-
-	switch (cmd) {
-	/* get driver info */
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strncpy(info.driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
-		info.fw_version[0] = '\0';
-		strncpy(info.bus_info, pci_name(np->pci_dev),
-			ETHTOOL_BUSINFO_LEN);
-		info.eedump_len = NATSEMI_EEPROM_SIZE;
-		info.regdump_len = NATSEMI_REGS_SIZE;
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&np->lock);
-		netdev_get_ecmd(dev, &ecmd);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		struct ethtool_cmd ecmd;
-		int r;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		r = netdev_set_ecmd(dev, &ecmd);
-		spin_unlock_irq(&np->lock);
-		return r;
-	}
-	/* get wake-on-lan */
-	case ETHTOOL_GWOL: {
-		struct ethtool_wolinfo wol = {ETHTOOL_GWOL};
-		spin_lock_irq(&np->lock);
-		netdev_get_wol(dev, &wol.supported, &wol.wolopts);
-		netdev_get_sopass(dev, wol.sopass);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &wol, sizeof(wol)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set wake-on-lan */
-	case ETHTOOL_SWOL: {
-		struct ethtool_wolinfo wol;
-		int r;
-		if (copy_from_user(&wol, useraddr, sizeof(wol)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		netdev_set_wol(dev, wol.wolopts);
-		r = netdev_set_sopass(dev, wol.sopass);
-		spin_unlock_irq(&np->lock);
-		return r;
-	}
-	/* get registers */
-	case ETHTOOL_GREGS: {
-		struct ethtool_regs regs;
-		u8 regbuf[NATSEMI_REGS_SIZE];
-		int r;
-
-		if (copy_from_user(&regs, useraddr, sizeof(regs)))
-			return -EFAULT;
-
-		if (regs.len > NATSEMI_REGS_SIZE) {
-			regs.len = NATSEMI_REGS_SIZE;
-		}
-		regs.version = NATSEMI_REGS_VER;
-		if (copy_to_user(useraddr, &regs, sizeof(regs)))
-			return -EFAULT;
+	strncpy(info->driver, DRV_NAME, ETHTOOL_BUSINFO_LEN);
+	strncpy(info->version, DRV_VERSION, ETHTOOL_BUSINFO_LEN);
+	strncpy(info->bus_info, pci_name(np->pci_dev), ETHTOOL_BUSINFO_LEN);
+}
 
-		useraddr += offsetof(struct ethtool_regs, data);
+static int get_regs_len(struct net_device *dev)
+{
+	return NATSEMI_REGS_SIZE;
+}
 
-		spin_lock_irq(&np->lock);
-		r = netdev_get_regs(dev, regbuf);
-		spin_unlock_irq(&np->lock);
+static int get_eeprom_len(struct net_device *dev)
+{
+	return NATSEMI_EEPROM_SIZE;
+}
 
-		if (r)
-			return r;
-		if (copy_to_user(useraddr, regbuf, regs.len))
-			return -EFAULT;
-		return 0;
-	}
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = np->msg_enable;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		np->msg_enable = edata.data;
-		return 0;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		int tmp;
-		int r = -EINVAL;
-		/* if autoneg is off, it's an error */
-		tmp = mdio_read(dev, MII_BMCR);
-		if (tmp & BMCR_ANENABLE) {
-			tmp |= (BMCR_ANRESTART);
-			mdio_write(dev, MII_BMCR, tmp);
-			r = 0;
-		}
-		return r;
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		/* LSTATUS is latched low until a read - so read twice */
-		mdio_read(dev, MII_BMSR);
-		edata.data = (mdio_read(dev, MII_BMSR)&BMSR_LSTATUS) ? 1:0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* get EEPROM */
-	case ETHTOOL_GEEPROM: {
-		struct ethtool_eeprom eeprom;
-		u8 eebuf[NATSEMI_EEPROM_SIZE];
-		int r;
+static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	spin_lock_irq(&np->lock);
+	netdev_get_ecmd(dev, ecmd);
+	spin_unlock_irq(&np->lock);
+	return 0;
+}
 
-		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
-			return -EFAULT;
+static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&np->lock);
+	res = netdev_set_ecmd(dev, ecmd);
+	spin_unlock_irq(&np->lock);
+	return res;
+}
 
-		if (eeprom.offset > eeprom.offset+eeprom.len)
-			return -EINVAL;
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	spin_lock_irq(&np->lock);
+	netdev_get_wol(dev, &wol->supported, &wol->wolopts);
+	netdev_get_sopass(dev, wol->sopass);
+	spin_unlock_irq(&np->lock);
+}
 
-		if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) {
-			eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset;
-		}
-		eeprom.magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
-		if (copy_to_user(useraddr, &eeprom, sizeof(eeprom)))
-			return -EFAULT;
+static int set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&np->lock);
+	netdev_set_wol(dev, wol->wolopts);
+	res = netdev_set_sopass(dev, wol->sopass);
+	spin_unlock_irq(&np->lock);
+	return res;
+}
 
-		useraddr += offsetof(struct ethtool_eeprom, data);
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	regs->version = NATSEMI_REGS_VER;
+	spin_lock_irq(&np->lock);
+	netdev_get_regs(dev, buf);
+	spin_unlock_irq(&np->lock);
+}
 
-		spin_lock_irq(&np->lock);
-		r = netdev_get_eeprom(dev, eebuf);
-		spin_unlock_irq(&np->lock);
+static u32 get_msglevel(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return np->msg_enable;
+}
 
-		if (r)
-			return r;
-		if (copy_to_user(useraddr, eebuf+eeprom.offset, eeprom.len))
-			return -EFAULT;
-		return 0;
-	}
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	np->msg_enable = val;
+}
 
+static int nway_reset(struct net_device *dev)
+{
+	int tmp;
+	int r = -EINVAL;
+	/* if autoneg is off, it's an error */
+	tmp = mdio_read(dev, MII_BMCR);
+	if (tmp & BMCR_ANENABLE) {
+		tmp |= (BMCR_ANRESTART);
+		mdio_write(dev, MII_BMCR, tmp);
+		r = 0;
 	}
+	return r;
+}
 
-	return -EOPNOTSUPP;
+static u32 get_link(struct net_device *dev)
+{
+	/* LSTATUS is latched low until a read - so read twice */
+	mdio_read(dev, MII_BMSR);
+	return (mdio_read(dev, MII_BMSR)&BMSR_LSTATUS) ? 1:0;
 }
 
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	u8 eebuf[NATSEMI_EEPROM_SIZE];
+	int res;
+
+	eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16);
+	spin_lock_irq(&np->lock);
+	res = netdev_get_eeprom(dev, eebuf);
+	spin_unlock_irq(&np->lock);
+	if (!res)
+		memcpy(data, eebuf+eeprom->offset, eeprom->len);
+	return res;
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = get_drvinfo,
+	.get_regs_len = get_regs_len,
+	.get_eeprom_len = get_eeprom_len,
+	.get_settings = get_settings,
+	.set_settings = set_settings,
+	.get_wol = get_wol,
+	.set_wol = set_wol,
+	.get_regs = get_regs,
+	.get_msglevel = get_msglevel,
+	.set_msglevel = set_msglevel,
+	.nway_reset = nway_reset,
+	.get_link = get_link,
+	.get_eeprom = get_eeprom,
+};
+
 static int netdev_set_wol(struct net_device *dev, u32 newval)
 {
 	struct netdev_private *np = netdev_priv(dev);
@@ -2976,8 +2937,6 @@ static int netdev_ioctl(struct net_devic
 	struct netdev_private *np = netdev_priv(dev);
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 	case SIOCDEVPRIVATE:		/* for binary compat, remove in 2.5 */
 		data->phy_id = np->phy_addr_external;
diff -puN drivers/net/ns83820.c~bk-netdev drivers/net/ns83820.c
--- 25/drivers/net/ns83820.c~bk-netdev	2004-09-06 18:43:15.634893520 -0700
+++ 25-akpm/drivers/net/ns83820.c	2004-09-06 18:43:15.807867224 -0700
@@ -1192,59 +1192,26 @@ static struct net_device_stats *ns83820_
 	return &dev->stats;
 }
 
-static int ns83820_ethtool_ioctl (struct ns83820 *dev, void __user *useraddr)
+static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:
-		{
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-			strcpy(info.driver, "ns83820");
-			strcpy(info.version, VERSION);
-			strcpy(info.bus_info, pci_name(dev->pci_dev));
-			if (copy_to_user(useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
-
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = { ETHTOOL_GLINK };
-		u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
-
-		if (cfg & CFG_LNKSTS)
-			edata.data = 1;
-		else
-			edata.data = 0;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-
-	default:
-		break;
-	}
-
-	return -EOPNOTSUPP;
+	struct ns83820 *dev = PRIV(ndev);
+	strcpy(info->driver, "ns83820");
+	strcpy(info->version, VERSION);
+	strcpy(info->bus_info, pci_name(dev->pci_dev));
 }
 
-static int ns83820_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+static u32 ns83820_get_link(struct net_device *ndev)
 {
 	struct ns83820 *dev = PRIV(ndev);
-
-	switch(cmd) {
-	case SIOCETHTOOL:
-		return ns83820_ethtool_ioctl(dev, rq->ifr_data);
-
-	default:
-		return -EOPNOTSUPP;
-	}
+	u32 cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+	return cfg & CFG_LNKSTS ? 1 : 0;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = ns83820_get_drvinfo,
+	.get_link = ns83820_get_link
+};
+
 static void ns83820_mib_isr(struct ns83820 *dev)
 {
 	spin_lock(&dev->misc_lock);
@@ -1884,7 +1851,7 @@ static int __devinit ns83820_init_one(st
 	ndev->get_stats = ns83820_get_stats;
 	ndev->change_mtu = ns83820_change_mtu;
 	ndev->set_multicast_list = ns83820_set_multicast;
-	ndev->do_ioctl = ns83820_ioctl;
+	SET_ETHTOOL_OPS(ndev, &ops);
 	ndev->tx_timeout = ns83820_tx_timeout;
 	ndev->watchdog_timeo = 5 * HZ;
 
diff -puN drivers/net/pcmcia/smc91c92_cs.c~bk-netdev drivers/net/pcmcia/smc91c92_cs.c
--- 25/drivers/net/pcmcia/smc91c92_cs.c~bk-netdev	2004-09-06 18:43:15.635893368 -0700
+++ 25-akpm/drivers/net/pcmcia/smc91c92_cs.c	2004-09-06 18:43:15.810866768 -0700
@@ -304,6 +304,7 @@ static void mdio_sync(ioaddr_t addr);
 static int mdio_read(struct net_device *dev, int phy_id, int loc);
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
 
 /*======================================================================
 
@@ -357,6 +358,7 @@ static dev_link_t *smc91c92_attach(void)
     dev->open = &smc_open;
     dev->stop = &smc_close;
     dev->do_ioctl = &smc_ioctl;
+    SET_ETHTOOL_OPS(dev, &ethtool_ops);
 #ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
@@ -2118,131 +2120,130 @@ static int smc_netdev_set_ecmd(struct ne
     return 0;
 }
 
-static int smc_ethtool_ioctl (struct net_device *dev, void __user *useraddr)
+static int check_if_running(struct net_device *dev)
 {
-    u32 ethcmd;
-    struct smc_private *smc = netdev_priv(dev);
-
-    if (get_user(ethcmd, (u32 __user *)useraddr))
-	return -EFAULT;
-
-    switch (ethcmd) {
-
-    case ETHTOOL_GDRVINFO: {
-	struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-	strcpy(info.driver, DRV_NAME);
-	strcpy(info.version, DRV_VERSION);
-	if (copy_to_user(useraddr, &info, sizeof(info)))
-	    return -EFAULT;
+	if (!netif_running(dev))
+		return -EINVAL;
 	return 0;
-    }
+}
+
+static void smc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+}
 
-    /* get settings */
-    case ETHTOOL_GSET: {
+static int smc_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct smc_private *smc = netdev_priv(dev);
+	ioaddr_t ioaddr = dev->base_addr;
+	u16 saved_bank = inw(ioaddr + BANK_SELECT);
 	int ret;
-	struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+
+	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
 	if (smc->cfg & CFG_MII_SELECT)
-	    ret = mii_ethtool_gset(&smc->mii_if, &ecmd);
+		ret = mii_ethtool_gset(&smc->mii_if, ecmd);
 	else
-	    ret = smc_netdev_get_ecmd(dev, &ecmd);
+		ret = smc_netdev_get_ecmd(dev, ecmd);
 	spin_unlock_irq(&smc->lock);
-	if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-	    return -EFAULT;
+	SMC_SELECT_BANK(saved_bank);
 	return ret;
-    }
+}
 
-    /* set settings */
-    case ETHTOOL_SSET: {
+static int smc_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct smc_private *smc = netdev_priv(dev);
+	ioaddr_t ioaddr = dev->base_addr;
+	u16 saved_bank = inw(ioaddr + BANK_SELECT);
 	int ret;
-	struct ethtool_cmd ecmd;
-	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-	    return -EFAULT;
+
+	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
 	if (smc->cfg & CFG_MII_SELECT)
-	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
+		ret = mii_ethtool_sset(&smc->mii_if, ecmd);
 	else
-	    ret = smc_netdev_set_ecmd(dev, &ecmd);
+		ret = smc_netdev_set_ecmd(dev, ecmd);
 	spin_unlock_irq(&smc->lock);
+	SMC_SELECT_BANK(saved_bank);
 	return ret;
-    }
+}
+
+static u32 smc_get_link(struct net_device *dev)
+{
+	struct smc_private *smc = netdev_priv(dev);
+	ioaddr_t ioaddr = dev->base_addr;
+	u16 saved_bank = inw(ioaddr + BANK_SELECT);
+	u32 ret;
 
-    /* get link status */
-    case ETHTOOL_GLINK: {
-	struct ethtool_value edata = { ETHTOOL_GLINK };
+	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
-	edata.data = smc_link_ok(dev);
+	ret = smc_link_ok(dev);
 	spin_unlock_irq(&smc->lock);
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-	    return -EFAULT;
-	return 0;
-    }
+	SMC_SELECT_BANK(saved_bank);
+	return ret;
+}
 
 #ifdef PCMCIA_DEBUG
-    /* get message-level */
-    case ETHTOOL_GMSGLVL: {
-	struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-	edata.data = pc_debug;
-	if (copy_to_user(useraddr, &edata, sizeof(edata)))
-	    return -EFAULT;
-	return 0;
-    }
+static u32 smc_get_msglevel(struct net_device *dev)
+{
+	return pc_debug;
+}
 
-    /* set message-level */
-    case ETHTOOL_SMSGLVL: {
-	struct ethtool_value edata;
-	if (copy_from_user(&edata, useraddr, sizeof(edata)))
-	    return -EFAULT;
-	pc_debug = edata.data;
-	return 0;
-    }
+static void smc_set_msglevel(struct net_device *dev, u32 val)
+{
+	pc_debug = val;
+}
 #endif
-    /* restart autonegotiation */
-    case ETHTOOL_NWAY_RST: {
-	if (smc->cfg & CFG_MII_SELECT)
-	    return mii_nway_restart(&smc->mii_if);
-	else
-	    return -EOPNOTSUPP;
-    }
-
-    default:
-	break;
-    }
 
-    return -EOPNOTSUPP;
-}
+static int smc_nway_reset(struct net_device *dev)
+{
+	struct smc_private *smc = netdev_priv(dev);
+	if (smc->cfg & CFG_MII_SELECT) {
+		ioaddr_t ioaddr = dev->base_addr;
+		u16 saved_bank = inw(ioaddr + BANK_SELECT);
+		int res;
+
+		SMC_SELECT_BANK(3);
+		res = mii_nway_restart(&smc->mii_if);
+		SMC_SELECT_BANK(saved_bank);
+
+		return res;
+	} else
+		return -EOPNOTSUPP;
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.begin = check_if_running,
+	.get_drvinfo = smc_get_drvinfo,
+	.get_settings = smc_get_settings,
+	.set_settings = smc_set_settings,
+	.get_link = smc_get_link,
+#ifdef PCMCIA_DEBUG
+	.get_msglevel = smc_get_msglevel,
+	.set_msglevel = smc_set_msglevel,
+#endif
+	.nway_reset = smc_nway_reset,
+};
 
 static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
-    struct smc_private *smc = netdev_priv(dev);
-    struct mii_ioctl_data *mii;
-    int rc = 0;
-    u_short saved_bank;
-    ioaddr_t ioaddr = dev->base_addr;
-
-    mii = if_mii(rq);
-    if (!netif_running(dev))
-    	return -EINVAL;
+	struct smc_private *smc = netdev_priv(dev);
+	struct mii_ioctl_data *mii = if_mii(rq);
+	int rc = 0;
+	u16 saved_bank;
+	ioaddr_t ioaddr = dev->base_addr;
 
-    switch (cmd) {
-    case SIOCETHTOOL:
-	saved_bank = inw(ioaddr + BANK_SELECT);
-	SMC_SELECT_BANK(3);
-	rc = smc_ethtool_ioctl(dev, rq->ifr_data);
-	SMC_SELECT_BANK(saved_bank);
-	break;
+	if (!netif_running(dev))
+		return -EINVAL;
 
-    default:
 	spin_lock_irq(&smc->lock);
 	saved_bank = inw(ioaddr + BANK_SELECT);
 	SMC_SELECT_BANK(3);
 	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
 	SMC_SELECT_BANK(saved_bank);
 	spin_unlock_irq(&smc->lock);
-	break;
-    }
-
-    return rc;
+	return rc;
 }
 
 static struct pcmcia_driver smc91c92_cs_driver = {
diff -puN drivers/net/r8169.c~bk-netdev drivers/net/r8169.c
--- 25/drivers/net/r8169.c~bk-netdev	2004-09-06 18:43:15.637893064 -0700
+++ 25-akpm/drivers/net/r8169.c	2004-09-06 18:43:15.815866008 -0700
@@ -6,6 +6,7 @@
  History:
  Feb  4 2002	- created initially by ShuChen <shuchen@realtek.com.tw>.
  May 20 2002	- Add link status force-mode and TBI mode support.
+        2004	- Massive updates. See kernel SCM system for details.
 =========================================================================
   1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
 	 Command: 'insmod r8169 media = SET_MEDIA'
@@ -33,6 +34,13 @@ VERSION 1.2	<2002/11/30>
 	- Copy mc_filter setup code from 8139cp
 	  (includes an optimization, and avoids set_bit use)
 
+VERSION 1.6LK	<2004/04/14>
+
+	- Merge of Realtek's version 1.6
+	- Conversion to DMA API
+	- Suspend/resume
+	- Endianness
+	- Misc Rx/Tx bugs
 */
 
 #include <linux/module.h>
@@ -42,13 +50,17 @@ VERSION 1.2	<2002/11/30>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/if_vlan.h>
 #include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 
 #include <asm/io.h>
 
-#define RTL8169_VERSION "1.2"
+#define RTL8169_VERSION "1.6LK"
 #define MODULENAME "r8169"
 #define RTL8169_DRIVER_NAME   MODULENAME " Gigabit Ethernet driver " RTL8169_VERSION
 #define PFX MODULENAME ": "
@@ -67,9 +79,11 @@ VERSION 1.2	<2002/11/30>
 
 #ifdef CONFIG_R8169_NAPI
 #define rtl8169_rx_skb			netif_receive_skb
+#define rtl8169_rx_hwaccel_skb		vlan_hwaccel_rx
 #define rtl8169_rx_quota(count, quota)	min(count, quota)
 #else
 #define rtl8169_rx_skb			netif_rx
+#define rtl8169_rx_hwaccel_skb		vlan_hwaccel_receive_skb
 #define rtl8169_rx_quota(count, quota)	count
 #endif
 
@@ -87,9 +101,6 @@ static int multicast_filter_limit = 32;
 /* MAC address length*/
 #define MAC_ADDR_LEN	6
 
-/* max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4).*/
-#define MAX_ETH_FRAME_SIZE	1536
-
 #define TX_FIFO_THRESH 256	/* In bytes */
 
 #define RX_FIFO_THRESH	7	/* 7 means NO threshold, Rx buffer level before first PCI xfer.  */
@@ -99,6 +110,7 @@ static int multicast_filter_limit = 32;
 #define RxPacketMaxSize	0x0800	/* Maximum size supported is 16K-1 */
 #define InterFrameGap	0x03	/* 3 means InterFrameGap = the shortest one */
 
+#define R8169_REGS_SIZE		256
 #define R8169_NAPI_WEIGHT	64
 #define NUM_TX_DESC	64	/* Number of Tx descriptor registers */
 #define NUM_RX_DESC	256	/* Number of Rx descriptor registers */
@@ -106,7 +118,6 @@ static int multicast_filter_limit = 32;
 #define R8169_TX_RING_BYTES	(NUM_TX_DESC * sizeof(struct TxDesc))
 #define R8169_RX_RING_BYTES	(NUM_RX_DESC * sizeof(struct RxDesc))
 
-#define RTL_MIN_IO_SIZE 0x80
 #define RTL8169_TX_TIMEOUT	(6*HZ)
 #define RTL8169_PHY_TIMEOUT	(10*HZ)
 
@@ -303,26 +314,52 @@ enum RTL8169_register_content {
 };
 
 enum _DescStatusBit {
-	OWNbit = 0x80000000,
-	EORbit = 0x40000000,
-	FSbit = 0x20000000,
-	LSbit = 0x10000000,
+	DescOwn		= (1 << 31), /* Descriptor is owned by NIC */
+	RingEnd		= (1 << 30), /* End of descriptor ring */
+	FirstFrag	= (1 << 29), /* First segment of a packet */
+	LastFrag	= (1 << 28), /* Final segment of a packet */
+
+	/* Tx private */
+	IPCS		= (1 << 18), /* Calculate IP checksum */
+	UDPCS		= (1 << 17), /* Calculate UDP/IP checksum */
+	TCPCS		= (1 << 16), /* Calculate TCP/IP checksum */
+	TxVlanTag	= (1 << 17), /* Add VLAN tag */
+
+	/* Rx private */
+	PID1		= (1 << 18), /* Protocol ID bit 1/2 */
+	PID0		= (1 << 17), /* Protocol ID bit 2/2 */
+
+#define RxProtoUDP	(PID1)
+#define RxProtoTCP	(PID0)
+#define RxProtoIP	(PID1 | PID0)
+#define RxProtoMask	RxProtoIP
+
+	IPFail		= (1 << 16), /* IP checksum failed */
+	UDPFail		= (1 << 15), /* UDP/IP checksum failed */
+	TCPFail		= (1 << 14), /* TCP/IP checksum failed */
+	RxVlanTag	= (1 << 16), /* VLAN tag available */
 };
 
 #define RsvdMask	0x3fffc000
 
 struct TxDesc {
-	u32 status;
-	u32 vlan_tag;
+	u32 opts1;
+	u32 opts2;
 	u64 addr;
 };
 
 struct RxDesc {
-	u32 status;
-	u32 vlan_tag;
+	u32 opts1;
+	u32 opts2;
 	u64 addr;
 };
 
+struct ring_info {
+	struct sk_buff	*skb;
+	u32		len;
+	u8		__pad[sizeof(void *) - sizeof(u32)];
+};
+
 struct rtl8169_private {
 	void *mmio_addr;		/* memory map physical address */
 	struct pci_dev *pci_dev;	/* Index of PCI device  */
@@ -340,13 +377,16 @@ struct rtl8169_private {
 	dma_addr_t TxPhyAddr;
 	dma_addr_t RxPhyAddr;
 	struct sk_buff *Rx_skbuff[NUM_RX_DESC];	/* Rx data buffers */
-	struct sk_buff *Tx_skbuff[NUM_TX_DESC];	/* Tx data buffers */
+	struct ring_info tx_skb[NUM_TX_DESC];	/* Tx data buffers */
+	unsigned rx_buf_sz;
 	struct timer_list timer;
 	u16 cp_cmd;
 	u16 intr_mask;
 	int phy_auto_nego_reg;
 	int phy_1000_ctrl_reg;
-
+#ifdef CONFIG_R8169_VLAN
+	struct vlan_group *vlgrp;
+#endif
 	int (*set_speed)(struct net_device *, u8 autoneg, u16 speed, u8 duplex);
 	void (*get_settings)(struct net_device *, struct ethtool_cmd *);
 	void (*phy_reset_enable)(void *);
@@ -508,6 +548,11 @@ static void rtl8169_get_drvinfo(struct n
 	strcpy(info->bus_info, pci_name(tp->pci_dev));
 }
 
+static int rtl8169_get_regs_len(struct net_device *dev)
+{
+	return R8169_REGS_SIZE;
+}
+
 static int rtl8169_set_speed_tbi(struct net_device *dev,
 				 u8 autoneg, u16 speed, u8 duplex)
 {
@@ -598,6 +643,105 @@ static int rtl8169_set_settings(struct n
 	return ret;
 }
 
+static u32 rtl8169_get_rx_csum(struct net_device *dev)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+
+	return !!(tp->cp_cmd & RxChkSum);
+}
+
+static int rtl8169_set_rx_csum(struct net_device *dev,  u32 data)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+
+	if (data)
+		tp->cp_cmd |= RxChkSum;
+	else
+		tp->cp_cmd &= ~RxChkSum;
+
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+	RTL_R16(CPlusCmd);
+
+	spin_unlock_irqrestore(&tp->lock, flags);
+
+	return 0;
+}
+
+#ifdef CONFIG_R8169_VLAN
+
+static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
+				      struct sk_buff *skb)
+{
+	return (tp->vlgrp && vlan_tx_tag_present(skb)) ?
+		TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb)) : 0x00;
+}
+
+static void rtl8169_vlan_rx_register(struct net_device *dev,
+				     struct vlan_group *grp)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	tp->vlgrp = grp;
+	tp->cp_cmd |= RxVlan;
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+	RTL_R16(CPlusCmd);
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static void rtl8169_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct rtl8169_private *tp = netdev_priv(dev);
+	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&tp->lock, flags);
+	tp->cp_cmd &= ~RxVlan;
+	RTL_W16(CPlusCmd, tp->cp_cmd);
+	RTL_R16(CPlusCmd);
+	if (tp->vlgrp)
+		tp->vlgrp->vlan_devices[vid] = NULL;
+	spin_unlock_irqrestore(&tp->lock, flags);
+}
+
+static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
+			       struct sk_buff *skb)
+{
+	u32 opts2 = desc->opts2;
+	int ret;
+
+	if (tp->vlgrp && (opts2 & RxVlanTag)) {
+		rtl8169_rx_hwaccel_skb(skb, tp->vlgrp,
+				       be16_to_cpu(opts2 & 0xffff));
+		ret = 0;
+	} else
+		ret = -1;
+	desc->opts2 = 0;
+	return ret;
+}
+
+#else /* !CONFIG_R8169_VLAN */
+
+static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
+				      struct sk_buff *skb)
+{
+	return 0;
+}
+
+static int rtl8169_rx_vlan_skb(struct rtl8169_private *tp, struct RxDesc *desc,
+			       struct sk_buff *skb)
+{
+	return -1;
+}
+
+#endif
+
 static void rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
@@ -671,12 +815,33 @@ static int rtl8169_get_settings(struct n
 	return 0;
 }
 
+static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
+			     void *p)
+{
+        struct rtl8169_private *tp = netdev_priv(dev);
+        unsigned long flags;
+
+        if (regs->len > R8169_REGS_SIZE)
+        	regs->len = R8169_REGS_SIZE;
+
+        spin_lock_irqsave(&tp->lock, flags);
+        memcpy_fromio(p, tp->mmio_addr, regs->len);
+        spin_unlock_irqrestore(&tp->lock, flags);
+}
 
 static struct ethtool_ops rtl8169_ethtool_ops = {
 	.get_drvinfo		= rtl8169_get_drvinfo,
+	.get_regs_len		= rtl8169_get_regs_len,
 	.get_link		= ethtool_op_get_link,
 	.get_settings		= rtl8169_get_settings,
 	.set_settings		= rtl8169_set_settings,
+	.get_rx_csum		= rtl8169_get_rx_csum,
+	.set_rx_csum		= rtl8169_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_regs		= rtl8169_get_regs,
 };
 
 static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, int bitnum,
@@ -907,28 +1072,31 @@ static inline void rtl8169_request_timer
 	add_timer(timer);
 }
 
+static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
+				  void *ioaddr)
+{
+	iounmap(ioaddr);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	free_netdev(dev);
+}
+
 static int __devinit
 rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
 		   void **ioaddr_out)
 {
-	void *ioaddr = NULL;
+	void *ioaddr;
 	struct net_device *dev;
 	struct rtl8169_private *tp;
-	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len;
-	int rc, i, acpi_idle_state = 0, pm_cap;
-
+	int rc = -ENOMEM, i, acpi_idle_state = 0, pm_cap;
 
-	assert(pdev != NULL);
 	assert(ioaddr_out != NULL);
 
-	*ioaddr_out = NULL;
-	*dev_out = NULL;
-
 	// dev zeroed in alloc_etherdev 
 	dev = alloc_etherdev(sizeof (*tp));
 	if (dev == NULL) {
 		printk(KERN_ERR PFX "unable to alloc new ethernet\n");
-		return -ENOMEM;
+		goto err_out;
 	}
 
 	SET_MODULE_OWNER(dev);
@@ -939,9 +1107,13 @@ rtl8169_init_board(struct pci_dev *pdev,
 	rc = pci_enable_device(pdev);
 	if (rc) {
 		printk(KERN_ERR PFX "%s: enable failure\n", pdev->slot_name);
-		goto err_out;
+		goto err_out_free_dev;
 	}
 
+	rc = pci_set_mwi(pdev);
+	if (rc < 0)
+		goto err_out_disable;
+
 	/* save power state before pci_enable_device overwrites it */
 	pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
 	if (pm_cap) {
@@ -952,41 +1124,38 @@ rtl8169_init_board(struct pci_dev *pdev,
 	} else {
 		printk(KERN_ERR PFX
 		       "Cannot find PowerManagement capability, aborting.\n");
-		goto err_out_free_res;
+		goto err_out_mwi;
 	}
 
-	mmio_start = pci_resource_start(pdev, 1);
-	mmio_end = pci_resource_end(pdev, 1);
-	mmio_flags = pci_resource_flags(pdev, 1);
-	mmio_len = pci_resource_len(pdev, 1);
-
 	// make sure PCI base addr 1 is MMIO
-	if (!(mmio_flags & IORESOURCE_MEM)) {
+	if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
 		printk(KERN_ERR PFX
 		       "region #1 not an MMIO resource, aborting\n");
 		rc = -ENODEV;
-		goto err_out_disable;
+		goto err_out_mwi;
 	}
 	// check for weird/broken PCI region reporting
-	if (mmio_len < RTL_MIN_IO_SIZE) {
+	if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
 		printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
 		rc = -ENODEV;
-		goto err_out_disable;
+		goto err_out_mwi;
 	}
 
 	rc = pci_request_regions(pdev, MODULENAME);
 	if (rc) {
 		printk(KERN_ERR PFX "%s: could not request regions.\n",
 		       pdev->slot_name);
-		goto err_out_disable;
+		goto err_out_mwi;
 	}
 
 	tp->cp_cmd = PCIMulRW | RxChkSum;
 
-	if ((sizeof(dma_addr_t) > 4) &&
-	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+	if ((sizeof(dma_addr_t) > 4) && !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
 		tp->cp_cmd |= PCIDAC;
-	else {
+		dev->features |= NETIF_F_HIGHDMA;
+	} else {
 		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 		if (rc < 0) {
 			printk(KERN_ERR PFX "DMA configuration failed.\n");
@@ -994,12 +1163,10 @@ rtl8169_init_board(struct pci_dev *pdev,
 		}
 	}
 
-
-	// enable PCI bus-mastering
 	pci_set_master(pdev);
 
 	// ioremap MMIO region 
-	ioaddr = ioremap(mmio_start, mmio_len);
+	ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
 	if (ioaddr == NULL) {
 		printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
 		rc = -EIO;
@@ -1036,26 +1203,35 @@ rtl8169_init_board(struct pci_dev *pdev,
 	}
 	tp->chipset = i;
 
+	tp->rx_buf_sz = RX_BUF_SIZE;
+
 	*ioaddr_out = ioaddr;
 	*dev_out = dev;
-	return 0;
+out:
+	return rc;
 
 err_out_free_res:
 	pci_release_regions(pdev);
 
+err_out_mwi:
+	pci_clear_mwi(pdev);
+
 err_out_disable:
 	pci_disable_device(pdev);
 
-err_out:
+err_out_free_dev:
 	free_netdev(dev);
-	return rc;
+err_out:
+	*ioaddr_out = NULL;
+	*dev_out = NULL;
+	goto out;
 }
 
 static int __devinit
 rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	struct net_device *dev = NULL;
-	struct rtl8169_private *tp = NULL;
+	struct rtl8169_private *tp;
 	void *ioaddr = NULL;
 	static int board_idx = -1;
 	static int printed_version = 0;
@@ -1079,8 +1255,6 @@ rtl8169_init_one(struct pci_dev *pdev, c
 
 	tp = dev->priv;
 	assert(ioaddr != NULL);
-	assert(dev != NULL);
-	assert(tp != NULL);
 
 	if (RTL_R8(PHYstatus) & TBI_Enable) {
 		tp->set_speed = rtl8169_set_speed_tbi;
@@ -1105,18 +1279,26 @@ rtl8169_init_one(struct pci_dev *pdev, c
 	dev->open = rtl8169_open;
 	dev->hard_start_xmit = rtl8169_start_xmit;
 	dev->get_stats = rtl8169_get_stats;
-	dev->ethtool_ops = &rtl8169_ethtool_ops;
+	SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops);
 	dev->stop = rtl8169_close;
 	dev->tx_timeout = rtl8169_tx_timeout;
 	dev->set_multicast_list = rtl8169_set_rx_mode;
 	dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
+
 #ifdef CONFIG_R8169_NAPI
 	dev->poll = rtl8169_poll;
 	dev->weight = R8169_NAPI_WEIGHT;
 	printk(KERN_INFO PFX "NAPI enabled\n");
 #endif
+
+#ifdef CONFIG_R8169_VLAN
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+	dev->vlan_rx_register = rtl8169_vlan_rx_register;
+	dev->vlan_rx_kill_vid = rtl8169_vlan_rx_kill_vid;
+#endif
+
 	tp->intr_mask = 0xffff;
 	tp->pci_dev = pdev;
 	tp->mmio_addr = ioaddr;
@@ -1125,10 +1307,7 @@ rtl8169_init_one(struct pci_dev *pdev, c
 
 	rc = register_netdev(dev);
 	if (rc) {
-		iounmap(ioaddr);
-		pci_release_regions(pdev);
-		pci_disable_device(pdev);
-		free_netdev(dev);
+		rtl8169_release_board(pdev, dev, ioaddr);
 		return rc;
 	}
 
@@ -1184,11 +1363,7 @@ rtl8169_remove_one(struct pci_dev *pdev)
 	assert(tp != NULL);
 
 	unregister_netdev(dev);
-	iounmap(tp->mmio_addr);
-	pci_release_regions(pdev);
-
-	pci_disable_device(pdev);
-	free_netdev(dev);
+	rtl8169_release_board(pdev, dev, tp->mmio_addr);
 	pci_set_drvdata(pdev, NULL);
 }
 
@@ -1354,49 +1529,51 @@ rtl8169_hw_start(struct net_device *dev)
 static inline void rtl8169_make_unusable_by_asic(struct RxDesc *desc)
 {
 	desc->addr = 0x0badbadbadbadbadull;
-	desc->status &= ~cpu_to_le32(OWNbit | RsvdMask);
+	desc->opts1 &= ~cpu_to_le32(DescOwn | RsvdMask);
 }
 
-static void rtl8169_free_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
-				struct RxDesc *desc)
+static void rtl8169_free_rx_skb(struct rtl8169_private *tp,
+				struct sk_buff **sk_buff, struct RxDesc *desc)
 {
-	pci_unmap_single(pdev, le64_to_cpu(desc->addr), RX_BUF_SIZE,
+	struct pci_dev *pdev = tp->pci_dev;
+
+	pci_unmap_single(pdev, le64_to_cpu(desc->addr), tp->rx_buf_sz,
 			 PCI_DMA_FROMDEVICE);
 	dev_kfree_skb(*sk_buff);
 	*sk_buff = NULL;
 	rtl8169_make_unusable_by_asic(desc);
 }
 
-static inline void rtl8169_return_to_asic(struct RxDesc *desc)
+static inline void rtl8169_return_to_asic(struct RxDesc *desc, int rx_buf_sz)
 {
-	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+	desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
 }
 
-static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping)
+static inline void rtl8169_give_to_asic(struct RxDesc *desc, dma_addr_t mapping,
+					int rx_buf_sz)
 {
 	desc->addr = cpu_to_le64(mapping);
-	desc->status |= cpu_to_le32(OWNbit + RX_BUF_SIZE);
+	desc->opts1 |= cpu_to_le32(DescOwn + rx_buf_sz);
 }
 
-static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct net_device *dev,
-				struct sk_buff **sk_buff, struct RxDesc *desc)
+static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+				struct RxDesc *desc, int rx_buf_sz)
 {
 	struct sk_buff *skb;
 	dma_addr_t mapping;
 	int ret = 0;
 
-	skb = dev_alloc_skb(RX_BUF_SIZE);
+	skb = dev_alloc_skb(rx_buf_sz);
 	if (!skb)
 		goto err_out;
 
-	skb->dev = dev;
 	skb_reserve(skb, 2);
 	*sk_buff = skb;
 
-	mapping = pci_map_single(pdev, skb->tail, RX_BUF_SIZE,
+	mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
 				 PCI_DMA_FROMDEVICE);
 
-	rtl8169_give_to_asic(desc, mapping);
+	rtl8169_give_to_asic(desc, mapping, rx_buf_sz);
 
 out:
 	return ret;
@@ -1413,7 +1590,7 @@ static void rtl8169_rx_clear(struct rtl8
 
 	for (i = 0; i < NUM_RX_DESC; i++) {
 		if (tp->Rx_skbuff[i]) {
-			rtl8169_free_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+			rtl8169_free_rx_skb(tp, tp->Rx_skbuff + i,
 					    tp->RxDescArray + i);
 		}
 	}
@@ -1430,8 +1607,8 @@ static u32 rtl8169_rx_fill(struct rtl816
 		if (tp->Rx_skbuff[i])
 			continue;
 			
-		ret = rtl8169_alloc_rx_skb(tp->pci_dev, dev, tp->Rx_skbuff + i,
-					   tp->RxDescArray + i);
+		ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
+					   tp->RxDescArray + i, tp->rx_buf_sz);
 		if (ret < 0)
 			break;
 	}
@@ -1440,7 +1617,7 @@ static u32 rtl8169_rx_fill(struct rtl816
 
 static inline void rtl8169_mark_as_last_descriptor(struct RxDesc *desc)
 {
-	desc->status |= cpu_to_le32(EORbit);
+	desc->opts1 |= cpu_to_le32(RingEnd);
 }
 
 static int rtl8169_init_ring(struct net_device *dev)
@@ -1449,10 +1626,8 @@ static int rtl8169_init_ring(struct net_
 
 	tp->cur_rx = tp->dirty_rx = 0;
 	tp->cur_tx = tp->dirty_tx = 0;
-	memset(tp->TxDescArray, 0x0, NUM_TX_DESC * sizeof (struct TxDesc));
-	memset(tp->RxDescArray, 0x0, NUM_RX_DESC * sizeof (struct RxDesc));
 
-	memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *));
+	memset(tp->tx_skb, 0x0, NUM_TX_DESC * sizeof(struct ring_info));
 	memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *));
 
 	if (rtl8169_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC)
@@ -1467,33 +1642,39 @@ err_out:
 	return -ENOMEM;
 }
 
-static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
+static void rtl8169_unmap_tx_skb(struct pci_dev *pdev, struct ring_info *tx_skb,
 				 struct TxDesc *desc)
 {
-	u32 len = sk_buff[0]->len;
+	unsigned int len = tx_skb->len;
 
-	pci_unmap_single(pdev, le64_to_cpu(desc->addr),
-			 len < ETH_ZLEN ? ETH_ZLEN : len, PCI_DMA_TODEVICE);
+	pci_unmap_single(pdev, le64_to_cpu(desc->addr), len, PCI_DMA_TODEVICE);
+	desc->opts2 = 0x00;
 	desc->addr = 0x00;
-	*sk_buff = NULL;
+	tx_skb->len = 0;
 }
 
-static void
-rtl8169_tx_clear(struct rtl8169_private *tp)
+static void rtl8169_tx_clear(struct rtl8169_private *tp)
 {
-	int i;
+	unsigned int i;
 
-	tp->cur_tx = 0;
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		struct sk_buff *skb = tp->Tx_skbuff[i];
+	for (i = tp->dirty_tx; i < tp->dirty_tx + NUM_TX_DESC; i++) {
+		unsigned int entry = i % NUM_TX_DESC;
+		struct ring_info *tx_skb = tp->tx_skb + entry;
+		unsigned int len = tx_skb->len;
 
-		if (skb) {
-			rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + i,
-					     tp->TxDescArray + i);
-			dev_kfree_skb(skb);
+		if (len) {
+			struct sk_buff *skb = tx_skb->skb;
+
+			rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb,
+					     tp->TxDescArray + entry);
+			if (skb) {
+				dev_kfree_skb(skb);
+				tx_skb->skb = NULL;
+			}
 			tp->stats.tx_dropped++;
 		}
 	}
+	tp->cur_tx = tp->dirty_tx = 0;
 }
 
 static void
@@ -1523,51 +1704,122 @@ rtl8169_tx_timeout(struct net_device *de
 	netif_wake_queue(dev);
 }
 
-static int
-rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
+			      u32 opts1)
+{
+	struct skb_shared_info *info = skb_shinfo(skb);
+	unsigned int cur_frag, entry;
+	struct TxDesc *txd;
+
+	entry = tp->cur_tx;
+	for (cur_frag = 0; cur_frag < info->nr_frags; cur_frag++) {
+		skb_frag_t *frag = info->frags + cur_frag;
+		dma_addr_t mapping;
+		u32 status, len;
+		void *addr;
+
+		entry = (entry + 1) % NUM_TX_DESC;
+
+		txd = tp->TxDescArray + entry;
+		len = frag->size;
+		addr = ((void *) page_address(frag->page)) + frag->page_offset;
+		mapping = pci_map_single(tp->pci_dev, addr, len, PCI_DMA_TODEVICE);
+
+		/* anti gcc 2.95.3 bugware (sic) */
+		status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
+
+		txd->opts1 = cpu_to_le32(status);
+		txd->addr = cpu_to_le64(mapping);
+
+		tp->tx_skb[entry].len = len;
+	}
+
+	if (cur_frag) {
+		tp->tx_skb[entry].skb = skb;
+		txd->opts1 |= cpu_to_le32(LastFrag);
+	}
+
+	return cur_frag;
+}
+
+static inline u32 rtl8169_tx_csum(struct sk_buff *skb)
+{
+	if (skb->ip_summed == CHECKSUM_HW) {
+		const struct iphdr *ip = skb->nh.iph;
+
+		if (ip->protocol == IPPROTO_TCP)
+			return IPCS | TCPCS;
+		else if (ip->protocol == IPPROTO_UDP)
+			return IPCS | UDPCS;
+		BUG();
+	}
+	return 0;
+}
+
+static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct rtl8169_private *tp = netdev_priv(dev);
+	unsigned int frags, entry = tp->cur_tx % NUM_TX_DESC;
+	struct TxDesc *txd = tp->TxDescArray + entry;
 	void *ioaddr = tp->mmio_addr;
-	unsigned int entry = tp->cur_tx % NUM_TX_DESC;
-	u32 len = skb->len;
+	dma_addr_t mapping;
+	u32 status, len;
+	u32 opts1;
+	
+	if (unlikely(tp->cur_tx - tp->dirty_tx < skb_shinfo(skb)->nr_frags)) {
+		netif_stop_queue(dev);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
+		return 1;
+	}
+
+	if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
+		goto err_drop;
+
+	opts1 = DescOwn | rtl8169_tx_csum(skb);
+
+	frags = rtl8169_xmit_frags(tp, skb, opts1);
+	if (frags) {
+		len = skb_headlen(skb);
+		opts1 |= FirstFrag;
+	} else {
+		len = skb->len;
+
+		if (unlikely(len < ETH_ZLEN)) {
+			skb = skb_padto(skb, ETH_ZLEN);
+			if (!skb)
+				goto err_update_stats;
+			len = ETH_ZLEN;
+		}
 
-	if (unlikely(skb->len < ETH_ZLEN)) {
-		skb = skb_padto(skb, ETH_ZLEN);
-		if (!skb)
-			goto err_update_stats;
-		len = ETH_ZLEN;
+		opts1 |= FirstFrag | LastFrag;
+		tp->tx_skb[entry].skb = skb;
 	}
-	
-	if (!(le32_to_cpu(tp->TxDescArray[entry].status) & OWNbit)) {
-		dma_addr_t mapping;
-		u32 status;
 
-		mapping = pci_map_single(tp->pci_dev, skb->data, len,
-					 PCI_DMA_TODEVICE);
+	mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE);
 
-		tp->Tx_skbuff[entry] = skb;
-		tp->TxDescArray[entry].addr = cpu_to_le64(mapping);
+	tp->tx_skb[entry].len = len;
+	txd->addr = cpu_to_le64(mapping);
+	txd->opts2 = rtl8169_tx_vlan_tag(tp, skb);
 
-		/* anti gcc 2.95.3 bugware */
-		status = OWNbit | FSbit | LSbit | len |
-			 (EORbit * !((entry + 1) % NUM_TX_DESC));
-		tp->TxDescArray[entry].status = cpu_to_le32(status);
-			
-		RTL_W8(TxPoll, 0x40);	//set polling bit
+	wmb();
 
-		dev->trans_start = jiffies;
+	/* anti gcc 2.95.3 bugware (sic) */
+	status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
+	txd->opts1 = cpu_to_le32(status);
 
-		tp->cur_tx++;
-		smp_wmb();
-	} else
-		goto err_drop;
+	dev->trans_start = jiffies;
 
-	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx) {
-		u32 dirty = tp->dirty_tx;
-	
+	tp->cur_tx += frags + 1;
+
+	smp_wmb();
+
+	RTL_W8(TxPoll, 0x40);	//set polling bit
+
+	if (tp->cur_tx - tp->dirty_tx < MAX_SKB_FRAGS) {
 		netif_stop_queue(dev);
 		smp_rmb();
-		if (dirty != tp->dirty_tx)
+		if (tp->cur_tx - tp->dirty_tx >= MAX_SKB_FRAGS)
 			netif_wake_queue(dev);
 	}
 
@@ -1597,22 +1849,24 @@ rtl8169_tx_interrupt(struct net_device *
 
 	while (tx_left > 0) {
 		unsigned int entry = dirty_tx % NUM_TX_DESC;
-		struct sk_buff *skb = tp->Tx_skbuff[entry];
+		struct ring_info *tx_skb = tp->tx_skb + entry;
+		u32 len = tx_skb->len;
 		u32 status;
 
 		rmb();
-		status = le32_to_cpu(tp->TxDescArray[entry].status);
-		if (status & OWNbit)
+		status = le32_to_cpu(tp->TxDescArray[entry].opts1);
+		if (status & DescOwn)
 			break;
 
-		/* FIXME: is it really accurate for TxErr ? */
-		tp->stats.tx_bytes += skb->len >= ETH_ZLEN ?
-				      skb->len : ETH_ZLEN;
+		tp->stats.tx_bytes += len;
 		tp->stats.tx_packets++;
-		rtl8169_unmap_tx_skb(tp->pci_dev, tp->Tx_skbuff + entry,
-				     tp->TxDescArray + entry);
-		dev_kfree_skb_irq(skb);
-		tp->Tx_skbuff[entry] = NULL;
+
+		rtl8169_unmap_tx_skb(tp->pci_dev, tx_skb, tp->TxDescArray + entry);
+
+		if (status & LastFrag) {
+			dev_kfree_skb_irq(tx_skb->skb);
+			tx_skb->skb = NULL;
+		}
 		dirty_tx++;
 		tx_left--;
 	}
@@ -1625,9 +1879,21 @@ rtl8169_tx_interrupt(struct net_device *
 	}
 }
 
+static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
+{
+	u32 opts1 = desc->opts1;
+	u32 status = opts1 & RxProtoMask;
+
+	if (((status == RxProtoTCP) && !(opts1 & TCPFail)) ||
+	    ((status == RxProtoUDP) && !(opts1 & UDPFail)) ||
+	    ((status == RxProtoIP) && !(opts1 & IPFail)))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	else
+		skb->ip_summed = CHECKSUM_NONE;
+}
+
 static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
-				      struct RxDesc *desc,
-				      struct net_device *dev)
+				      struct RxDesc *desc, int rx_buf_sz)
 {
 	int ret = -1;
 
@@ -1636,11 +1902,10 @@ static inline int rtl8169_try_rx_copy(st
 
 		skb = dev_alloc_skb(pkt_size + 2);
 		if (skb) {
-			skb->dev = dev;
 			skb_reserve(skb, 2);
 			eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
 			*sk_buff = skb;
-			rtl8169_return_to_asic(desc);
+			rtl8169_return_to_asic(desc, rx_buf_sz);
 			ret = 0;
 		}
 	}
@@ -1667,9 +1932,9 @@ rtl8169_rx_interrupt(struct net_device *
 		u32 status;
 
 		rmb();
-		status = le32_to_cpu(tp->RxDescArray[entry].status);
+		status = le32_to_cpu(tp->RxDescArray[entry].opts1);
 
-		if (status & OWNbit)
+		if (status & DescOwn)
 			break;
 		if (status & RxRES) {
 			printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name);
@@ -1685,22 +1950,27 @@ rtl8169_rx_interrupt(struct net_device *
 			void (*pci_action)(struct pci_dev *, dma_addr_t,
 				size_t, int) = pci_dma_sync_single_for_device;
 
-
+			rtl8169_rx_csum(skb, desc);
+			
 			pci_dma_sync_single_for_cpu(tp->pci_dev,
-				le64_to_cpu(desc->addr), RX_BUF_SIZE,
+				le64_to_cpu(desc->addr), tp->rx_buf_sz,
 				PCI_DMA_FROMDEVICE);
 
-			if (rtl8169_try_rx_copy(&skb, pkt_size, desc, dev)) {
+			if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
+						tp->rx_buf_sz)) {
 				pci_action = pci_unmap_single;
 				tp->Rx_skbuff[entry] = NULL;
 			}
 
 			pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
-				   RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+				   tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 
+			skb->dev = dev;
 			skb_put(skb, pkt_size);
 			skb->protocol = eth_type_trans(skb, dev);
-			rtl8169_rx_skb(skb);
+
+			if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0)
+				rtl8169_rx_skb(skb);
 
 			dev->last_rx = jiffies;
 			tp->stats.rx_bytes += pkt_size;
diff -puN drivers/net/sk_mca.c~bk-netdev drivers/net/sk_mca.c
--- 25/drivers/net/sk_mca.c~bk-netdev	2004-09-06 18:43:15.638892912 -0700
+++ 25-akpm/drivers/net/sk_mca.c	2004-09-06 18:43:15.816865856 -0700
@@ -972,14 +972,6 @@ static struct net_device_stats *skmca_st
 	return &(priv->stat);
 }
 
-/* we don't support runtime reconfiguration, since an MCA card can
-   be unambigously identified by its POS registers. */
-
-static int skmca_config(struct net_device *dev, struct ifmap *map)
-{
-	return 0;
-}
-
 /* switch receiver mode.  We use the LANCE's multicast filter to prefilter
    multicast addresses. */
 
@@ -1147,7 +1139,6 @@ struct net_device * __init skmca_probe(i
 	/* set methods */
 	dev->open = skmca_open;
 	dev->stop = skmca_close;
-	dev->set_config = skmca_config;
 	dev->hard_start_xmit = skmca_tx;
 	dev->do_ioctl = NULL;
 	dev->get_stats = skmca_stats;
diff -puN drivers/net/starfire.c~bk-netdev drivers/net/starfire.c
--- 25/drivers/net/starfire.c~bk-netdev	2004-09-06 18:43:15.640892608 -0700
+++ 25-akpm/drivers/net/starfire.c	2004-09-06 18:43:15.820865248 -0700
@@ -799,12 +799,13 @@ static struct net_device_stats *get_stat
 static int	netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int	netdev_close(struct net_device *dev);
 static void	netdev_media_change(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
 
 
 #ifdef VLAN_SUPPORT
 static void netdev_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-        struct netdev_private *np = dev->priv;
+        struct netdev_private *np = netdev_priv(dev);
 
         spin_lock(&np->lock);
 	if (debug > 2)
@@ -816,7 +817,7 @@ static void netdev_vlan_rx_register(stru
 
 static void netdev_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	spin_lock(&np->lock);
 	if (debug > 1)
@@ -827,7 +828,7 @@ static void netdev_vlan_rx_add_vid(struc
 
 static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	spin_lock(&np->lock);
 	if (debug > 1)
@@ -951,7 +952,7 @@ static int __devinit starfire_init_one(s
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 	spin_lock_init(&np->lock);
 	pci_set_drvdata(pdev, dev);
 
@@ -1015,6 +1016,7 @@ static int __devinit starfire_init_one(s
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &netdev_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
 	if (mtu)
 		dev->mtu = mtu;
@@ -1102,7 +1104,7 @@ static void mdio_write(struct net_device
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i, retval;
 	size_t tx_done_q_size, rx_done_q_size, tx_ring_size, rx_ring_size;
@@ -1267,7 +1269,7 @@ static int netdev_open(struct net_device
 
 static void check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	u16 reg0;
 	int silly_count = 1000;
 
@@ -1302,7 +1304,7 @@ static void check_duplex(struct net_devi
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int old_debug;
 
@@ -1332,7 +1334,7 @@ static void tx_timeout(struct net_device
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int i;
 
 	np->cur_rx = np->cur_tx = np->reap_tx = 0;
@@ -1378,7 +1380,7 @@ static void init_ring(struct net_device 
 
 static int start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned int entry;
 	u32 status;
 	int i;
@@ -1497,7 +1499,7 @@ static irqreturn_t intr_handler(int irq,
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	np = dev->priv;
+	np = netdev_priv(dev);
 
 	do {
 		u32 intr_status = readl(ioaddr + IntrClear);
@@ -1597,7 +1599,7 @@ static irqreturn_t intr_handler(int irq,
    for clarity, code sharing between NAPI/non-NAPI, and better register allocation. */
 static int __netdev_rx(struct net_device *dev, int *quota)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	u32 desc_status;
 	int retcode = 0;
 
@@ -1752,7 +1754,7 @@ static int netdev_poll(struct net_device
 
 static void refill_rx_ring(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct sk_buff *skb;
 	int entry = -1;
 
@@ -1780,7 +1782,7 @@ static void refill_rx_ring(struct net_de
 
 static void netdev_media_change(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	u16 reg0, reg1, reg4, reg5;
 	u32 new_tx_mode;
@@ -1855,7 +1857,7 @@ static void netdev_media_change(struct n
 
 static void netdev_error(struct net_device *dev, int intr_status)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	/* Came close to underrunning the Tx FIFO, increase threshold. */
 	if (intr_status & IntrTxDataLow) {
@@ -1883,7 +1885,7 @@ static void netdev_error(struct net_devi
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	/* This adapter architecture needs no SMP locks. */
 	np->stats.tx_bytes = readl(ioaddr + 0x57010);
@@ -1917,7 +1919,7 @@ static void set_rx_mode(struct net_devic
 	struct dev_mc_list *mclist;
 	int i;
 #ifdef VLAN_SUPPORT
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 
 	rx_mode |= VlanMode;
 	if (np->vlgrp) {
@@ -1996,106 +1998,89 @@ static void set_rx_mode(struct net_devic
 	writel(rx_mode, ioaddr + RxFilterMode);
 }
 
+static int check_if_running(struct net_device *dev)
+{
+	if (!netif_running(dev))
+		return -EINVAL;
+	return 0;
+}
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct ethtool_cmd ecmd;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, PCI_SLOT_NAME(np->pci_dev));
+}
 
-	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-		return -EFAULT;
+static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	spin_lock_irq(&np->lock);
+	mii_ethtool_gset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	return 0;
+}
 
-	switch (ecmd.cmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info;
-		memset(&info, 0, sizeof(info));
-		info.cmd = ecmd.cmd;
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		*info.fw_version = 0;
-		strcpy(info.bus_info, PCI_SLOT_NAME(np->pci_dev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-		       return -EFAULT;
-		return 0;
-	}
+static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&np->lock);
+	res = mii_ethtool_sset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	check_duplex(dev);
+	return res;
+}
 
-	/* get settings */
-	case ETHTOOL_GSET: {
-		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-		spin_lock_irq(&np->lock);
-		mii_ethtool_gset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set settings */
-	case ETHTOOL_SSET: {
-		int r;
-		struct ethtool_cmd ecmd;
-		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-			return -EFAULT;
-		spin_lock_irq(&np->lock);
-		r = mii_ethtool_sset(&np->mii_if, &ecmd);
-		spin_unlock_irq(&np->lock);
-		check_duplex(dev);
-		return r;
-	}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST: {
-		return mii_nway_restart(&np->mii_if);
-	}
-	/* get link status */
-	case ETHTOOL_GLINK: {
-		struct ethtool_value edata = {ETHTOOL_GLINK};
-		edata.data = mii_link_ok(&np->mii_if);
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
+static int nway_reset(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return mii_nway_restart(&np->mii_if);
+}
 
-	/* get message-level */
-	case ETHTOOL_GMSGLVL: {
-		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
-		if (copy_to_user(useraddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-	}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL: {
-		struct ethtool_value edata;
-		if (copy_from_user(&edata, useraddr, sizeof(edata)))
-			return -EFAULT;
-		debug = edata.data;
-		return 0;
-	}
-	default:
-		return -EOPNOTSUPP;
-	}
+static u32 get_link(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return mii_link_ok(&np->mii_if);
 }
 
+static u32 get_msglevel(struct net_device *dev)
+{
+	return debug;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+	debug = val;
+}
+
+static struct ethtool_ops ethtool_ops = {
+	.begin = check_if_running,
+	.get_drvinfo = get_drvinfo,
+	.get_settings = get_settings,
+	.set_settings = set_settings,
+	.nway_reset = nway_reset,
+	.get_link = get_link,
+	.get_msglevel = get_msglevel,
+	.set_msglevel = set_msglevel,
+};
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
+	struct mii_ioctl_data *data = if_mii(rq);
 	int rc;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd == SIOCETHTOOL)
-		rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
+	spin_lock_irq(&np->lock);
+	rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
+	spin_unlock_irq(&np->lock);
 
-	else {
-		struct mii_ioctl_data *data = if_mii(rq);
-		spin_lock_irq(&np->lock);
-		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
-		spin_unlock_irq(&np->lock);
-
-		if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
-			check_duplex(dev);
-	}
+	if ((cmd == SIOCSMIIREG) && (data->phy_id == np->phys[0]))
+		check_duplex(dev);
 
 	return rc;
 }
@@ -2103,7 +2088,7 @@ static int netdev_ioctl(struct net_devic
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int i;
 
 	netif_stop_queue(dev);
@@ -2174,16 +2159,16 @@ static int netdev_close(struct net_devic
 static void __devexit starfire_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct netdev_private *np;
+	struct netdev_private *np = netdev_priv(dev);
 
 	if (!dev)
 		BUG();
 
-	np = dev->priv;
+	unregister_netdev(dev);
+
 	if (np->queue_mem)
 		pci_free_consistent(pdev, np->queue_mem_size, np->queue_mem, np->queue_mem_dma);
 
-	unregister_netdev(dev);
 
 	/* XXX: add wakeup code -- requires firmware for MagicPacket */
 	pci_set_power_state(pdev, 3);	/* go to sleep in D3 mode */
diff -puN drivers/net/sundance.c~bk-netdev drivers/net/sundance.c
--- 25/drivers/net/sundance.c~bk-netdev	2004-09-06 18:43:15.642892304 -0700
+++ 25-akpm/drivers/net/sundance.c	2004-09-06 18:43:15.823864792 -0700
@@ -511,8 +511,7 @@ static int __set_mac_addr(struct net_dev
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
-
-
+static struct ethtool_ops ethtool_ops;
 
 static int __devinit sundance_probe1 (struct pci_dev *pdev,
 				      const struct pci_device_id *ent)
@@ -567,7 +566,7 @@ static int __devinit sundance_probe1 (st
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 	np->pci_dev = pdev;
 	np->chip_id = chip_idx;
 	np->msg_enable = (1 << debug) - 1;
@@ -600,6 +599,7 @@ static int __devinit sundance_probe1 (st
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &netdev_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->change_mtu = &change_mtu;
@@ -787,7 +787,7 @@ static void mdio_sync(long mdio_addr)
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int i, retval = 0;
@@ -817,7 +817,7 @@ static int mdio_read(struct net_device *
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
 	int i;
@@ -846,7 +846,7 @@ static void mdio_write(struct net_device
 
 static int netdev_open(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -916,7 +916,7 @@ static int netdev_open(struct net_device
 
 static void check_duplex(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
 	int negotiated = mii_lpa & np->mii_if.advertising;
@@ -945,7 +945,7 @@ static void check_duplex(struct net_devi
 static void netdev_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 
@@ -962,7 +962,7 @@ static void netdev_timer(unsigned long d
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	unsigned long flag;
 	
@@ -1015,7 +1015,7 @@ static void tx_timeout(struct net_device
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void init_ring(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int i;
 
 	np->cur_rx = np->cur_tx = 0;
@@ -1058,7 +1058,7 @@ static void init_ring(struct net_device 
 static void tx_poll (unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	unsigned head = np->cur_task % TX_RING_SIZE;
 	struct netdev_desc *txdesc = 
 		&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
@@ -1085,7 +1085,7 @@ static void tx_poll (unsigned long data)
 static int
 start_tx (struct sk_buff *skb, struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct netdev_desc *txdesc;
 	unsigned entry;
 
@@ -1127,7 +1127,7 @@ start_tx (struct sk_buff *skb, struct ne
 static int
 reset_tx (struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct sk_buff *skb;
 	int i;
@@ -1176,7 +1176,7 @@ static irqreturn_t intr_handler(int irq,
 	int handled = 0;
 
 	ioaddr = dev->base_addr;
-	np = dev->priv;
+	np = netdev_priv(dev);
 
 	do {
 		int intr_status = readw(ioaddr + IntrStatus);
@@ -1301,7 +1301,7 @@ static irqreturn_t intr_handler(int irq,
 static void rx_poll(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int entry = np->cur_rx % RX_RING_SIZE;
 	int boguscnt = np->budget;
 	long ioaddr = dev->base_addr;
@@ -1398,7 +1398,7 @@ not_done:
 
 static void refill_rx (struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int entry;
 	int cnt = 0;
 
@@ -1429,7 +1429,7 @@ static void refill_rx (struct net_device
 static void netdev_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	u16 mii_ctl, mii_advertise, mii_lpa;
 	int speed;
 
@@ -1483,7 +1483,7 @@ static void netdev_error(struct net_devi
 
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -1512,7 +1512,7 @@ static struct net_device_stats *get_stat
 static void set_rx_mode(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	u16 mc_filter[4];			/* Multicast hash filter */
 	u32 rx_mode;
 	int i;
@@ -1565,91 +1565,79 @@ static int __set_mac_addr(struct net_dev
 	writew(addr16, dev->base_addr + StationAddr+4);
 	return 0;
 }
-	
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static int check_if_running(struct net_device *dev)
 {
-	struct netdev_private *np = dev->priv;
-	u32 ethcmd;
+	if (!netif_running(dev))
+		return -EINVAL;
+	return 0;
+}
 
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pci_dev));
+}
 
-        switch (ethcmd) {
-		/* get constant driver settings/info */
-        	case ETHTOOL_GDRVINFO: {
-			struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-			strcpy(info.driver, DRV_NAME);
-			strcpy(info.version, DRV_VERSION);
-			strcpy(info.bus_info, pci_name(np->pci_dev));
-			memset(&info.fw_version, 0, sizeof(info.fw_version));
-			if (copy_to_user(useraddr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
+static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	spin_lock_irq(&np->lock);
+	mii_ethtool_gset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	return 0;
+}
 
-		/* get media settings */
-		case ETHTOOL_GSET: {
-			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-			spin_lock_irq(&np->lock);
-			mii_ethtool_gset(&np->mii_if, &ecmd);
-			spin_unlock_irq(&np->lock);
-			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-				return -EFAULT;
-			return 0;
-		}
-		/* set media settings */
-		case ETHTOOL_SSET: {
-			int r;
-			struct ethtool_cmd ecmd;
-			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-				return -EFAULT;
-			spin_lock_irq(&np->lock);
-			r = mii_ethtool_sset(&np->mii_if, &ecmd);
-			spin_unlock_irq(&np->lock);
-			return r;
-		}
-
-		/* restart autonegotiation */
-		case ETHTOOL_NWAY_RST: {
-			return mii_nway_restart(&np->mii_if);
-		}
-
-		/* get link status */
-		case ETHTOOL_GLINK: {
-			struct ethtool_value edata = {ETHTOOL_GLINK};
-			edata.data = mii_link_ok(&np->mii_if);
-			if (copy_to_user(useraddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
+static int set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	int res;
+	spin_lock_irq(&np->lock);
+	res = mii_ethtool_sset(&np->mii_if, ecmd);
+	spin_unlock_irq(&np->lock);
+	return res;
+}
 
-		/* get message-level */
-		case ETHTOOL_GMSGLVL: {
-			struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-			edata.data = np->msg_enable;
-			if (copy_to_user(useraddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-		/* set message-level */
-		case ETHTOOL_SMSGLVL: {
-			struct ethtool_value edata;
-			if (copy_from_user(&edata, useraddr, sizeof(edata)))
-				return -EFAULT;
-			np->msg_enable = edata.data;
-			return 0;
-		}
+static int nway_reset(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return mii_nway_restart(&np->mii_if);
+}
+
+static u32 get_link(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return mii_link_ok(&np->mii_if);
+}
 
-		default:
-		return -EOPNOTSUPP;
+static u32 get_msglevel(struct net_device *dev)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	return np->msg_enable;
+}
 
-        }
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+	struct netdev_private *np = netdev_priv(dev);
+	np->msg_enable = val;
 }
 
+static struct ethtool_ops ethtool_ops = {
+	.begin = check_if_running,
+	.get_drvinfo = get_drvinfo,
+	.get_settings = get_settings,
+	.set_settings = set_settings,
+	.nway_reset = nway_reset,
+	.get_link = get_link,
+	.get_msglevel = get_msglevel,
+	.set_msglevel = set_msglevel,
+};
+
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	int rc;
 	int i;
 	long ioaddr = dev->base_addr;
@@ -1657,14 +1645,9 @@ static int netdev_ioctl(struct net_devic
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	if (cmd == SIOCETHTOOL)
-		rc = netdev_ethtool_ioctl(dev, rq->ifr_data);
-
-	else {
-		spin_lock_irq(&np->lock);
-		rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
-		spin_unlock_irq(&np->lock);
-	}
+	spin_lock_irq(&np->lock);
+	rc = generic_mii_ioctl(&np->mii_if, if_mii(rq), cmd, NULL);
+	spin_unlock_irq(&np->lock);
 	switch (cmd) {
 		case SIOCDEVPRIVATE:
 		for (i=0; i<TX_RING_SIZE; i++) {
@@ -1696,7 +1679,7 @@ static int netdev_ioctl(struct net_devic
 static int netdev_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct netdev_private *np = dev->priv;
+	struct netdev_private *np = netdev_priv(dev);
 	struct sk_buff *skb;
 	int i;
 
@@ -1775,7 +1758,7 @@ static void __devexit sundance_remove1 (
 	struct net_device *dev = pci_get_drvdata(pdev);
 
 	if (dev) {
-		struct netdev_private *np = dev->priv;
+		struct netdev_private *np = netdev_priv(dev);
 
 		unregister_netdev(dev);
         	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
diff -puN drivers/net/tulip/de4x5.c~bk-netdev drivers/net/tulip/de4x5.c
--- 25/drivers/net/tulip/de4x5.c~bk-netdev	2004-09-06 18:43:15.644892000 -0700
+++ 25-akpm/drivers/net/tulip/de4x5.c	2004-09-06 18:43:15.827864184 -0700
@@ -5089,7 +5089,7 @@ mii_get_phy(struct net_device *dev)
     lp->useMII = TRUE;
 
     /* Search the MII address space for possible PHY devices */
-    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(++i)%DE4X5_MAX_MII) {
+    for (n=0, lp->mii_cnt=0, i=1; !((i==1) && (n==1)); i=(i+1)%DE4X5_MAX_MII) {
 	lp->phy[lp->active].addr = i;
 	if (i==0) n++;                             /* Count cycles */
 	while (de4x5_reset_phy(dev)<0) udelay(100);/* Wait for reset */
diff -puN drivers/net/tulip/tulip_core.c~bk-netdev drivers/net/tulip/tulip_core.c
--- 25/drivers/net/tulip/tulip_core.c~bk-netdev	2004-09-06 18:43:15.645891848 -0700
+++ 25-akpm/drivers/net/tulip/tulip_core.c	2004-09-06 18:43:15.829863880 -0700
@@ -830,30 +830,18 @@ static struct net_device_stats *tulip_ge
 }
 
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct tulip_private *np = netdev_priv(dev);
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, pci_name(np->pdev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-        }
-
-	return -EOPNOTSUPP;
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pdev));
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = tulip_get_drvinfo
+};
+
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -865,9 +853,6 @@ static int private_ioctl (struct net_dev
 	unsigned int regnum = data->reg_num;
 
 	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, rq->ifr_data);
-
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 		if (tp->mii_cnt)
 			data->phy_id = phy;
@@ -1644,6 +1629,7 @@ static int __devinit tulip_init_one (str
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &poll_tulip;
 #endif
+	SET_ETHTOOL_OPS(dev, &ops);
 
 	if (register_netdev(dev))
 		goto err_out_free_ring;
diff -puN drivers/net/tulip/xircom_tulip_cb.c~bk-netdev drivers/net/tulip/xircom_tulip_cb.c
--- 25/drivers/net/tulip/xircom_tulip_cb.c~bk-netdev	2004-09-06 18:43:15.647891544 -0700
+++ 25-akpm/drivers/net/tulip/xircom_tulip_cb.c	2004-09-06 18:43:15.832863424 -0700
@@ -350,6 +350,7 @@ static struct net_device_stats *xircom_g
 static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void set_rx_mode(struct net_device *dev);
 static void check_duplex(struct net_device *dev);
+static struct ethtool_ops ops;
 
 
 /* The Xircom cards are picky about when certain bits in CSR6 can be
@@ -450,7 +451,7 @@ static void __devinit read_mac_address(s
  */
 static void find_mii_transceivers(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	int phy, phy_idx;
 
 	if (media_cap[tp->default_port] & MediaIsMII) {
@@ -505,7 +506,7 @@ static void find_mii_transceivers(struct
  */
 static void transceiver_voodoo(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
@@ -584,7 +585,7 @@ static int __devinit xircom_init_one(str
 	/* Clear the missed-packet counter. */
 	(volatile int)inl(ioaddr + CSR8);
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 
 	tp->lock = SPIN_LOCK_UNLOCKED;
 	tp->pdev = pdev;
@@ -626,6 +627,7 @@ static int __devinit xircom_init_one(str
 #endif
 	dev->tx_timeout = xircom_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	SET_ETHTOOL_OPS(dev, &ops);
 
 	transceiver_voodoo(dev);
 
@@ -749,7 +751,7 @@ static void mdio_write(struct net_device
 static void
 xircom_up(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -804,7 +806,7 @@ xircom_up(struct net_device *dev)
 static int
 xircom_open(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 
 	if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
@@ -818,7 +820,7 @@ xircom_open(struct net_device *dev)
 
 static void xircom_tx_timeout(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (media_cap[dev->if_port] & MediaIsMII) {
@@ -870,7 +872,7 @@ static void xircom_tx_timeout(struct net
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void xircom_init_ring(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	int i;
 
 	tp->tx_full = 0;
@@ -919,7 +921,7 @@ static void xircom_init_ring(struct net_
 static int
 xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	int entry;
 	u32 flag;
 
@@ -971,7 +973,7 @@ xircom_start_xmit(struct sk_buff *skb, s
 
 static void xircom_media_change(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	u16 reg0, reg1, reg4, reg5;
 	u32 csr6 = inl(ioaddr + CSR6), newcsr6;
@@ -1032,7 +1034,7 @@ static void xircom_media_change(struct n
 
 static void check_duplex(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	u16 reg0;
 
 	mdio_write(dev, tp->phys[0], MII_BMCR, BMCR_RESET);
@@ -1065,7 +1067,7 @@ static void check_duplex(struct net_devi
 static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_instance;
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int csr5, work_budget = max_interrupt_work;
 	int handled = 0;
@@ -1203,7 +1205,7 @@ static irqreturn_t xircom_interrupt(int 
 static int
 xircom_rx(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	int entry = tp->cur_rx % RX_RING_SIZE;
 	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
 	int work_done = 0;
@@ -1303,7 +1305,7 @@ static void
 xircom_down(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 
 	/* Disable interrupts by clearing the interrupt mask. */
 	outl(0, ioaddr + CSR7);
@@ -1321,7 +1323,7 @@ static int
 xircom_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	int i;
 
 	if (xircom_debug > 1)
@@ -1359,7 +1361,7 @@ xircom_close(struct net_device *dev)
 
 static struct net_device_stats *xircom_get_stats(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	if (netif_device_present(dev))
@@ -1368,18 +1370,10 @@ static struct net_device_stats *xircom_g
 	return &tp->stats;
 }
 
-
-static int xircom_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static int xircom_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
-	struct ethtool_cmd ecmd;
-	struct xircom_private *tp = dev->priv;
-
-	if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
-		return -EFAULT;
-
-	switch (ecmd.cmd) {
-	case ETHTOOL_GSET:
-		ecmd.supported =
+	struct xircom_private *tp = netdev_priv(dev);
+	ecmd->supported =
 			SUPPORTED_10baseT_Half |
 			SUPPORTED_10baseT_Full |
 			SUPPORTED_100baseT_Half |
@@ -1387,98 +1381,90 @@ static int xircom_ethtool_ioctl(struct n
 			SUPPORTED_Autoneg |
 			SUPPORTED_MII;
 
-		ecmd.advertising = ADVERTISED_MII;
-		if (tp->advertising[0] & ADVERTISE_10HALF)
-			ecmd.advertising |= ADVERTISED_10baseT_Half;
-		if (tp->advertising[0] & ADVERTISE_10FULL)
-			ecmd.advertising |= ADVERTISED_10baseT_Full;
-		if (tp->advertising[0] & ADVERTISE_100HALF)
-			ecmd.advertising |= ADVERTISED_100baseT_Half;
-		if (tp->advertising[0] & ADVERTISE_100FULL)
-			ecmd.advertising |= ADVERTISED_100baseT_Full;
-		if (tp->autoneg) {
-			ecmd.advertising |= ADVERTISED_Autoneg;
-			ecmd.autoneg = AUTONEG_ENABLE;
-		} else
-			ecmd.autoneg = AUTONEG_DISABLE;
-
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = tp->phys[0];
-		ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10;
-		ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		ecmd.maxtxpkt = TX_RING_SIZE / 2;
-		ecmd.maxrxpkt = 0;
+	ecmd->advertising = ADVERTISED_MII;
+	if (tp->advertising[0] & ADVERTISE_10HALF)
+		ecmd->advertising |= ADVERTISED_10baseT_Half;
+	if (tp->advertising[0] & ADVERTISE_10FULL)
+		ecmd->advertising |= ADVERTISED_10baseT_Full;
+	if (tp->advertising[0] & ADVERTISE_100HALF)
+		ecmd->advertising |= ADVERTISED_100baseT_Half;
+	if (tp->advertising[0] & ADVERTISE_100FULL)
+		ecmd->advertising |= ADVERTISED_100baseT_Full;
+	if (tp->autoneg) {
+		ecmd->advertising |= ADVERTISED_Autoneg;
+		ecmd->autoneg = AUTONEG_ENABLE;
+	} else
+		ecmd->autoneg = AUTONEG_DISABLE;
 
-		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
+	ecmd->port = PORT_MII;
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = tp->phys[0];
+	ecmd->speed = tp->speed100 ? SPEED_100 : SPEED_10;
+	ecmd->duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+	ecmd->maxtxpkt = TX_RING_SIZE / 2;
+	ecmd->maxrxpkt = 0;
+	return 0;
+}
 
-	case ETHTOOL_SSET: {
-		u16 autoneg, speed100, full_duplex;
+static int xircom_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	struct xircom_private *tp = netdev_priv(dev);
+	u16 autoneg, speed100, full_duplex;
 
-		autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
-		speed100 = (ecmd.speed == SPEED_100);
-		full_duplex = (ecmd.duplex == DUPLEX_FULL);
-
-		tp->autoneg = autoneg;
-		if (speed100 != tp->speed100 ||
-		    full_duplex != tp->full_duplex) {
-			tp->speed100 = speed100;
-			tp->full_duplex = full_duplex;
-			/* change advertising bits */
-			tp->advertising[0] &= ~(ADVERTISE_10HALF |
-					     ADVERTISE_10FULL |
-					     ADVERTISE_100HALF |
-					     ADVERTISE_100FULL |
-					     ADVERTISE_100BASE4);
-			if (speed100) {
-				if (full_duplex)
-					tp->advertising[0] |= ADVERTISE_100FULL;
-				else
-					tp->advertising[0] |= ADVERTISE_100HALF;
-			} else {
-				if (full_duplex)
-					tp->advertising[0] |= ADVERTISE_10FULL;
-				else
-					tp->advertising[0] |= ADVERTISE_10HALF;
-			}
+	autoneg = (ecmd->autoneg == AUTONEG_ENABLE);
+	speed100 = (ecmd->speed == SPEED_100);
+	full_duplex = (ecmd->duplex == DUPLEX_FULL);
+
+	tp->autoneg = autoneg;
+	if (speed100 != tp->speed100 ||
+	    full_duplex != tp->full_duplex) {
+		tp->speed100 = speed100;
+		tp->full_duplex = full_duplex;
+		/* change advertising bits */
+		tp->advertising[0] &= ~(ADVERTISE_10HALF |
+				     ADVERTISE_10FULL |
+				     ADVERTISE_100HALF |
+				     ADVERTISE_100FULL |
+				     ADVERTISE_100BASE4);
+		if (speed100) {
+			if (full_duplex)
+				tp->advertising[0] |= ADVERTISE_100FULL;
+			else
+				tp->advertising[0] |= ADVERTISE_100HALF;
+		} else {
+			if (full_duplex)
+				tp->advertising[0] |= ADVERTISE_10FULL;
+			else
+				tp->advertising[0] |= ADVERTISE_10HALF;
 		}
-		check_duplex(dev);
-		return 0;
-	}
-
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info;
-		memset(&info, 0, sizeof(info));
-		info.cmd = ecmd.cmd;
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		*info.fw_version = 0;
-		strcpy(info.bus_info, pci_name(tp->pdev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-		       return -EFAULT;
-		return 0;
 	}
+	check_duplex(dev);
+	return 0;
+}
 
-	default:
-		return -EOPNOTSUPP;
-	}
+static void xircom_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct xircom_private *tp = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(tp->pdev));
 }
 
+static struct ethtool_ops ops = {
+	.get_settings = xircom_get_settings,
+	.set_settings = xircom_set_settings,
+	.get_drvinfo = xircom_get_drvinfo,
+};
 
 /* Provide ioctl() calls to examine the MII xcvr state. */
 static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	u16 *data = (u16 *)&rq->ifr_ifru;
 	int phy = tp->phys[0] & 0x1f;
 	unsigned long flags;
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return xircom_ethtool_ioctl(dev, rq->ifr_data);
-
 	/* Legacy mii-diag interface */
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 		if (tp->mii_cnt)
@@ -1531,7 +1517,7 @@ static int xircom_ioctl(struct net_devic
    when re-entered but still correct. */
 static void set_rx_mode(struct net_device *dev)
 {
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	struct dev_mc_list *mclist;
 	long ioaddr = dev->base_addr;
 	int csr6 = inl(ioaddr + CSR6);
@@ -1672,7 +1658,7 @@ MODULE_DEVICE_TABLE(pci, xircom_pci_tabl
 static int xircom_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);
 	if (tp->open)
 		xircom_down(dev);
@@ -1688,7 +1674,7 @@ static int xircom_suspend(struct pci_dev
 static int xircom_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xircom_private *tp = dev->priv;
+	struct xircom_private *tp = netdev_priv(dev);
 	printk(KERN_INFO "xircom_resume(%s)\n", dev->name);
 
 	pci_set_power_state(pdev,0);
diff -puN drivers/net/typhoon.c~bk-netdev drivers/net/typhoon.c
--- 25/drivers/net/typhoon.c~bk-netdev	2004-09-06 18:43:15.649891240 -0700
+++ 25-akpm/drivers/net/typhoon.c	2004-09-06 18:43:15.835862968 -0700
@@ -688,7 +688,7 @@ out:
 static void
 typhoon_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct cmd_desc xp_cmd;
 	int err;
 
@@ -726,7 +726,7 @@ typhoon_vlan_rx_register(struct net_devi
 static void
 typhoon_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	spin_lock_bh(&tp->state_lock);
 	if(tp->vlgrp)
 		tp->vlgrp->vlan_devices[vid] = NULL;
@@ -757,7 +757,7 @@ typhoon_tso_fill(struct sk_buff *skb, st
 static int
 typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct transmit_ring *txRing;
 	struct tx_desc *txd, *first_txd;
 	dma_addr_t skb_dma;
@@ -908,7 +908,7 @@ typhoon_start_tx(struct sk_buff *skb, st
 static void
 typhoon_set_rx_mode(struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct cmd_desc xp_cmd;
 	u32 mc_filter[2];
 	u16 filter;
@@ -1002,7 +1002,7 @@ typhoon_do_get_stats(struct typhoon *tp)
 static struct net_device_stats *
 typhoon_get_stats(struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct net_device_stats *stats = &tp->stats;
 	struct net_device_stats *saved = &tp->stats_saved;
 
@@ -1155,90 +1155,55 @@ typhoon_ethtool_sset(struct typhoon *tp,
 	return 0;
 }
 
-static inline int
-typhoon_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
-	u32 ethcmd;
-
-	if(copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-
-			typhoon_ethtool_gdrvinfo(tp, &info);
-			if(copy_to_user(useraddr, &info, sizeof(info)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GSET: {
-			struct ethtool_cmd cmd = { ETHTOOL_GSET };
-
-			typhoon_ethtool_gset(tp, &cmd);
-			if(copy_to_user(useraddr, &cmd, sizeof(cmd)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_SSET: {
-			struct ethtool_cmd cmd;
-			if(copy_from_user(&cmd, useraddr, sizeof(cmd)))
-				return -EFAULT;
-
-			return typhoon_ethtool_sset(tp, &cmd);
-		}
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-
-			edata.data = netif_carrier_ok(dev) ? 1 : 0;
-			if(copy_to_user(useraddr, &edata, sizeof(edata)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GWOL: {
-			struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
-
-			if(tp->wol_events & TYPHOON_WAKE_LINK_EVENT)
-				wol.wolopts |= WAKE_PHY;
-			if(tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
-				wol.wolopts |= WAKE_MAGIC;
-			if(copy_to_user(useraddr, &wol, sizeof(wol)))
-				return -EFAULT;
-			return 0;
-	}
-	case ETHTOOL_SWOL: {
-			struct ethtool_wolinfo wol;
-
-			if(copy_from_user(&wol, useraddr, sizeof(wol)))
-				return -EFAULT;
-			tp->wol_events = 0;
-			if(wol.wolopts & WAKE_PHY)
-				tp->wol_events |= TYPHOON_WAKE_LINK_EVENT;
-			if(wol.wolopts & WAKE_MAGIC)
-				tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT;
-			return 0;
-	}
-	default:
-		break;
-	}
+	struct typhoon *tp = netdev_priv(dev);
+	typhoon_ethtool_gdrvinfo(tp, info);
+}
 
-	return -EOPNOTSUPP;
+static int typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct typhoon *tp = netdev_priv(dev);
+	typhoon_ethtool_gset(tp, cmd);
+	return 0;
 }
 
-static int
-typhoon_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+static int typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return typhoon_ethtool_ioctl(dev, ifr->ifr_data);
-	default:
-		break;
-	}
+	struct typhoon *tp = netdev_priv(dev);
+	typhoon_ethtool_sset(tp, cmd);
+	return 0;
+}
 
-	return -EOPNOTSUPP;
+static void typhoon_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct typhoon *tp = netdev_priv(dev);
+	if (tp->wol_events & TYPHOON_WAKE_LINK_EVENT)
+		wol->wolopts |= WAKE_PHY;
+	if (tp->wol_events & TYPHOON_WAKE_MAGIC_PKT)
+		wol->wolopts |= WAKE_MAGIC;
+}
+
+static int typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+	struct typhoon *tp = netdev_priv(dev);
+	tp->wol_events = 0;
+	if (wol->wolopts & WAKE_PHY)
+		tp->wol_events |= TYPHOON_WAKE_LINK_EVENT;
+	if (wol->wolopts & WAKE_MAGIC)
+		tp->wol_events |= TYPHOON_WAKE_MAGIC_PKT;
+	return 0;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = typhoon_get_drvinfo,
+	.get_settings = typhoon_get_settings,
+	.set_settings = typhoon_set_settings,
+	.get_link = ethtool_op_get_link,
+	.get_wol = typhoon_get_wol,
+	.set_wol = typhoon_set_wol,
+};
+
 static int
 typhoon_wait_interrupt(unsigned long ioaddr)
 {
@@ -1756,7 +1721,7 @@ typhoon_fill_free_ring(struct typhoon *t
 static int
 typhoon_poll(struct net_device *dev, int *total_budget)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct typhoon_indexes *indexes = tp->indexes;
 	int orig_budget = *total_budget;
 	int budget, work_done, done;
@@ -2068,7 +2033,7 @@ typhoon_stop_runtime(struct typhoon *tp,
 static void
 typhoon_tx_timeout(struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 
 	if(typhoon_reset(dev->base_addr, WaitNoSleep) < 0) {
 		printk(KERN_WARNING "%s: could not reset in tx timeout\n",
@@ -2098,7 +2063,7 @@ truely_dead:
 static int
 typhoon_open(struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	int err;
 
 	err = typhoon_wakeup(tp, WaitSleep);
@@ -2140,7 +2105,7 @@ out:
 static int
 typhoon_close(struct net_device *dev)
 {
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
 
@@ -2168,7 +2133,7 @@ static int
 typhoon_resume(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 
 	/* If we're down, resume when we are upped.
 	 */
@@ -2200,7 +2165,7 @@ static int
 typhoon_suspend(struct pci_dev *pdev, u32 state)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct typhoon *tp = (struct typhoon *) dev->priv;
+	struct typhoon *tp = netdev_priv(dev);
 	struct cmd_desc xp_cmd;
 
 	/* If we're down, we're already suspended.
@@ -2366,7 +2331,7 @@ typhoon_init_one(struct pci_dev *pdev, c
 	}
 
 	dev->irq = pdev->irq;
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	tp->shared = (struct typhoon_shared *) shared;
 	tp->shared_dma = shared_dma;
 	tp->pdev = pdev;
@@ -2464,9 +2429,9 @@ typhoon_init_one(struct pci_dev *pdev, c
 	dev->watchdog_timeo	= TX_TIMEOUT;
 	dev->get_stats		= typhoon_get_stats;
 	dev->set_mac_address	= typhoon_set_mac_address;
-	dev->do_ioctl		= typhoon_ioctl;
 	dev->vlan_rx_register	= typhoon_vlan_rx_register;
 	dev->vlan_rx_kill_vid	= typhoon_vlan_rx_kill_vid;
+	SET_ETHTOOL_OPS(dev, &ops);
 
 	/* We can handle scatter gather, up to 16 entries, and
 	 * we can do IP checksumming (only version 4, doh...)
@@ -2537,7 +2502,7 @@ static void __devexit
 typhoon_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct typhoon *tp = (struct typhoon *) (dev->priv);
+	struct typhoon *tp = netdev_priv(dev);
 
 	unregister_netdev(dev);
 	pci_set_power_state(pdev, 0);
diff -puN drivers/net/wan/lmc/lmc_main.c~bk-netdev drivers/net/wan/lmc/lmc_main.c
--- 25/drivers/net/wan/lmc/lmc_main.c~bk-netdev	2004-09-06 18:43:15.663889112 -0700
+++ 25-akpm/drivers/net/wan/lmc/lmc_main.c	2004-09-06 18:43:15.837862664 -0700
@@ -101,7 +101,6 @@ static int lmc_open(struct net_device *d
 static int lmc_close(struct net_device *dev);
 static struct net_device_stats *lmc_get_stats(struct net_device *dev);
 static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
-static int lmc_set_config(struct net_device *dev, struct ifmap *map);
 static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
 static void lmc_softreset(lmc_softc_t * const);
 static void lmc_running_reset(struct net_device *dev);
@@ -814,7 +813,6 @@ static void lmc_setup(struct net_device 
     dev->stop = lmc_close;
     dev->get_stats = lmc_get_stats;
     dev->do_ioctl = lmc_ioctl;
-    dev->set_config = lmc_set_config;
     dev->tx_timeout = lmc_driver_timeout;
     dev->watchdog_timeo = (HZ); /* 1 second */
     
@@ -1975,13 +1973,6 @@ static void lmc_softreset (lmc_softc_t *
     lmc_trace(sc->lmc_device, "lmc_softreset out");
 }
 
-static int lmc_set_config(struct net_device *dev, struct ifmap *map) /*fold00*/
-{
-    lmc_trace(dev, "lmc_set_config in");
-    lmc_trace(dev, "lmc_set_config out");
-    return -EOPNOTSUPP;
-}
-
 void lmc_gpio_mkinput(lmc_softc_t * const sc, u_int32_t bits) /*fold00*/
 {
     lmc_trace(sc->lmc_device, "lmc_gpio_mkinput in");
diff -puN drivers/net/wireless/airo.c~bk-netdev drivers/net/wireless/airo.c
--- 25/drivers/net/wireless/airo.c~bk-netdev	2004-09-06 18:43:15.666888656 -0700
+++ 25-akpm/drivers/net/wireless/airo.c	2004-09-06 18:43:15.843861752 -0700
@@ -1189,6 +1189,7 @@ struct airo_info {
 	struct iw_statistics	wstats;		// wireless stats
 	unsigned long		scan_timestamp;	/* Time started to scan */
 	struct iw_spy_data	spy_data;
+	struct iw_public_data	wireless_data;
 #endif /* WIRELESS_EXT */
 #ifdef MICSUPPORT
 	/* MIC stuff */
@@ -2627,8 +2628,7 @@ static void wifi_setup(struct net_device
 	dev->set_mac_address = &airo_set_mac_address;
 	dev->do_ioctl = &airo_ioctl;
 #ifdef WIRELESS_EXT
-	dev->get_wireless_stats = airo_get_wireless_stats;
-	dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
+	dev->wireless_handlers = &airo_handler_def;
 #endif /* WIRELESS_EXT */
 	dev->change_mtu = &airo_change_mtu;
 	dev->open = &airo_open;
@@ -2655,6 +2655,9 @@ static struct net_device *init_wifidev(s
 	dev->priv = ethdev->priv;
 	dev->irq = ethdev->irq;
 	dev->base_addr = ethdev->base_addr;
+#ifdef WIRELESS_EXT
+	dev->wireless_data = ethdev->wireless_data;
+#endif /* WIRELESS_EXT */
 	memcpy(dev->dev_addr, ethdev->dev_addr, dev->addr_len);
 	err = register_netdev(dev);
 	if (err<0) {
@@ -2734,8 +2737,9 @@ struct net_device *_init_airo_card( unsi
 	dev->set_mac_address = &airo_set_mac_address;
 	dev->do_ioctl = &airo_ioctl;
 #ifdef WIRELESS_EXT
-	dev->get_wireless_stats = airo_get_wireless_stats;
-	dev->wireless_handlers = (struct iw_handler_def *)&airo_handler_def;
+	dev->wireless_handlers = &airo_handler_def;
+	ai->wireless_data.spy_data = &ai->spy_data;
+	dev->wireless_data = &ai->wireless_data;
 #endif /* WIRELESS_EXT */
 	dev->change_mtu = &airo_change_mtu;
 	dev->open = &airo_open;
@@ -3218,7 +3222,7 @@ badrx:
 					goto exitrx;
 				}
 			}
-#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+#ifdef WIRELESS_SPY
 			if (apriv->spy_data.spy_number > 0) {
 				char *sa;
 				struct iw_quality wstats;
@@ -3238,7 +3242,7 @@ badrx:
 				/* Update spy records */
 				wireless_spy_update(dev, sa, &wstats);
 			}
-#endif /* IW_WIRELESS_SPY */
+#endif /* WIRELESS_SPY */
 			OUT4500( apriv, EVACK, EV_RX);
 
 			if (test_bit(FLAG_802_11, &apriv->flags)) {
@@ -3468,7 +3472,7 @@ badmic:
 #else
 		memcpy(buffer, ai->rxfids[0].virtual_host_addr, len);
 #endif
-#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+#ifdef WIRELESS_SPY
 		if (ai->spy_data.spy_number > 0) {
 			char *sa;
 			struct iw_quality wstats;
@@ -3480,7 +3484,7 @@ badmic:
 			/* Update spy records */
 			wireless_spy_update(ai->dev, sa, &wstats);
 		}
-#endif /* IW_WIRELESS_SPY */
+#endif /* WIRELESS_SPY */
 
 		skb->dev = ai->dev;
 		skb->ip_summed = CHECKSUM_NONE;
@@ -6506,6 +6510,13 @@ static int airo_get_range(struct net_dev
 		range->avg_qual.level = 176;	/* -80 dBm */
 	range->avg_qual.noise = 0;
 
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+				IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+				IW_EVENT_CAPA_MASK(SIOCGIWAP) |
+				IW_EVENT_CAPA_MASK(SIOCGIWSCAN));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+	range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVTXDROP);
 	return 0;
 }
 
@@ -6873,9 +6884,15 @@ static int airo_get_scan(struct net_devi
 	while((!rc) && (BSSList.index != 0xffff)) {
 		/* Translate to WE format this entry */
 		current_ev = airo_translate_scan(dev, current_ev,
-						 extra + IW_SCAN_MAX_DATA,
+						 extra + dwrq->length,
 						 &BSSList);
 
+		/* Check if there is space for one more entry */
+		if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
+			/* Ask user space to try again with a bigger buffer */
+			return -E2BIG;
+		}
+
 		/* Read next entry */
 		rc = PC4500_readrid(ai, RID_BSSLISTNEXT,
 				    &BSSList, sizeof(BSSList), 1);
@@ -7011,12 +7028,10 @@ static const struct iw_handler_def	airo_
 	.num_standard	= sizeof(airo_handler)/sizeof(iw_handler),
 	.num_private	= sizeof(airo_private_handler)/sizeof(iw_handler),
 	.num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
-	.standard	= (iw_handler *) airo_handler,
-	.private	= (iw_handler *) airo_private_handler,
-	.private_args	= (struct iw_priv_args *) airo_private_args,
-	.spy_offset	= ((void *) (&((struct airo_info *) NULL)->spy_data) -
-			   (void *) NULL),
-
+	.standard	= airo_handler,
+	.private	= airo_private_handler,
+	.private_args	= airo_private_args,
+	.get_wireless_stats = airo_get_wireless_stats,
 };
 
 #endif /* WIRELESS_EXT */
diff -puN drivers/net/wireless/netwave_cs.c~bk-netdev drivers/net/wireless/netwave_cs.c
--- 25/drivers/net/wireless/netwave_cs.c~bk-netdev	2004-09-06 18:43:15.668888352 -0700
+++ 25-akpm/drivers/net/wireless/netwave_cs.c	2004-09-06 18:43:15.846861296 -0700
@@ -219,7 +219,6 @@ static void netwave_reset(struct net_dev
 /* Misc device stuff */
 static int netwave_open(struct net_device *dev);  /* Open the device */
 static int netwave_close(struct net_device *dev); /* Close the device */
-static int netwave_config(struct net_device *dev, struct ifmap *map);
 
 /* Packet transmission and Packet reception */
 static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
@@ -482,7 +481,6 @@ static dev_link_t *netwave_attach(void)
     /* Netwave specific entries in the device structure */
     SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &netwave_start_xmit;
-    dev->set_config = &netwave_config;
     dev->get_stats  = &netwave_get_stats;
     dev->set_multicast_list = &set_multicast_list;
     /* wireless extensions */
@@ -1289,16 +1287,6 @@ static void netwave_reset(struct net_dev
 }
 
 /*
- * Function netwave_config (dev, map)
- *
- *    Configure device, this work is done by netwave_pcmcia_config when a
- *    card is inserted
- */
-static int netwave_config(struct net_device *dev, struct ifmap *map) {
-    return 0; 
-}
-
-/*
  * Function netwave_hw_xmit (data, len, dev)    
  */
 static int netwave_hw_xmit(unsigned char* data, int len,
diff -puN drivers/net/wireless/prism54/isl_38xx.c~bk-netdev drivers/net/wireless/prism54/isl_38xx.c
--- 25/drivers/net/wireless/prism54/isl_38xx.c~bk-netdev	2004-09-06 18:43:15.682886224 -0700
+++ 25-akpm/drivers/net/wireless/prism54/isl_38xx.c	2004-09-06 18:43:15.847861144 -0700
@@ -133,8 +133,8 @@ isl38xx_trigger_device(int asleep, void 
 		      readl(device_base + ISL38XX_CTRL_STAT_REG));
 		udelay(ISL38XX_WRITEIO_DELAY);
 
-		if (reg = readl(device_base + ISL38XX_INT_IDENT_REG),
-		    reg == 0xabadface) {
+		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
+		if (reg == 0xabadface) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
 			do_gettimeofday(&current_time);
 			DEBUG(SHOW_TRACING,
@@ -192,10 +192,8 @@ isl38xx_trigger_device(int asleep, void 
 void
 isl38xx_interface_reset(void *device_base, dma_addr_t host_address)
 {
-	u32 reg;
-
 #if VERBOSE > SHOW_ERROR_MESSAGES
-	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n");
+	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
 #endif
 
 	/* load the address of the control block in the device */
@@ -203,8 +201,7 @@ isl38xx_interface_reset(void *device_bas
 	udelay(ISL38XX_WRITEIO_DELAY);
 
 	/* set the reset bit in the Device Interrupt Register */
-	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET,
-			  ISL38XX_DEV_INT_REG);
+	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);
 
 	/* enable the interrupt for detecting initialization */
@@ -212,9 +209,7 @@ isl38xx_interface_reset(void *device_bas
 	/* Note: Do not enable other interrupts here. We want the
 	 * device to have come up first 100% before allowing any other 
 	 * interrupts. */
-	reg = ISL38XX_INT_IDENT_INIT;
-
-	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
+	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
 	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
 }
 
diff -puN drivers/net/wireless/prism54/isl_38xx.h~bk-netdev drivers/net/wireless/prism54/isl_38xx.h
--- 25/drivers/net/wireless/prism54/isl_38xx.h~bk-netdev	2004-09-06 18:43:15.683886072 -0700
+++ 25-akpm/drivers/net/wireless/prism54/isl_38xx.h	2004-09-06 18:43:15.847861144 -0700
@@ -95,6 +95,10 @@ isl38xx_w32_flush(void *base, u32 val, u
 #define ISL38XX_INT_SOURCES                     0x001E
 
 /* Control/Status register bits */
+/* Looks like there are other meaningful bits
+    0x20004400 seen in normal operation,
+    0x200044db at 'timeout waiting for mgmt response'
+*/
 #define ISL38XX_CTRL_STAT_SLEEPMODE             0x00000200
 #define	ISL38XX_CTRL_STAT_CLKRUN		0x00800000
 #define ISL38XX_CTRL_STAT_RESET                 0x10000000
diff -puN drivers/net/wireless/prism54/isl_ioctl.c~bk-netdev drivers/net/wireless/prism54/isl_ioctl.c
--- 25/drivers/net/wireless/prism54/isl_ioctl.c~bk-netdev	2004-09-06 18:43:15.685885768 -0700
+++ 25-akpm/drivers/net/wireless/prism54/isl_ioctl.c	2004-09-06 18:43:15.852860384 -0700
@@ -36,38 +36,6 @@
 
 #include <net/iw_handler.h>	/* New driver API */
 
-static int init_mode = CARD_DEFAULT_IW_MODE;
-static int init_channel = CARD_DEFAULT_CHANNEL;
-static int init_wep = CARD_DEFAULT_WEP;
-static int init_filter = CARD_DEFAULT_FILTER;
-static int init_authen = CARD_DEFAULT_AUTHEN;
-static int init_dot1x = CARD_DEFAULT_DOT1X;
-static int init_conformance = CARD_DEFAULT_CONFORMANCE;
-static int init_mlme = CARD_DEFAULT_MLME_MODE;
-
-module_param(init_mode, int, 0);
-MODULE_PARM_DESC(init_mode,
-		 "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor");
-
-module_param(init_channel, int, 0);
-MODULE_PARM_DESC(init_channel,
-		 "Check `iwpriv ethx channel` for available channels");
-
-module_param(init_wep, int, 0);
-module_param(init_filter, int, 0);
-
-module_param(init_authen, int, 0);
-MODULE_PARM_DESC(init_authen,
-		 "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH");
-
-module_param(init_dot1x, int, 0);
-MODULE_PARM_DESC(init_dot1x,
-		 "\n0: None/not set	(Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
-
-module_param(init_mlme, int, 0);
-MODULE_PARM_DESC(init_mlme,
-		 "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED");
-
 /**
  * prism54_mib_mode_helper - MIB change mode helper function
  * @mib: the &struct islpci_mib object to modify
@@ -141,36 +109,34 @@ prism54_mib_mode_helper(islpci_private *
 void
 prism54_mib_init(islpci_private *priv)
 {
-	u32 t;
+	u32 channel, authen, wep, filter, dot1x, mlme, conformance, power, mode;
 	struct obj_buffer psm_buffer = {
 		.size = PSM_BUFFER_SIZE,
 		.addr = priv->device_psm_buffer
 	};
 
-	mgt_set(priv, DOT11_OID_CHANNEL, &init_channel);
-	mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen);
-	mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep);
-
+	channel = CARD_DEFAULT_CHANNEL;
+	authen = CARD_DEFAULT_AUTHEN;
+	wep = CARD_DEFAULT_WEP;
+	filter = CARD_DEFAULT_FILTER; /* (0) Do not filter un-encrypted data */
+	dot1x = CARD_DEFAULT_DOT1X; 
+	mlme = CARD_DEFAULT_MLME_MODE;
+	conformance = CARD_DEFAULT_CONFORMANCE;
+	power = 127;
+	mode = CARD_DEFAULT_IW_MODE;
+
+	mgt_set(priv, DOT11_OID_CHANNEL, &channel);
+	mgt_set(priv, DOT11_OID_AUTHENABLE, &authen);
+	mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &wep);
 	mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer);
-	mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter);
-	mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x);
-	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme);
-	mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance);
-
-	t = 127;
-	mgt_set(priv, OID_INL_OUTPUTPOWER, &t);
-
-	/* Important: we are setting a default wireless mode and we are 
-	 * forcing a valid one, so prism54_mib_mode_helper should just set
-	 * mib values depending on what the wireless mode given is. No need
-	 * for it save old values */
-	if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) {
-		printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. "
-		       "Using default mode\n", __FUNCTION__);
-		init_mode = CARD_DEFAULT_IW_MODE;
-	}
+	mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &filter);
+	mgt_set(priv, DOT11_OID_DOT1XENABLE, &dot1x);
+	mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlme);
+	mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &conformance);
+	mgt_set(priv, OID_INL_OUTPUTPOWER, &power);
+
 	/* This sets all of the mode-dependent values */
-	prism54_mib_mode_helper(priv, init_mode);
+	prism54_mib_mode_helper(priv, mode);
 }
 
 /* this will be executed outside of atomic context thanks to
@@ -485,6 +451,15 @@ prism54_get_range(struct net_device *nde
 	/* txpower is supported in dBm's */
 	range->txpower_capa = IW_TXPOW_DBM;
 
+#if WIRELESS_EXT > 16
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_K_0 |
+	IW_EVENT_CAPA_MASK(SIOCGIWTHRSPY) |
+	IW_EVENT_CAPA_MASK(SIOCGIWAP));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+	range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+#endif /* WIRELESS_EXT > 16 */
+
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return 0;
 
@@ -629,8 +604,8 @@ prism54_translate_bss(struct net_device 
 	current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL);
 
 	/* Add frequency. (short) bss->channel is the frequency in MHz */
-	iwe.u.freq.m = channel_of_freq(bss->channel);
-	iwe.u.freq.e = 0;
+	iwe.u.freq.m = bss->channel;
+	iwe.u.freq.e = 6;
 	iwe.cmd = SIOCGIWFREQ;
 	current_ev =
 	    iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN);
@@ -690,19 +665,33 @@ prism54_get_scan(struct net_device *ndev
 	rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
 	noise = r.u;
 
-	/* Ask the device for a list of known bss. We can report at most
-	 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
-	 * if you change the value of IWMAX_BSS=24.
-	 */
+	/* Ask the device for a list of known bss.
+	* The old API, using SIOCGIWAPLIST, had a hard limit of IW_MAX_AP=64.
+	* The new API, using SIOCGIWSCAN, is only limited by the buffer size.
+	* WE-14->WE-16, the buffer is limited to IW_SCAN_MAX_DATA bytes.
+	* Starting with WE-17, the buffer can be as big as needed.
+	* But the device won't repport anything if you change the value
+	* of IWMAX_BSS=24. */
+	
 	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
 	bsslist = r.ptr;
 
 	/* ok now, scan the list and translate its info */
-	for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
+	for (i = 0; i < (int) bsslist->nr; i++) {
 		current_ev = prism54_translate_bss(ndev, current_ev,
-						   extra + IW_SCAN_MAX_DATA,
+						   extra + dwrq->length,
 						   &(bsslist->bsslist[i]),
 						   noise);
+#if WIRELESS_EXT > 16
+		/* Check if there is space for one more entry */
+		if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) {
+			/* Ask user space to try again with a bigger buffer */
+			rvalue = -E2BIG;
+			break;
+		}
+#endif /* WIRELESS_EXT > 16 */
+	}
+
 	kfree(bsslist);
 	dwrq->length = (current_ev - extra);
 	dwrq->flags = 0;	/* todo */
@@ -1746,11 +1735,13 @@ prism54_process_trap_helper(islpci_priva
 			    char *data)
 {
 	struct obj_mlme *mlme = (struct obj_mlme *) data;
-	size_t len;
-	u8 *payload, *pos = (u8 *) (mlme + 1);
-
-	len = pos[0] | (pos[1] << 8);	/* little endian data length */
-	payload = pos + 2;
+	struct obj_mlmeex *mlmeex = (struct obj_mlmeex *) data;
+	struct obj_mlmeex *confirm;
+	u8 wpa_ie[MAX_WPA_IE_LEN];
+	int wpa_ie_len;
+	size_t len = 0; /* u16, better? */
+	u8 *payload = 0, *pos = 0;
+	int ret;
 
 	/* I think all trapable objects are listed here.
 	 * Some oids have a EX version. The difference is that they are emitted
@@ -1760,9 +1751,14 @@ prism54_process_trap_helper(islpci_priva
 	 * suited. We use the more flexible custom event facility.
 	 */
 
+	if (oid >= DOT11_OID_BEACON) {
+		len = mlmeex->size;
+		payload = pos = mlmeex->data;
+	}
+
 	/* I fear prism54_process_bss_data won't work with big endian data */
 	if ((oid == DOT11_OID_BEACON) || (oid == DOT11_OID_PROBE))
-		prism54_process_bss_data(priv, oid, mlme->address,
+		prism54_process_bss_data(priv, oid, mlmeex->address,
 					 payload, len);
 
 	mgt_le_to_cpu(isl_oid[oid].flags & OID_FLAG_TYPE, (void *) mlme);
@@ -1822,21 +1818,134 @@ prism54_process_trap_helper(islpci_priva
 
 	case DOT11_OID_AUTHENTICATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Authenticate request", mlme, 1);
+		send_formatted_event(priv, "Authenticate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_AUTHING)
+			break;
+
+		confirm = kmalloc(sizeof(struct obj_mlmeex) + 6, GFP_ATOMIC);
+
+		if (!confirm) 
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+		printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+		confirm->id = -1; /* or mlmeex->id ? */
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+		confirm->size = 6;
+		confirm->data[0] = 0x00;
+		confirm->data[1] = 0x00;
+		confirm->data[2] = 0x02;
+		confirm->data[3] = 0x00;
+		confirm->data[4] = 0x00;
+		confirm->data[5] = 0x00;
+
+		ret = mgt_set_varlen(priv, DOT11_OID_ASSOCIATEEX, confirm, 6);
+
+		kfree(confirm);
+		if (ret)
+			return ret;
 		break;
 
 	case DOT11_OID_DISASSOCIATEEX:
-		send_formatted_event(priv, "Disassociate request", mlme, 0);
+		send_formatted_event(priv, "Disassociate request (ex)", mlme, 0);
 		break;
 
 	case DOT11_OID_ASSOCIATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Associate request", mlme, 1);
+		send_formatted_event(priv, "Associate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_AUTHING)
+			break;
+		
+		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+		if (!confirm)
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+		confirm->id = ((struct obj_mlmeex *)mlme)->id;
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+		if (!wpa_ie_len) {
+			printk(KERN_DEBUG "No WPA IE found from "
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+			kfree(confirm);
+			break;
+		}
+
+		confirm->size = wpa_ie_len;
+		memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+		kfree(confirm);
+		
 		break;
 
 	case DOT11_OID_REASSOCIATEEX:
 		handle_request(priv, mlme, oid);
-		send_formatted_event(priv, "Reassociate request", mlme, 1);
+		send_formatted_event(priv, "Reassociate request (ex)", mlme, 1);
+
+		if (priv->iw_mode != IW_MODE_MASTER 
+				&& mlmeex->state != DOT11_STATE_ASSOCING)
+			break;
+
+		confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
+
+		if (!confirm)
+			break;
+
+		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
+
+		confirm->id = mlmeex->id;
+		confirm->state = 0; /* not used */
+		confirm->code = 0;
+
+		wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+
+		if (!wpa_ie_len) {
+			printk(KERN_DEBUG "No WPA IE found from "
+					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n", 
+				mlmeex->address[0],
+				mlmeex->address[1],
+				mlmeex->address[2],
+				mlmeex->address[3],
+				mlmeex->address[4],
+				mlmeex->address[5]
+				);
+			kfree(confirm);
+			break;
+		}
+
+		confirm->size = wpa_ie_len; 
+		memcpy(&confirm->data, wpa_ie, wpa_ie_len);
+
+		mgt_set_varlen(priv, oid, confirm, wpa_ie_len);
+
+		kfree(confirm);
+		
 		break;
 
 	default:
@@ -1879,23 +1988,367 @@ prism54_set_mac_address(struct net_devic
 	return ret;
 }
 
+/* Note: currently, use hostapd ioctl from the Host AP driver for WPA
+ * support. This is to be replaced with Linux wireless extensions once they
+ * get WPA support. */
+
+/* Note II: please leave all this together as it will be easier to remove later,
+ * once wireless extensions add WPA support -mcgrof */
+
+/* PRISM54_HOSTAPD ioctl() cmd: */
+enum {
+	PRISM2_SET_ENCRYPTION = 6,
+	PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+	PRISM2_HOSTAPD_MLME = 13,
+	PRISM2_HOSTAPD_SCAN_REQ = 14,
+};
+
+#define PRISM54_SET_WPA			SIOCIWFIRSTPRIV+12
+#define PRISM54_HOSTAPD			SIOCIWFIRSTPRIV+25
+#define PRISM54_DROP_UNENCRYPTED	SIOCIWFIRSTPRIV+26
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) 
+ * used in ioctl() */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+	
+struct prism2_hostapd_param {
+	u32 cmd;
+	u8 sta_addr[ETH_ALEN];
+	union {
+	       struct {
+		       u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+		       u32 flags;
+		       u32 err;
+		       u8 idx;
+		       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+		       u16 key_len;
+		       u8 key[0];
+		       } crypt;
+               struct {
+                       u8 len;
+                       u8 data[0];
+               } generic_elem;
+               struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+                       u16 cmd;
+                       u16 reason_code;
+               } mlme;
+               struct {
+                       u8 ssid_len;
+                       u8 ssid[32];
+               } scan_req;
+       } u;
+};
+
+
+static int
+prism2_ioctl_set_encryption(struct net_device *dev,
+	struct prism2_hostapd_param *param,
+	int param_len)
+{
+	islpci_private *priv = netdev_priv(dev);
+	int rvalue = 0, force = 0;
+	int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+	union oid_res_t r;
+
+	/* with the new API, it's impossible to get a NULL pointer.
+	 * New version of iwconfig set the IW_ENCODE_NOKEY flag
+	 * when no key is given, but older versions don't. */
+
+	if (param->u.crypt.key_len > 0) {
+		/* we have a key to set */
+		int index = param->u.crypt.idx;
+		int current_index;
+		struct obj_key key = { DOT11_PRIV_TKIP, 0, "" };
+
+		/* get the current key index */
+		rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+		current_index = r.u;
+		/* Verify that the key is not marked as invalid */
+		if (!(param->u.crypt.flags & IW_ENCODE_NOKEY)) {
+			key.length = param->u.crypt.key_len > sizeof (param->u.crypt.key) ?
+			    sizeof (param->u.crypt.key) : param->u.crypt.key_len;
+			memcpy(key.key, param->u.crypt.key, key.length);
+			if (key.length == 32)
+				/* we want WPA-PSK */
+				key.type = DOT11_PRIV_TKIP;
+			if ((index < 0) || (index > 3))
+				/* no index provided use the current one */
+				index = current_index;
+
+			/* now send the key to the card  */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYX, index,
+					    &key);
+		}
+		/*
+		 * If a valid key is set, encryption should be enabled 
+		 * (user may turn it off later).
+		 * This is also how "iwconfig ethX key on" works
+		 */
+		if ((index == current_index) && (key.length > 0))
+			force = 1;
+	} else {
+		int index = (param->u.crypt.flags & IW_ENCODE_INDEX) - 1;
+		if ((index >= 0) && (index <= 3)) {
+			/* we want to set the key index */
+			rvalue |=
+			    mgt_set_request(priv, DOT11_OID_DEFKEYID, 0,
+					    &index);
+		} else {
+			if (!param->u.crypt.flags & IW_ENCODE_MODE) {
+				/* we cannot do anything. Complain. */
+				return -EINVAL;
+			}
+		}
+	}
+	/* now read the flags */
+	if (param->u.crypt.flags & IW_ENCODE_DISABLED) {
+		/* Encoding disabled, 
+		 * authen = DOT11_AUTH_OS;
+		 * invoke = 0;
+		 * exunencrypt = 0; */
+	}
+	if (param->u.crypt.flags & IW_ENCODE_OPEN)
+		/* Encode but accept non-encoded packets. No auth */
+		invoke = 1;
+	if ((param->u.crypt.flags & IW_ENCODE_RESTRICTED) || force) {
+		/* Refuse non-encoded packets. Auth */
+		authen = DOT11_AUTH_BOTH;
+		invoke = 1;
+		exunencrypt = 1;
+	}
+	/* do the change if requested  */
+	if ((param->u.crypt.flags & IW_ENCODE_MODE) || force) {
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke);
+		rvalue |=
+		    mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+				    &exunencrypt);
+	}
+	return rvalue;
+}
+
+static int
+prism2_ioctl_set_generic_element(struct net_device *ndev,
+	struct prism2_hostapd_param *param,
+	int param_len)
+{
+       islpci_private *priv = netdev_priv(ndev);
+       int max_len, len, alen, ret=0;
+       struct obj_attachment *attach;
+
+       len = param->u.generic_elem.len;
+       max_len = param_len - PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+       if (max_len < 0 || max_len < len)
+               return -EINVAL;
+
+       alen = sizeof(*attach) + len;
+       attach = kmalloc(alen, GFP_KERNEL);
+       if (attach == NULL)
+               return -ENOMEM;
+
+       memset(attach, 0, alen);
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+       /* Note: endianness is covered by mgt_set_varlen */
+
+       attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+               (WLAN_FC_STYPE_ASSOC_REQ << 4);
+       attach->id = -1;
+       attach->size = len;
+       memcpy(attach->data, param->u.generic_elem.data, len);
+
+       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+       if (ret == 0) {
+               attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+                       (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+	       ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach, len);
+
+	       if (ret == 0) 
+		       printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+				       ndev->name);
+       }
+
+       kfree(attach);
+       return ret;
+
+}
+
+static int
+prism2_ioctl_mlme(struct net_device *dev, struct prism2_hostapd_param *param)
+{
+	return -EOPNOTSUPP;
+}
+
+static int
+prism2_ioctl_scan_req(struct net_device *ndev,
+                     struct prism2_hostapd_param *param)
+{
+	islpci_private *priv = netdev_priv(ndev);
+	int i, rvalue;
+	struct obj_bsslist *bsslist;
+	u32 noise = 0;
+	char *extra = "";
+	char *current_ev = "foo";
+	union oid_res_t r;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT) {
+		/* device is not ready, fail gently */
+		return 0;
+	}
+
+	/* first get the noise value. We will use it to report the link quality */
+	rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r);
+	noise = r.u;
+
+	/* Ask the device for a list of known bss. We can report at most
+	 * IW_MAX_AP=64 to the range struct. But the device won't repport anything
+	 * if you change the value of IWMAX_BSS=24.
+	 */
+	rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r);
+	bsslist = r.ptr;
+
+	/* ok now, scan the list and translate its info */
+	for (i = 0; i < min(IW_MAX_AP, (int) bsslist->nr); i++)
+		current_ev = prism54_translate_bss(ndev, current_ev,
+						   extra + IW_SCAN_MAX_DATA,
+						   &(bsslist->bsslist[i]),
+						   noise);
+	kfree(bsslist);
+
+	return rvalue;
+}
+
+static int
+prism54_hostapd(struct net_device *ndev, struct iw_point *p)
+{
+       struct prism2_hostapd_param *param;
+       int ret = 0;
+       u32 uwrq;
+
+       printk(KERN_DEBUG "prism54_hostapd - len=%d\n", p->length);
+       if (p->length < sizeof(struct prism2_hostapd_param) ||
+           p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
+               return -EINVAL;
+
+       param = (struct prism2_hostapd_param *) kmalloc(p->length, GFP_KERNEL);
+       if (param == NULL)
+               return -ENOMEM;
+
+       if (copy_from_user(param, p->pointer, p->length)) {
+               kfree(param);
+               return -EFAULT;
+       }
+
+       switch (param->cmd) {
+       case PRISM2_SET_ENCRYPTION:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant set encryption request\n",
+			       ndev->name);
+               ret = prism2_ioctl_set_encryption(ndev, param, p->length);
+               break;
+       case PRISM2_HOSTAPD_SET_GENERIC_ELEMENT:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant set WPA IE request\n",
+			       ndev->name);
+               ret = prism2_ioctl_set_generic_element(ndev, param,
+                                                      p->length);
+               break;
+       case PRISM2_HOSTAPD_MLME:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant MLME request\n",
+			       ndev->name);
+               ret = prism2_ioctl_mlme(ndev, param);
+               break;
+       case PRISM2_HOSTAPD_SCAN_REQ:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant scan request\n",
+			       ndev->name);
+               ret = prism2_ioctl_scan_req(ndev, param);
+               break;
+	case PRISM54_SET_WPA:
+	       printk(KERN_DEBUG "%s: Caught WPA supplicant wpa init request\n",
+			       ndev->name);
+	       uwrq = 1;
+	       ret = prism54_set_wpa(ndev, NULL, &uwrq, NULL);
+	       break;
+	case PRISM54_DROP_UNENCRYPTED:
+	       printk(KERN_DEBUG "%s: Caught WPA drop unencrypted request\n",
+			       ndev->name);
+#if 0
+	       uwrq = 0x01;
+	       mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &uwrq);
+	       down_write(&priv->mib_sem);
+	       mgt_commit(priv);
+	       up_write(&priv->mib_sem);
+#endif
+	       /* Not necessary, as set_wpa does it, should we just do it here though? */
+	       ret = 0;
+	       break;
+       default:
+	       printk(KERN_DEBUG "%s: Caught a WPA supplicant request that is not supported\n",
+			       ndev->name);
+               ret = -EOPNOTSUPP;
+               break;
+       }
+
+       if (ret == 0 && copy_to_user(p->pointer, param, p->length))
+               ret = -EFAULT;
+
+       kfree(param);
+
+       return ret;
+}
+
 int
 prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
 		__u32 * uwrq, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
+	u32 mlme, authen, dot1x, filter, wep;
 
-	down_write(&priv->mib_sem);
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return 0;
+
+	wep = 1; /* For privacy invoked */
+	filter = 1; /* Filter out all unencrypted frames */
+	dot1x = 0x01; /* To enable eap filter */
+	mlme = DOT11_MLME_EXTENDED;
+	authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
 
+	down_write(&priv->mib_sem);
 	priv->wpa = *uwrq;
-	if (priv->wpa) {
-		u32 l = DOT11_MLME_EXTENDED;
-		mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l);
+
+	switch (priv->wpa) {
+		default:
+		case 0: /* Clears/disables WPA and friends */
+			wep = 0;
+			filter = 0; /* Do not filter un-encrypted data */
+			dot1x = 0;
+			mlme = DOT11_MLME_AUTO;
+			printk("%s: Disabling WPA\n", ndev->name);
+			break;
+		case 2: 
+		case 1: /* WPA */
+			printk("%s: Enabling WPA\n", ndev->name);
+			break;
 	}
-	/* restart the card with new level. Needed ? */
-	mgt_commit(priv);
 	up_write(&priv->mib_sem);
 
+	mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+	mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &wep);
+	mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &filter);
+	mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+	mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlme);
+
 	return 0;
 }
 
@@ -1947,7 +2400,7 @@ prism54_debug_get_oid(struct net_device 
 		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	struct islpci_mgmtframe *response = NULL;
+	struct islpci_mgmtframe *response;
 	int ret = -EIO;
 
 	printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid);
@@ -1983,7 +2436,7 @@ prism54_debug_set_oid(struct net_device 
 		      struct iw_point *data, char *extra)
 {
 	islpci_private *priv = netdev_priv(ndev);
-	struct islpci_mgmtframe *response = NULL;
+	struct islpci_mgmtframe *response;
 	int ret = 0, response_op = PIMFOR_OP_ERROR;
 
 	printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid,
@@ -2256,14 +2709,24 @@ const struct iw_handler_def prism54_hand
 	.standard = (iw_handler *) prism54_handler,
 	.private = (iw_handler *) prism54_private_handler,
 	.private_args = (struct iw_priv_args *) prism54_private_args,
+#if WIRELESS_EXT == 16
 	.spy_offset = offsetof(islpci_private, spy_data),
+#endif /* WIRELESS_EXT == 16 */
 };
 
-/* For ioctls that don't work with the new API */
+/* For wpa_supplicant */
 
 int
 prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
 {
-
+	struct iwreq *wrq = (struct iwreq *) rq;
+	int ret = -1;
+	switch (cmd) {
+		case PRISM54_HOSTAPD:
+		if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+		ret = prism54_hostapd(ndev, &wrq->u.data);
+		return ret;
+	}
 	return -EOPNOTSUPP;
 }
diff -puN drivers/net/wireless/prism54/isl_ioctl.h~bk-netdev drivers/net/wireless/prism54/isl_ioctl.h
--- 25/drivers/net/wireless/prism54/isl_ioctl.h~bk-netdev	2004-09-06 18:43:15.686885616 -0700
+++ 25-akpm/drivers/net/wireless/prism54/isl_ioctl.h	2004-09-06 18:43:15.853860232 -0700
@@ -48,6 +48,8 @@ size_t prism54_wpa_ie_get(islpci_private
 int prism54_set_mac_address(struct net_device *, void *);
 
 int prism54_ioctl(struct net_device *, struct ifreq *, int);
+int prism54_set_wpa(struct net_device *, struct iw_request_info *, 
+			__u32 *, char *);
 
 extern const struct iw_handler_def prism54_handler_def;
 
diff -puN drivers/net/wireless/prism54/isl_oid.h~bk-netdev drivers/net/wireless/prism54/isl_oid.h
--- 25/drivers/net/wireless/prism54/isl_oid.h~bk-netdev	2004-09-06 18:43:15.688885312 -0700
+++ 25-akpm/drivers/net/wireless/prism54/isl_oid.h	2004-09-06 18:43:15.853860232 -0700
@@ -91,6 +91,14 @@ struct obj_frequencies {
 	u16 mhz[0];
 } __attribute__ ((packed));
 
+struct obj_attachment {
+	char type;
+	char reserved;
+	short id;
+	short size;
+	char data[0];
+} __attribute__((packed));
+
 /* 
  * in case everything's ok, the inlined function below will be
  * optimized away by the compiler...
@@ -472,6 +480,7 @@ enum oid_num_t {
 #define OID_TYPE_MLMEEX		0x09
 #define OID_TYPE_ADDR		0x0A
 #define OID_TYPE_RAW		0x0B
+#define OID_TYPE_ATTACH		0x0C
 
 /* OID_TYPE_MLMEEX is special because of a variable size field when sending.
  * Not yet implemented (not used in driver anyway).
diff -puN drivers/net/wireless/prism54/islpci_dev.c~bk-netdev drivers/net/wireless/prism54/islpci_dev.c
--- 25/drivers/net/wireless/prism54/islpci_dev.c~bk-netdev	2004-09-06 18:43:15.689885160 -0700
+++ 25-akpm/drivers/net/wireless/prism54/islpci_dev.c	2004-09-06 18:43:15.855859928 -0700
@@ -375,8 +375,6 @@ islpci_open(struct net_device *ndev)
 	u32 rc;
 	islpci_private *priv = netdev_priv(ndev);
 
-	printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
-
 	/* reset data structures, upload firmware and reset device */
 	rc = islpci_reset(priv,1);
 	if (rc) {
@@ -462,8 +460,7 @@ islpci_upload_fw(islpci_private *priv)
 		return rc;
 	}
 
-	printk(KERN_DEBUG
-	       "%s: firmware uploaded done, now triggering reset...\n",
+	printk(KERN_DEBUG "%s: firmware upload complete\n",
 	       priv->ndev->name);
 
 	islpci_set_state(priv, PRV_STATE_POSTBOOT);
@@ -499,15 +496,16 @@ islpci_reset_if(islpci_private *priv)
 		/* If we're here it's because our IRQ hasn't yet gone through. 
 		 * Retry a bit more...
 		 */
-		 printk(KERN_ERR "%s: device soft reset timed out\n",
-		       priv->ndev->name);
-
+		printk(KERN_ERR "%s: reset problem: no 'reset complete' IRQ seen\n",
+			priv->ndev->name);
 	}
 
 	finish_wait(&priv->reset_done, &wait);
 
-	if(result)
+	if (result) {
+		printk(KERN_ERR "%s: islpci_reset_if: failure\n", priv->ndev->name);
 		return result;
+	}
 
 	islpci_set_state(priv, PRV_STATE_INIT);
 
@@ -524,6 +522,7 @@ islpci_reset_if(islpci_private *priv)
 
 	islpci_set_state(priv, PRV_STATE_READY);
 
+	printk(KERN_DEBUG "%s: interface reset complete\n", priv->ndev->name);
 	return 0;
 }
 
@@ -584,18 +583,18 @@ islpci_reset(islpci_private *priv, int r
 	/* now that the data structures are cleaned up, upload
 	 * firmware and reset interface */
 		rc = islpci_upload_fw(priv);
-		if (rc) 
+		if (rc) {
+			printk(KERN_ERR "%s: islpci_reset: failure\n",
+				priv->ndev->name);
 			return rc;
+		}
 	}
 
 	/* finally reset interface */
 	rc = islpci_reset_if(priv);
-	if (!rc) /* If successful */
-		return rc;
-	
-	printk(KERN_DEBUG  "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
+	if (rc)
+		printk(KERN_ERR "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n");
 	return rc;
-
 }
 
 struct net_device_stats *
@@ -604,7 +603,7 @@ islpci_statistics(struct net_device *nde
 	islpci_private *priv = netdev_priv(ndev);
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
-	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
+	DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
 #endif
 
 	return &priv->statistics;
@@ -830,6 +829,12 @@ islpci_setup(struct pci_dev *pdev)
 	priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ?
 		priv->monitor_type : ARPHRD_ETHER;
 
+#if WIRELESS_EXT > 16
+	/* Add pointers to enable iwspy support. */
+	priv->wireless_data.spy_data = &priv->spy_data;
+	ndev->wireless_data = &priv->wireless_data;
+#endif /* WIRELESS_EXT > 16 */
+
 	/* save the start and end address of the PCI memory area */
 	ndev->mem_start = (unsigned long) priv->device_base;
 	ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE;
diff -puN drivers/net/wireless/prism54/islpci_dev.h~bk-netdev drivers/net/wireless/prism54/islpci_dev.h
--- 25/drivers/net/wireless/prism54/islpci_dev.h~bk-netdev	2004-09-06 18:43:15.690885008 -0700
+++ 25-akpm/drivers/net/wireless/prism54/islpci_dev.h	2004-09-06 18:43:15.855859928 -0700
@@ -100,6 +100,10 @@ typedef struct {
 
 	struct iw_spy_data spy_data; /* iwspy support */
 
+#if WIRELESS_EXT > 16
+	struct iw_public_data wireless_data;
+#endif /* WIRELESS_EXT > 16 */
+
 	int monitor_type; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_PRISM */
 
 	struct islpci_acl acl;
diff -puN drivers/net/wireless/prism54/islpci_eth.c~bk-netdev drivers/net/wireless/prism54/islpci_eth.c
--- 25/drivers/net/wireless/prism54/islpci_eth.c~bk-netdev	2004-09-06 18:43:15.692884704 -0700
+++ 25-akpm/drivers/net/wireless/prism54/islpci_eth.c	2004-09-06 18:43:15.856859776 -0700
@@ -508,11 +508,12 @@ islpci_eth_tx_timeout(struct net_device 
 	/* increment the transmit error counter */
 	statistics->tx_errors++;
 
+	printk(KERN_WARNING "%s: tx_timeout", ndev->name);
 	if (!priv->reset_task_pending) {
 		priv->reset_task_pending = 1;
+		printk(", scheduling a reset");
 		netif_stop_queue(ndev);
 		schedule_work(&priv->reset_task);
 	}
-
-	return;
+	printk("\n");
 }
diff -puN drivers/net/wireless/prism54/oid_mgt.c~bk-netdev drivers/net/wireless/prism54/oid_mgt.c
--- 25/drivers/net/wireless/prism54/oid_mgt.c~bk-netdev	2004-09-06 18:43:15.693884552 -0700
+++ 25-akpm/drivers/net/wireless/prism54/oid_mgt.c	2004-09-06 18:43:15.858859472 -0700
@@ -201,7 +201,8 @@ struct oid_t isl_oid[] = {
 	OID_U32(DOT11_OID_STATIMEOUT, 0x19000000),
 	OID_U32_C(DOT11_OID_MLMEAUTOLEVEL, 0x19000001),
 	OID_U32(DOT11_OID_BSSTIMEOUT, 0x19000002),
-	OID_UNKNOWN(DOT11_OID_ATTACHMENT, 0x19000003),
+	[DOT11_OID_ATTACHMENT] = {0x19000003, 0,
+		sizeof(struct obj_attachment), OID_TYPE_ATTACH},
 	OID_STRUCT_C(DOT11_OID_PSMBUFFER, 0x19000004, struct obj_buffer,
 		     OID_TYPE_BUFFER),
 
@@ -329,6 +330,12 @@ mgt_le_to_cpu(int type, void *data)
 			mlme->size = le16_to_cpu(mlme->size);
 			break;
 		}
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = data;
+			attach->id = le16_to_cpu(attach->id);
+			attach->size = le16_to_cpu(attach->size);; 
+			break;
+	}
 	case OID_TYPE_SSID:
 	case OID_TYPE_KEY:
 	case OID_TYPE_ADDR:
@@ -392,6 +399,12 @@ mgt_cpu_to_le(int type, void *data)
 			mlme->size = cpu_to_le16(mlme->size);
 			break;
 		}
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = data;
+			attach->id = cpu_to_le16(attach->id);
+			attach->size = cpu_to_le16(attach->size);; 
+			break;
+	}
 	case OID_TYPE_SSID:
 	case OID_TYPE_KEY:
 	case OID_TYPE_ADDR:
@@ -465,6 +478,42 @@ mgt_set_request(islpci_private *priv, en
 	return ret;
 }
 
+/* None of these are cached */
+int
+mgt_set_varlen(islpci_private *priv, enum oid_num_t n, void *data, int extra_len)
+{
+	int ret = 0;
+	struct islpci_mgmtframe *response;
+	int response_op = PIMFOR_OP_ERROR;
+	int dlen;
+	u32 oid;
+
+	BUG_ON(OID_NUM_LAST <= n);
+
+	dlen = isl_oid[n].size;
+	oid = isl_oid[n].oid;
+
+	mgt_cpu_to_le(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+	if (islpci_get_state(priv) >= PRV_STATE_READY) {
+		ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid,
+					     data, dlen + extra_len, &response);
+		if (!ret) {
+			response_op = response->header->operation;
+			islpci_mgt_release(response);
+		}
+		if (ret || response_op == PIMFOR_OP_ERROR)
+			ret = -EIO;
+	} else 
+		ret = -EIO;
+
+	/* re-set given data to what it was */
+	if (data)
+		mgt_le_to_cpu(isl_oid[n].flags & OID_FLAG_TYPE, data);
+
+	return ret;
+}
+
 int
 mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data,
 		union oid_res_t *res)
@@ -555,15 +604,18 @@ mgt_commit_list(islpci_private *priv, en
 		u32 oid = t->oid;
 		BUG_ON(data == NULL);
 		while (j <= t->range) {
-			response = NULL;
-			ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
+			int r = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET,
 						      oid, data, t->size,
 						      &response);
 			if (response) {
-				ret |= (response->header->operation ==
-					PIMFOR_OP_ERROR);
+				r |= (response->header->operation == PIMFOR_OP_ERROR);
 				islpci_mgt_release(response);
 			}
+			if (r)
+				printk(KERN_ERR "%s: mgt_commit_list: failure. "
+					"oid=%08x err=%d\n",
+					priv->ndev->name, oid, r);
+			ret |= r;
 			j++;
 			oid++;
 			data += t->size;
@@ -624,7 +676,7 @@ static enum oid_num_t commit_part2[] = {
 static int
 mgt_update_addr(islpci_private *priv)
 {
-	struct islpci_mgmtframe *res = NULL;
+	struct islpci_mgmtframe *res;
 	int ret;
 
 	ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET,
@@ -638,9 +690,13 @@ mgt_update_addr(islpci_private *priv)
 	if (res)
 		islpci_mgt_release(res);
 
+	if (ret)
+		printk(KERN_ERR "%s: mgt_update_addr: failure\n", priv->ndev->name);
 	return ret;
 }
 
+#define VEC_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
 void
 mgt_commit(islpci_private *priv)
 {
@@ -650,14 +706,10 @@ mgt_commit(islpci_private *priv)
 	if (islpci_get_state(priv) < PRV_STATE_INIT)
 		return;
 
-	rvalue = mgt_commit_list(priv, commit_part1,
-				 sizeof (commit_part1) /
-				 sizeof (commit_part1[0]));
+	rvalue = mgt_commit_list(priv, commit_part1, VEC_SIZE(commit_part1));
 
 	if (priv->iw_mode != IW_MODE_MONITOR)
-		rvalue |= mgt_commit_list(priv, commit_part2,
-					  sizeof (commit_part2) /
-					  sizeof (commit_part2[0]));
+		rvalue |= mgt_commit_list(priv, commit_part2, VEC_SIZE(commit_part2));
 
 	u = OID_INL_MODE;
 	rvalue |= mgt_commit_list(priv, &u, 1);
@@ -666,11 +718,44 @@ mgt_commit(islpci_private *priv)
 	if (rvalue) {
 		/* some request have failed. The device might be in an
 		   incoherent state. We should reset it ! */
-		printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the "
-		       "device \n", priv->ndev->name);
+		printk(KERN_DEBUG "%s: mgt_commit: failure\n", priv->ndev->name);
 	}
 }
 
+/* The following OIDs need to be "unlatched":
+ *
+ * MEDIUMLIMIT,BEACONPERIOD,DTIMPERIOD,ATIMWINDOW,LISTENINTERVAL
+ * FREQUENCY,EXTENDEDRATES.
+ *
+ * The way to do this is to set ESSID. Note though that they may get 
+ * unlatch before though by setting another OID. */
+void
+mgt_unlatch_all(islpci_private *priv)
+{
+	u32 u;
+	int rvalue = 0;
+
+	if (islpci_get_state(priv) < PRV_STATE_INIT)
+		return;
+
+	u = DOT11_OID_SSID;
+	rvalue = mgt_commit_list(priv, &u, 1);
+	/* Necessary if in MANUAL RUN mode? */
+#if 0
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+
+	u = DOT11_OID_MLMEAUTOLEVEL;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+
+	u = OID_INL_MODE;
+	rvalue |= mgt_commit_list(priv, &u, 1);
+#endif
+
+	if (rvalue)
+		printk(KERN_DEBUG "%s: Unlatching OIDs failed\n", priv->ndev->name);
+}
+
 /* This will tell you if you are allowed to answer a mlme(ex) request .*/
 
 int
@@ -771,6 +856,14 @@ mgt_response_to_str(enum oid_num_t n, un
 					mlme->state, mlme->code, mlme->size);
 		}
 		break;
+	case OID_TYPE_ATTACH:{
+			struct obj_attachment *attach = r->ptr;
+			return snprintf(str, PRIV_STR_SIZE,
+					"id=%d\nsize=%d\n",
+					attach->id,
+					attach->size);
+		}
+		break;
 	case OID_TYPE_SSID:{
 			struct obj_ssid *ssid = r->ptr;
 			return snprintf(str, PRIV_STR_SIZE,
diff -puN drivers/net/wireless/prism54/oid_mgt.h~bk-netdev drivers/net/wireless/prism54/oid_mgt.h
--- 25/drivers/net/wireless/prism54/oid_mgt.h~bk-netdev	2004-09-06 18:43:15.695884248 -0700
+++ 25-akpm/drivers/net/wireless/prism54/oid_mgt.h	2004-09-06 18:43:15.858859472 -0700
@@ -36,6 +36,8 @@ int channel_of_freq(int);
 void mgt_le_to_cpu(int, void *);
 
 int mgt_set_request(islpci_private *, enum oid_num_t, int, void *);
+int mgt_set_varlen(islpci_private *, enum oid_num_t, void *, int);
+
 
 int mgt_get_request(islpci_private *, enum oid_num_t, int, void *,
 		    union oid_res_t *);
@@ -47,6 +49,7 @@ void mgt_set(islpci_private *, enum oid_
 void mgt_get(islpci_private *, enum oid_num_t, void *);
 
 void mgt_commit(islpci_private *);
+void mgt_unlatch_all(islpci_private *);
 
 int mgt_mlme_answer(islpci_private *);
 
diff -puN drivers/net/wireless/wavelan.c~bk-netdev drivers/net/wireless/wavelan.c
--- 25/drivers/net/wireless/wavelan.c~bk-netdev	2004-09-06 18:43:15.696884096 -0700
+++ 25-akpm/drivers/net/wireless/wavelan.c	2004-09-06 18:43:15.861859016 -0700
@@ -2172,6 +2172,11 @@ static int wavelan_get_range(struct net_
 	range->num_bitrates = 1;
 	range->bitrate[0] = 2000000;	/* 2 Mb/s */
 
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
+				IW_EVENT_CAPA_MASK(0x8B04));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
 	/* Disable interrupts and save flags. */
 	spin_lock_irqsave(&lp->spinlock, flags);
 	
@@ -2403,11 +2408,10 @@ static const struct iw_handler_def	wavel
 	.num_standard	= sizeof(wavelan_handler)/sizeof(iw_handler),
 	.num_private	= sizeof(wavelan_private_handler)/sizeof(iw_handler),
 	.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
-	.standard	= (iw_handler *) wavelan_handler,
-	.private	= (iw_handler *) wavelan_private_handler,
-	.private_args	= (struct iw_priv_args *) wavelan_private_args,
-	.spy_offset	= ((void *) (&((net_local *) NULL)->spy_data) -
-			   (void *) NULL),
+	.standard	= wavelan_handler,
+	.private	= wavelan_private_handler,
+	.private_args	= wavelan_private_args,
+	.get_wireless_stats = wavelan_get_wireless_stats,
 };
 
 /*------------------------------------------------------------------*/
@@ -4191,8 +4195,9 @@ static int __init wavelan_config(struct 
 #endif				/* SET_MAC_ADDRESS */
 
 #ifdef WIRELESS_EXT		/* if wireless extension exists in the kernel */
-	dev->get_wireless_stats = wavelan_get_wireless_stats;
-	dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
+	dev->wireless_handlers = &wavelan_handler_def;
+	lp->wireless_data.spy_data = &lp->spy_data;
+	dev->wireless_data = &lp->wireless_data;
 #endif
 
 	dev->mtu = WAVELAN_MTU;
diff -puN drivers/net/wireless/wavelan_cs.c~bk-netdev drivers/net/wireless/wavelan_cs.c
--- 25/drivers/net/wireless/wavelan_cs.c~bk-netdev	2004-09-06 18:43:15.698883792 -0700
+++ 25-akpm/drivers/net/wireless/wavelan_cs.c	2004-09-06 18:43:15.868857952 -0700
@@ -502,7 +502,7 @@ unsigned char WAVELAN_BEACON_ADDRESS[]= 
   
 void wv_roam_init(struct net_device *dev)
 {
-  net_local  *lp= (net_local *)dev->priv;
+  net_local  *lp= netdev_priv(dev);
 
   /* Do not remove this unless you have a good reason */
   printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
@@ -532,7 +532,7 @@ void wv_roam_init(struct net_device *dev
 void wv_roam_cleanup(struct net_device *dev)
 {
   wavepoint_history *ptr,*old_ptr;
-  net_local *lp= (net_local *)dev->priv;
+  net_local *lp= netdev_priv(dev);
   
   printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
   
@@ -762,7 +762,7 @@ static inline void wl_roam_gather(struct
   unsigned short nwid=ntohs(beacon->nwid);  
   unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
   wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
-  net_local *lp=(net_local *)dev->priv;              /* Device info */
+  net_local *lp = netdev_priv(dev);              /* Device info */
 
 #ifdef I_NEED_THIS_FEATURE
   /* Some people don't need this, some other may need it */
@@ -1006,7 +1006,7 @@ read_ringbuf(struct net_device *	dev,
 static inline void
 wv_82593_reconfig(struct net_device *	dev)
 {
-  net_local *		lp = (net_local *)dev->priv;
+  net_local *		lp = netdev_priv(dev);
   dev_link_t *		link = lp->link;
   unsigned long		flags;
 
@@ -1135,7 +1135,7 @@ static void
 wv_mmc_show(struct net_device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *)dev->priv;
+  net_local *	lp = netdev_priv(dev);
   mmr_t		m;
 
   /* Basic check */
@@ -1224,7 +1224,7 @@ wv_mmc_show(struct net_device *	dev)
 static void
 wv_ru_show(struct net_device *	dev)
 {
-  net_local *lp = (net_local *) dev->priv;
+  net_local *lp = netdev_priv(dev);
 
   printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
   printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
@@ -1258,9 +1258,7 @@ wv_dev_show(struct net_device *	dev)
 static void
 wv_local_show(struct net_device *	dev)
 {
-  net_local *lp;
-
-  lp = (net_local *)dev->priv;
+  net_local *lp = netdev_priv(dev);
 
   printk(KERN_DEBUG "local:");
   /*
@@ -1418,7 +1416,7 @@ wavelan_get_stats(struct net_device *	de
   printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
 #endif
 
-  return(&((net_local *) dev->priv)->stats);
+  return(&((net_local *)netdev_priv(dev))->stats);
 }
 
 /*------------------------------------------------------------------*/
@@ -1433,7 +1431,7 @@ wavelan_get_stats(struct net_device *	de
 static void
 wavelan_set_multicast_list(struct net_device *	dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
 
 #ifdef DEBUG_IOCTL_TRACE
   printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
@@ -1550,7 +1548,6 @@ wavelan_set_mac_address(struct net_devic
 /*
  * Frequency setting (for hardware able of it)
  * It's a bit complicated and you don't really want to look into it...
- * (called in wavelan_ioctl)
  */
 static inline int
 wv_set_frequency(u_long		base,	/* i/o port of the card */
@@ -1826,7 +1823,7 @@ static inline void
 wl_his_gather(struct net_device *	dev,
 	      u_char *	stats)		/* Statistics to gather */
 {
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
   u_char	level = stats[0] & MMR_SIGNAL_LVL;
   int		i;
 
@@ -1840,28 +1837,15 @@ wl_his_gather(struct net_device *	dev,
 }
 #endif	/* HISTOGRAM */
 
-static inline int
-wl_netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-
-		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-
-	return -EOPNOTSUPP;
+	strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1);
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = wl_get_drvinfo
+};
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get protocol name
@@ -1885,7 +1869,7 @@ static int wavelan_set_nwid(struct net_d
 			    char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	mm_t m;
 	unsigned long flags;
@@ -1943,7 +1927,7 @@ static int wavelan_get_nwid(struct net_d
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -1975,7 +1959,7 @@ static int wavelan_set_freq(struct net_d
 			    char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	int ret;
 
@@ -2005,7 +1989,7 @@ static int wavelan_get_freq(struct net_d
 			    char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -2051,7 +2035,7 @@ static int wavelan_set_sens(struct net_d
 			    char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -2086,7 +2070,7 @@ static int wavelan_get_sens(struct net_d
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -2117,7 +2101,7 @@ static int wavelan_set_encode(struct net
 			      char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	psa_t psa;
 	int ret = 0;
@@ -2187,7 +2171,7 @@ static int wavelan_get_encode(struct net
 			      char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 	int ret = 0;
@@ -2234,7 +2218,7 @@ static int wavelan_set_essid(struct net_
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	int ret = 0;
 
@@ -2282,7 +2266,7 @@ static int wavelan_get_essid(struct net_
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 
 	/* Is the domain ID active ? */
 	wrqu->data.flags = lp->filter_domains;
@@ -2347,7 +2331,7 @@ static int wavelan_set_mode(struct net_d
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 	int ret = 0;
 
@@ -2406,7 +2390,7 @@ static int wavelan_get_range(struct net_
 			     char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	struct iw_range *range = (struct iw_range *) extra;
 	unsigned long flags;
 	int ret = 0;
@@ -2438,6 +2422,12 @@ static int wavelan_get_range(struct net_
 	range->num_bitrates = 1;
 	range->bitrate[0] = 2000000;	/* 2 Mb/s */
 
+	/* Event capability (kernel + driver) */
+	range->event_capa[0] = (IW_EVENT_CAPA_MASK(0x8B02) |
+				IW_EVENT_CAPA_MASK(0x8B04) |
+				IW_EVENT_CAPA_MASK(0x8B06));
+	range->event_capa[1] = IW_EVENT_CAPA_K_1;
+
 	/* Disable interrupts and save flags. */
 	spin_lock_irqsave(&lp->spinlock, flags);
 	
@@ -2476,7 +2466,7 @@ static int wavelan_set_qthr(struct net_d
 			    char *extra)
 {
 	ioaddr_t base = dev->base_addr;
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 
@@ -2507,7 +2497,7 @@ static int wavelan_get_qthr(struct net_d
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	psa_t psa;
 	unsigned long flags;
 
@@ -2535,7 +2525,7 @@ static int wavelan_set_roam(struct net_d
 			    union iwreq_data *wrqu,
 			    char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 	unsigned long flags;
 
 	/* Disable interrupts and save flags. */
@@ -2580,7 +2570,7 @@ static int wavelan_set_histo(struct net_
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 
 	/* Check the number of intervals. */
 	if (wrqu->data.length > 16) {
@@ -2623,7 +2613,7 @@ static int wavelan_get_histo(struct net_
 			     union iwreq_data *wrqu,
 			     char *extra)
 {
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
+	net_local *lp = netdev_priv(dev);
 
 	/* Set the number of intervals. */
 	wrqu->data.length = lp->his_number;
@@ -2737,50 +2727,14 @@ static const struct iw_handler_def	wavel
 	.num_standard	= sizeof(wavelan_handler)/sizeof(iw_handler),
 	.num_private	= sizeof(wavelan_private_handler)/sizeof(iw_handler),
 	.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
-	.standard	= (iw_handler *) wavelan_handler,
-	.private	= (iw_handler *) wavelan_private_handler,
-	.private_args	= (struct iw_priv_args *) wavelan_private_args,
-	.spy_offset	= ((void *) (&((net_local *) NULL)->spy_data) -
-			   (void *) NULL),
+	.standard	= wavelan_handler,
+	.private	= wavelan_private_handler,
+	.private_args	= wavelan_private_args,
+	.get_wireless_stats = wavelan_get_wireless_stats,
 };
 
 /*------------------------------------------------------------------*/
 /*
- * Perform ioctl : config & info stuff
- * This is here that are treated the wireless extensions (iwconfig)
- */
-static int
-wavelan_ioctl(struct net_device *	dev,	/* Device on wich the ioctl apply */
-	      struct ifreq *	rq,	/* Data passed */
-	      int		cmd)	/* Ioctl number */
-{
-  int			ret = 0;
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
-#endif
-
-  /* Look what is the request */
-  switch(cmd)
-    {
-    case SIOCETHTOOL:
-      ret = wl_netdev_ethtool_ioctl(dev, rq->ifr_data);
-      break;
-
-      /* ------------------- OTHER IOCTL ------------------- */
-
-    default:
-      ret = -EOPNOTSUPP;
-    }
-
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
-#endif
-  return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
  * Get wireless statistics
  * Called by /proc/net/wireless...
  */
@@ -2788,7 +2742,7 @@ static iw_stats *
 wavelan_get_wireless_stats(struct net_device *	dev)
 {
   ioaddr_t		base = dev->base_addr;
-  net_local *		lp = (net_local *) dev->priv;
+  net_local *		lp = netdev_priv(dev);
   mmr_t			m;
   iw_stats *		wstats;
   unsigned long		flags;
@@ -2913,7 +2867,7 @@ wv_packet_read(struct net_device *		dev,
 	       int		fd_p,
 	       int		sksize)
 {
-  net_local *		lp = (net_local *) dev->priv;
+  net_local *		lp = netdev_priv(dev);
   struct sk_buff *	skb;
 
 #ifdef DEBUG_RX_TRACE
@@ -3015,7 +2969,7 @@ static inline void
 wv_packet_rcv(struct net_device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
   int		newrfp;
   int		rp;
   int		len;
@@ -3150,7 +3104,7 @@ wv_packet_write(struct net_device *	dev,
 		void *		buf,
 		short		length)
 {
-  net_local *		lp = (net_local *) dev->priv;
+  net_local *		lp = netdev_priv(dev);
   ioaddr_t		base = dev->base_addr;
   unsigned long		flags;
   int			clen = length;
@@ -3211,7 +3165,7 @@ static int
 wavelan_packet_xmit(struct sk_buff *	skb,
 		    struct net_device *		dev)
 {
-  net_local *		lp = (net_local *)dev->priv;
+  net_local *		lp = netdev_priv(dev);
   unsigned long		flags;
 
 #ifdef DEBUG_TX_TRACE
@@ -3470,7 +3424,7 @@ static int
 wv_ru_stop(struct net_device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
   unsigned long	flags;
   int		status;
   int		spin;
@@ -3533,7 +3487,7 @@ static int
 wv_ru_start(struct net_device *	dev)
 {
   ioaddr_t	base = dev->base_addr;
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
   unsigned long	flags;
 
 #ifdef DEBUG_CONFIG_TRACE
@@ -3621,7 +3575,7 @@ static int
 wv_82593_config(struct net_device *	dev)
 {
   ioaddr_t			base = dev->base_addr;
-  net_local *			lp = (net_local *) dev->priv;
+  net_local *			lp = netdev_priv(dev);
   struct i82593_conf_block	cfblk;
   int				ret = TRUE;
 
@@ -3796,7 +3750,7 @@ wv_pcmcia_reset(struct net_device *	dev)
 {
   int		i;
   conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  dev_link_t *	link = ((net_local *)netdev_priv(dev))->link;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
@@ -3856,7 +3810,7 @@ wv_pcmcia_reset(struct net_device *	dev)
 static int
 wv_hw_config(struct net_device *	dev)
 {
-  net_local *		lp = (net_local *) dev->priv;
+  net_local *		lp = netdev_priv(dev);
   ioaddr_t		base = dev->base_addr;
   unsigned long		flags;
   int			ret = FALSE;
@@ -3963,7 +3917,7 @@ wv_hw_config(struct net_device *	dev)
 static inline void
 wv_hw_reset(struct net_device *	dev)
 {
-  net_local *	lp = (net_local *) dev->priv;
+  net_local *	lp = netdev_priv(dev);
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
@@ -4131,8 +4085,8 @@ wv_pcmcia_config(dev_link_t *	link)
       return FALSE;
     }
 
-  strcpy(((net_local *) dev->priv)->node.dev_name, dev->name);
-  link->dev = &((net_local *) dev->priv)->node;
+  strcpy(((net_local *) netdev_priv(dev))->node.dev_name, dev->name);
+  link->dev = &((net_local *) netdev_priv(dev))->node;
 
 #ifdef DEBUG_CONFIG_TRACE
   printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
@@ -4203,7 +4157,7 @@ wavelan_interrupt(int		irq,
   printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
 #endif
 
-  lp = (net_local *) dev->priv;
+  lp = netdev_priv(dev);
   base = dev->base_addr;
 
 #ifdef DEBUG_INTERRUPT_INFO
@@ -4453,7 +4407,7 @@ wavelan_interrupt(int		irq,
 static void
 wavelan_watchdog(struct net_device *	dev)
 {
-  net_local *		lp = (net_local *) dev->priv;
+  net_local *		lp = netdev_priv(dev);
   ioaddr_t		base = dev->base_addr;
   unsigned long		flags;
   int			aborted = FALSE;
@@ -4528,8 +4482,8 @@ wavelan_watchdog(struct net_device *	dev
 static int
 wavelan_open(struct net_device *	dev)
 {
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
-  net_local *	lp = (net_local *)dev->priv;
+  net_local *	lp = netdev_priv(dev);
+  dev_link_t *	link = lp->link;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4583,7 +4537,7 @@ wavelan_open(struct net_device *	dev)
 static int
 wavelan_close(struct net_device *	dev)
 {
-  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  dev_link_t *	link = ((net_local *)netdev_priv(dev))->link;
   ioaddr_t	base = dev->base_addr;
 
 #ifdef DEBUG_CALLBACK_TRACE
@@ -4686,7 +4640,7 @@ wavelan_attach(void)
   }
   link->priv = link->irq.Instance = dev;
 
-  lp = dev->priv;
+  lp = netdev_priv(dev);
 
   /* Init specific data */
   lp->configured = 0;
@@ -4718,11 +4672,12 @@ wavelan_attach(void)
   /* Set the watchdog timer */
   dev->tx_timeout	= &wavelan_watchdog;
   dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+  SET_ETHTOOL_OPS(dev, &ops);
 
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-  dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
-  dev->do_ioctl = wavelan_ioctl;	/* old wireless extensions */
-  dev->get_wireless_stats = wavelan_get_wireless_stats;
+  dev->wireless_handlers = &wavelan_handler_def;
+  lp->wireless_data.spy_data = &lp->spy_data;
+  dev->wireless_data = &lp->wireless_data;
 #endif
 
   /* Other specific data */
@@ -4820,8 +4775,8 @@ wavelan_detach(dev_link_t *	link)
       if (link->dev)
 	unregister_netdev(dev);
       link->dev = NULL;
-      ((net_local *) dev->priv)->link = NULL;
-      ((net_local *) dev->priv)->dev = NULL;
+      ((net_local *)netdev_priv(dev))->link = NULL;
+      ((net_local *)netdev_priv(dev))->dev = NULL;
       free_netdev(dev);
     }
   kfree(link);
diff -puN drivers/net/wireless/wavelan_cs.p.h~bk-netdev drivers/net/wireless/wavelan_cs.p.h
--- 25/drivers/net/wireless/wavelan_cs.p.h~bk-netdev	2004-09-06 18:43:15.700883488 -0700
+++ 25-akpm/drivers/net/wireless/wavelan_cs.p.h	2004-09-06 18:43:15.870857648 -0700
@@ -629,6 +629,7 @@ struct net_local
   iw_stats	wstats;		/* Wireless specific stats */
 
   struct iw_spy_data	spy_data;
+  struct iw_public_data	wireless_data;
 #endif
 
 #ifdef HISTOGRAM
@@ -725,6 +726,8 @@ static inline void
 /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
 static en_stats	*
 	wavelan_get_stats(struct net_device *);	/* Give stats /proc/net/dev */
+static iw_stats *
+	wavelan_get_wireless_stats(struct net_device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
 static inline int
 	wv_start_of_frame(struct net_device *,	/* Seek beggining of current frame */
diff -puN drivers/net/wireless/wavelan.p.h~bk-netdev drivers/net/wireless/wavelan.p.h
--- 25/drivers/net/wireless/wavelan.p.h~bk-netdev	2004-09-06 18:43:15.701883336 -0700
+++ 25-akpm/drivers/net/wireless/wavelan.p.h	2004-09-06 18:43:15.862858864 -0700
@@ -510,6 +510,7 @@ struct net_local
   iw_stats	wstats;		/* Wireless-specific statistics */
 
   struct iw_spy_data	spy_data;
+  struct iw_public_data	wireless_data;
 #endif
 
 #ifdef HISTOGRAM
@@ -614,6 +615,8 @@ static inline void
 /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
 static en_stats	*
 	wavelan_get_stats(struct net_device *);	/* Give stats /proc/net/dev */
+static iw_stats *
+	wavelan_get_wireless_stats(struct net_device *);
 static void
 	wavelan_set_multicast_list(struct net_device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
diff -puN drivers/net/wireless/wl3501_cs.c~bk-netdev drivers/net/wireless/wl3501_cs.c
--- 25/drivers/net/wireless/wl3501_cs.c~bk-netdev	2004-09-06 18:43:15.703883032 -0700
+++ 25-akpm/drivers/net/wireless/wl3501_cs.c	2004-09-06 18:43:15.872857344 -0700
@@ -1487,55 +1487,14 @@ struct iw_statistics *wl3501_get_wireles
 	return wstats;
 }
 
-static inline int wl3501_ethtool_ioctl(struct net_device *dev, void __user *uaddr)
+static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
-	int rc = -EFAULT;
-
-	if (copy_from_user(&ethcmd, uaddr, sizeof(ethcmd)))
-		goto out;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = { .cmd = ETHTOOL_GDRVINFO, };
-
-		strlcpy(info.driver, wl3501_dev_info, sizeof(info.driver));
-		rc = copy_to_user(uaddr, &info, sizeof(info)) ? -EFAULT : 1;
-	}
-	default:
-		rc = -EOPNOTSUPP;
-		break;
-	}
-out:
-	return rc;
+	strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
 }
 
-/**
- * wl3501_ioctl - Perform IOCTL call functions
- * @dev - network device
- * @ifreq - request
- * @cmd - command
- *
- * Perform IOCTL call functions here. Some are privileged operations and the
- * effective uid is checked in those cases.
- *
- * This part is optional. Needed only if you want to run wlu (unix version).
- *
- * CAUTION: To prevent interrupted by wl3501_interrupt() and timer-based
- * wl3501_hard_start_xmit() from other interrupts, this should be run
- * single-threaded.
- */
-static int wl3501_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-	int rc = -ENODEV;
-
-	if (netif_device_present(dev)) {
-		rc = -EOPNOTSUPP;
-		if (cmd == SIOCETHTOOL)
-			rc = wl3501_ethtool_ioctl(dev, rq->ifr_data);
-	}
-	return rc;
-}
+static struct ethtool_ops ops = {
+	.get_drvinfo = wl3501_get_drvinfo
+};
 
 /**
  * wl3501_detach - deletes a driver "instance"
@@ -2047,8 +2006,8 @@ static dev_link_t *wl3501_attach(void)
 	dev->watchdog_timeo	= 5 * HZ;
 	dev->get_stats		= wl3501_get_stats;
 	dev->get_wireless_stats = wl3501_get_wireless_stats;
-	dev->do_ioctl		= wl3501_ioctl;
 	dev->wireless_handlers	= (struct iw_handler_def *)&wl3501_handler_def;
+	SET_ETHTOOL_OPS(dev, &ops);
 	netif_stop_queue(dev);
 	link->priv = link->irq.Instance = dev;
 
diff -puN drivers/net/yellowfin.c~bk-netdev drivers/net/yellowfin.c
--- 25/drivers/net/yellowfin.c~bk-netdev	2004-09-06 18:43:15.704882880 -0700
+++ 25-akpm/drivers/net/yellowfin.c	2004-09-06 18:43:15.874857040 -0700
@@ -406,6 +406,7 @@ static void yellowfin_error(struct net_d
 static int yellowfin_close(struct net_device *dev);
 static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
+static struct ethtool_ops ethtool_ops;
 
 
 static int __devinit yellowfin_init_one(struct pci_dev *pdev,
@@ -440,7 +441,7 @@ static int __devinit yellowfin_init_one(
 	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
-	np = dev->priv;
+	np = netdev_priv(dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_free_netdev;
@@ -521,6 +522,7 @@ static int __devinit yellowfin_init_one(
 	dev->get_stats = &yellowfin_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &netdev_ioctl;
+	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 	dev->tx_timeout = yellowfin_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
@@ -619,7 +621,7 @@ static void mdio_write(long ioaddr, int 
 
 static int yellowfin_open(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int i;
 
@@ -701,7 +703,7 @@ static int yellowfin_open(struct net_dev
 static void yellowfin_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	int next_tick = 60*HZ;
 
@@ -735,7 +737,7 @@ static void yellowfin_timer(unsigned lon
 
 static void yellowfin_tx_timeout(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Yellowfin transmit timed out at %d/%d Tx "
@@ -772,7 +774,7 @@ static void yellowfin_tx_timeout(struct 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void yellowfin_init_ring(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	int i;
 
 	yp->tx_full = 0;
@@ -855,7 +857,7 @@ static void yellowfin_init_ring(struct n
 
 static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	unsigned entry;
 	int len = skb->len;
 
@@ -953,7 +955,7 @@ static irqreturn_t yellowfin_interrupt(i
 #endif
 
 	ioaddr = dev->base_addr;
-	yp = dev->priv;
+	yp = netdev_priv(dev);
 	
 	spin_lock (&yp->lock);
 
@@ -1095,7 +1097,7 @@ static irqreturn_t yellowfin_interrupt(i
    for clarity and better register allocation. */
 static int yellowfin_rx(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	int entry = yp->cur_rx % RX_RING_SIZE;
 	int boguscnt = yp->dirty_rx + RX_RING_SIZE - yp->cur_rx;
 
@@ -1239,7 +1241,7 @@ static int yellowfin_rx(struct net_devic
 
 static void yellowfin_error(struct net_device *dev, int intr_status)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 
 	printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 		   dev->name, intr_status);
@@ -1253,7 +1255,7 @@ static void yellowfin_error(struct net_d
 static int yellowfin_close(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	int i;
 
 	netif_stop_queue (dev);
@@ -1340,7 +1342,7 @@ static int yellowfin_close(struct net_de
 
 static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	return &yp->stats;
 }
 
@@ -1348,7 +1350,7 @@ static struct net_device_stats *yellowfi
 
 static void set_rx_mode(struct net_device *dev)
 {
-	struct yellowfin_private *yp = dev->priv;
+	struct yellowfin_private *yp = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	u16 cfg_value = inw(ioaddr + Cnfg);
 
@@ -1394,39 +1396,25 @@ static void set_rx_mode(struct net_devic
 	outw(cfg_value | 0x1000, ioaddr + Cnfg);
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	struct yellowfin_private *np = dev->priv;
-	u32 ethcmd;
-		
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-        switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, pci_name(np->pci_dev));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-
-        }
-	
-	return -EOPNOTSUPP;
+	struct yellowfin_private *np = netdev_priv(dev);
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->bus_info, pci_name(np->pci_dev));
 }
 
+static struct ethtool_ops ethtool_ops = {
+	.get_drvinfo = yellowfin_get_drvinfo
+};
+
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
-	struct yellowfin_private *np = dev->priv;
+	struct yellowfin_private *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = if_mii(rq);
 
 	switch(cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(dev, rq->ifr_data);
 	case SIOCGMIIPHY:		/* Get address of MII PHY in use. */
 		data->phy_id = np->phys[0] & 0x1f;
 		/* Fall Through */
@@ -1466,7 +1454,7 @@ static void __devexit yellowfin_remove_o
 
 	if (!dev)
 		BUG();
-	np = dev->priv;
+	np = netdev_priv(dev);
 
         pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status, 
 		np->tx_status_dma);
diff -puN drivers/usb/gadget/ether.c~bk-netdev drivers/usb/gadget/ether.c
--- 25/drivers/usb/gadget/ether.c~bk-netdev	2004-09-06 18:43:15.718880752 -0700
+++ 25-akpm/drivers/usb/gadget/ether.c	2004-09-06 18:43:15.876856736 -0700
@@ -1670,7 +1670,7 @@ eth_disconnect (struct usb_gadget *gadge
 
 static int eth_change_mtu (struct net_device *net, int new_mtu)
 {
-	struct eth_dev	*dev = (struct eth_dev *) net->priv;
+	struct eth_dev	*dev = netdev_priv(net);
 
 	// FIXME if rndis, don't change while link's live
 
@@ -1685,58 +1685,29 @@ static int eth_change_mtu (struct net_de
 
 static struct net_device_stats *eth_get_stats (struct net_device *net)
 {
-	return &((struct eth_dev *) net->priv)->stats;
+	return &((struct eth_dev *)netdev_priv(net))->stats;
 }
 
-static int eth_ethtool_ioctl (struct net_device *net, void __user *useraddr)
+static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p)
 {
-	struct eth_dev	*dev = (struct eth_dev *) net->priv;
-	u32		cmd;
-
-	if (get_user (cmd, (u32 __user *)useraddr))
-		return -EFAULT;
-	switch (cmd) {
-
-	case ETHTOOL_GDRVINFO: {	/* get driver info */
-		struct ethtool_drvinfo		info;
-
-		memset (&info, 0, sizeof info);
-		info.cmd = ETHTOOL_GDRVINFO;
-		strlcpy (info.driver, shortname, sizeof info.driver);
-		strlcpy (info.version, DRIVER_VERSION, sizeof info.version);
-		strlcpy (info.fw_version, dev->gadget->name,
-			sizeof info.fw_version);
-		strlcpy (info.bus_info, dev->gadget->dev.bus_id,
-			sizeof info.bus_info);
-		if (copy_to_user (useraddr, &info, sizeof (info)))
-			return -EFAULT;
-		return 0;
-		}
-
-	case ETHTOOL_GLINK: {		/* get link status */
-		struct ethtool_value	edata = { ETHTOOL_GLINK };
-
-		edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN);
-		if (copy_to_user (useraddr, &edata, sizeof (edata)))
-			return -EFAULT;
-		return 0;
-		}
-
-	}
-	/* Note that the ethtool user space code requires EOPNOTSUPP */
-	return -EOPNOTSUPP;
+	struct eth_dev	*dev = netdev_priv(net);
+	strlcpy(p->driver, shortname, sizeof p->driver);
+	strlcpy(p->version, DRIVER_VERSION, sizeof p->version);
+	strlcpy(p->fw_version, dev->gadget->name, sizeof p->fw_version);
+	strlcpy (p->bus_info, dev->gadget->dev.bus_id, sizeof p->bus_info);
 }
 
-static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+static u32 eth_get_link(struct net_device *net)
 {
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return eth_ethtool_ioctl(net, rq->ifr_data);
-	default:
-		return -EOPNOTSUPP;
-	}
+	struct eth_dev	*dev = netdev_priv(net);
+	return dev->gadget->speed != USB_SPEED_UNKNOWN;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = eth_get_drvinfo,
+	.get_link = eth_get_link
+};
+
 static void defer_kevent (struct eth_dev *dev, int flag)
 {
 	if (test_and_set_bit (flag, &dev->todo))
@@ -1997,7 +1968,7 @@ static void tx_complete (struct usb_ep *
 
 static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 	int			length = skb->len;
 	int			retval;
 	struct usb_request	*req = NULL;
@@ -2110,7 +2081,7 @@ static void rndis_control_ack_complete (
 
 static int rndis_control_ack (struct net_device *net)
 {
-	struct eth_dev          *dev = (struct eth_dev *) net->priv;
+	struct eth_dev          *dev = netdev_priv(net);
 	u32                     length;
 	struct usb_request      *resp;
 	
@@ -2177,7 +2148,7 @@ static void eth_start (struct eth_dev *d
 
 static int eth_open (struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 
 	DEBUG (dev, "%s\n", __FUNCTION__);
 	if (netif_carrier_ok (dev->net))
@@ -2187,7 +2158,7 @@ static int eth_open (struct net_device *
 
 static int eth_stop (struct net_device *net)
 {
-	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	struct eth_dev		*dev = netdev_priv(net);
 
 	VDEBUG (dev, "%s\n", __FUNCTION__);
 	netif_stop_queue (net);
@@ -2474,7 +2445,7 @@ autoconf_fail:
  	net = alloc_etherdev (sizeof *dev);
  	if (!net)
 		return status;
-	dev = net->priv;
+	dev = netdev_priv(net);
 	spin_lock_init (&dev->lock);
 	INIT_WORK (&dev->work, eth_work, dev);
 	INIT_LIST_HEAD (&dev->tx_reqs);
@@ -2518,7 +2489,7 @@ autoconf_fail:
 	net->stop = eth_stop;
 	// watchdog_timeo, tx_timeout ...
 	// set_multicast_list
-	net->do_ioctl = eth_ioctl;
+	SET_ETHTOOL_OPS(net, &ops);
 
 	/* preallocate control response and buffer */
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
diff -puN drivers/usb/net/catc.c~bk-netdev drivers/usb/net/catc.c
--- 25/drivers/usb/net/catc.c~bk-netdev	2004-09-06 18:43:15.730878928 -0700
+++ 25-akpm/drivers/usb/net/catc.c	2004-09-06 18:43:15.878856432 -0700
@@ -411,7 +411,7 @@ static void catc_tx_done(struct urb *urb
 
 static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 	unsigned long flags;
 	char *tx_buf;
 
@@ -442,7 +442,7 @@ static int catc_hard_start_xmit(struct s
 
 static void catc_tx_timeout(struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 
 	warn("Transmit timed out.");
 	catc->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
@@ -604,7 +604,7 @@ static void catc_stats_timer(unsigned lo
 
 static struct net_device_stats *catc_get_stats(struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 	return &catc->stats;
 }
 
@@ -622,7 +622,7 @@ static void catc_multicast(unsigned char
 
 static void catc_set_multicast_list(struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 	struct dev_mc_list *mc;
 	u8 broadcast[6];
 	u8 rx = RxEnable | RxPolarity | RxMultiCast;
@@ -664,74 +664,38 @@ static void catc_set_multicast_list(stru
 	}
 }
 
-/*
- * ioctl's
- */
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+void catc_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-        struct catc *catc = dev->priv;
-        u32 cmd;
-        
-        if (get_user(cmd, (u32 __user *)useraddr))
-                return -EFAULT;
-
-        switch (cmd) {
-        /* get driver info */
-        case ETHTOOL_GDRVINFO: {
-                struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-                strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
-                strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info);
-                if (copy_to_user(useraddr, &info, sizeof(info)))
-                        return -EFAULT;
-                return 0;
-        }
-
-	/* get settings */
-	case ETHTOOL_GSET:
-		if (catc->is_f5u011) {
-			struct ethtool_cmd ecmd = { ETHTOOL_GSET, 
-						    SUPPORTED_10baseT_Half | SUPPORTED_TP, 
-						    ADVERTISED_10baseT_Half | ADVERTISED_TP, 
-						    SPEED_10, 
-						    DUPLEX_HALF, 
-						    PORT_TP, 
-						    0, 
-						    XCVR_INTERNAL, 
-						    AUTONEG_DISABLE, 
-						    1, 
-						    1 
-			};
-			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
-				return -EFAULT;
-			return 0;
-		} else {
-			return -EOPNOTSUPP;
-		}
+	struct catc *catc = netdev_priv(dev);
+	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+	usb_make_path (catc->usbdev, info->bus_info, sizeof info->bus_info);
+}
+
+static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct catc *catc = netdev_priv(dev);
+	if (!catc->is_f5u011)
+		return -EOPNOTSUPP;
 
-        /* get link status */
-        case ETHTOOL_GLINK: {
-                struct ethtool_value edata = {ETHTOOL_GLINK};
-                edata.data = netif_carrier_ok(dev);
-                if (copy_to_user(useraddr, &edata, sizeof(edata)))
-                        return -EFAULT;
-                return 0;
-        }
-	}
-        
-        return -EOPNOTSUPP;
-}
-
-static int catc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
-        switch(cmd) {
-        case SIOCETHTOOL:
-                return netdev_ethtool_ioctl(dev, rq->ifr_data);
-        default:
-                return -EOPNOTSUPP;
-        }
+	cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
+	cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
+	cmd->speed = SPEED_10;
+	cmd->duplex = DUPLEX_HALF;
+	cmd->port = PORT_TP; 
+	cmd->phy_address = 0;
+	cmd->transceiver = XCVR_INTERNAL;
+	cmd->autoneg = AUTONEG_DISABLE;
+	cmd->maxtxpkt = 1;
+	cmd->maxrxpkt = 1;
+	return 0;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = catc_get_drvinfo,
+	.get_settings = catc_get_settings,
+	.get_link = ethtool_op_get_link
+};
 
 /*
  * Open, close.
@@ -739,7 +703,7 @@ static int catc_ioctl(struct net_device 
 
 static int catc_open(struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 	int status;
 
 	catc->irq_urb->dev = catc->usbdev;
@@ -758,7 +722,7 @@ static int catc_open(struct net_device *
 
 static int catc_stop(struct net_device *netdev)
 {
-	struct catc *catc = netdev->priv;
+	struct catc *catc = netdev_priv(netdev);
 
 	netif_stop_queue(netdev);
 
@@ -791,17 +755,11 @@ static int catc_probe(struct usb_interfa
 		return -EIO;
 	}
 
-	catc = kmalloc(sizeof(struct catc), GFP_KERNEL);
-	if (!catc)
+	netdev = alloc_etherdev(sizeof(struct catc));
+	if (!netdev)
 		return -ENOMEM;
 
-	memset(catc, 0, sizeof(struct catc));
-
-	netdev = alloc_etherdev(0);
-	if (!netdev) {
-		kfree(catc);
-		return -EIO;
-	}
+	catc = netdev_priv(netdev);
 
 	netdev->open = catc_open;
 	netdev->hard_start_xmit = catc_hard_start_xmit;
@@ -810,8 +768,7 @@ static int catc_probe(struct usb_interfa
 	netdev->tx_timeout = catc_tx_timeout;
 	netdev->watchdog_timeo = TX_TIMEOUT;
 	netdev->set_multicast_list = catc_set_multicast_list;
-	netdev->do_ioctl = catc_ioctl;
-	netdev->priv = catc;
+	SET_ETHTOOL_OPS(netdev, &ops);
 
 	catc->usbdev = usbdev;
 	catc->netdev = netdev;
@@ -839,7 +796,6 @@ static int catc_probe(struct usb_interfa
 		if (catc->irq_urb)
 			usb_free_urb(catc->irq_urb);
 		free_netdev(netdev);
-		kfree(catc);
 		return -ENOMEM;
 	}
 
@@ -944,7 +900,6 @@ static int catc_probe(struct usb_interfa
 		usb_free_urb(catc->rx_urb);
 		usb_free_urb(catc->irq_urb);
 		free_netdev(netdev);
-		kfree(catc);
 		return -EIO;
 	}
 	return 0;
@@ -962,7 +917,6 @@ static void catc_disconnect(struct usb_i
 		usb_free_urb(catc->rx_urb);
 		usb_free_urb(catc->irq_urb);
 		free_netdev(catc->netdev);
-		kfree(catc);
 	}
 }
 
diff -puN drivers/usb/net/kaweth.c~bk-netdev drivers/usb/net/kaweth.c
--- 25/drivers/usb/net/kaweth.c~bk-netdev	2004-09-06 18:43:15.732878624 -0700
+++ 25-akpm/drivers/usb/net/kaweth.c	2004-09-06 18:43:15.879856280 -0700
@@ -710,37 +710,15 @@ static int kaweth_close(struct net_devic
 	return 0;
 }
 
-static int netdev_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
+static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
-	u32 ethcmd;
 
-	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-		return -EFAULT;
-
-	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strlcpy(info.driver, driver_name, sizeof(info.driver));
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	}
-
-	return -EOPNOTSUPP;
+	strlcpy(info->driver, driver_name, sizeof(info->driver));
 }
 
-/****************************************************************
- *     kaweth_ioctl
- ****************************************************************/
-static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
-{
-	switch (cmd) {
-	case SIOCETHTOOL:
-		return netdev_ethtool_ioctl(net, rq->ifr_data);
-	}
-	return -EOPNOTSUPP;
-}
+static struct ethtool_ops ops = {
+	.get_drvinfo = kaweth_get_drvinfo
+};
 
 /****************************************************************
  *     kaweth_usb_transmit_complete
@@ -1107,11 +1085,11 @@ static int kaweth_probe(
 	kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
 	kaweth->net->tx_timeout = kaweth_tx_timeout;
 
-	kaweth->net->do_ioctl = kaweth_ioctl;
 	kaweth->net->hard_start_xmit = kaweth_start_xmit;
 	kaweth->net->set_multicast_list = kaweth_set_rx_mode;
 	kaweth->net->get_stats = kaweth_netdev_stats;
 	kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size);
+	SET_ETHTOOL_OPS(kaweth->net, &ops);
 
 	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
 
diff -puN drivers/usb/net/pegasus.c~bk-netdev drivers/usb/net/pegasus.c
--- 25/drivers/usb/net/pegasus.c~bk-netdev	2004-09-06 18:43:15.733878472 -0700
+++ 25-akpm/drivers/usb/net/pegasus.c	2004-09-06 18:43:15.882855824 -0700
@@ -308,7 +308,7 @@ static int read_mii_word(pegasus_t * peg
 
 static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
-	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+	pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
 	int res;
 
 	read_mii_word(pegasus, phy_id, loc, (u16 *) & res);
@@ -338,7 +338,7 @@ static int write_mii_word(pegasus_t * pe
 
 static void mdio_write(struct net_device *dev, int phy_id, int loc, int val)
 {
-	pegasus_t *pegasus = (pegasus_t *) dev->priv;
+	pegasus_t *pegasus = (pegasus_t *) netdev_priv(dev);
 
 	write_mii_word(pegasus, phy_id, loc, val);
 }
@@ -471,7 +471,7 @@ static int enable_net_traffic(struct net
 {
 	__u16 linkpart;
 	__u8 data[4];
-	pegasus_t *pegasus = dev->priv;
+	pegasus_t *pegasus = netdev_priv(dev);
 
 	read_mii_word(pegasus, pegasus->phy, MII_LPA, &linkpart);
 	data[0] = 0xc9;
@@ -754,11 +754,7 @@ static void intr_callback(struct urb *ur
 
 static void pegasus_tx_timeout(struct net_device *net)
 {
-	pegasus_t *pegasus = net->priv;
-
-	if (!pegasus)
-		return;
-
+	pegasus_t *pegasus = netdev_priv(net);
 	warn("%s: Tx timed out.", net->name);
 	pegasus->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(pegasus->tx_urb);
@@ -767,7 +763,7 @@ static void pegasus_tx_timeout(struct ne
 
 static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
 {
-	pegasus_t *pegasus = net->priv;
+	pegasus_t *pegasus = netdev_priv(net);
 	int count = ((skb->len + 2) & 0x3f) ? skb->len + 2 : skb->len + 3;
 	int res;
 	__u16 l16 = skb->len;
@@ -804,7 +800,7 @@ static int pegasus_start_xmit(struct sk_
 
 static struct net_device_stats *pegasus_netdev_stats(struct net_device *dev)
 {
-	return &((pegasus_t *) dev->priv)->stats;
+	return &((pegasus_t *) netdev_priv(dev))->stats;
 }
 
 static inline void disable_net_traffic(pegasus_t * pegasus)
@@ -832,10 +828,9 @@ static inline void get_interrupt_interva
 
 static void set_carrier(struct net_device *net)
 {
-	pegasus_t *pegasus;
+	pegasus_t *pegasus = netdev_priv(net);
 	short tmp;
 
-	pegasus = net->priv;
 	read_mii_word(pegasus, pegasus->phy, MII_BMSR, &tmp);
 	if (tmp & BMSR_LSTATUS)
 		netif_carrier_on(net);
@@ -890,7 +885,7 @@ static int alloc_urbs(pegasus_t * pegasu
 
 static int pegasus_open(struct net_device *net)
 {
-	pegasus_t *pegasus = (pegasus_t *) net->priv;
+	pegasus_t *pegasus = netdev_priv(net);
 	int res;
 
 	if (pegasus->rx_skb == NULL)
@@ -933,7 +928,7 @@ exit:
 
 static int pegasus_close(struct net_device *net)
 {
-	pegasus_t *pegasus = net->priv;
+	pegasus_t *pegasus = netdev_priv(net);
 
 	pegasus->flags &= ~PEGASUS_RUNNING;
 	netif_stop_queue(net);
@@ -944,177 +939,120 @@ static int pegasus_close(struct net_devi
 
 	return 0;
 }
-#ifdef	CONFIG_MII
-static int pegasus_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
-{
 
-	u32 ethcmd;
-	pegasus_t *pegasus = dev->priv;
+void pegasus_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	strncpy(info->driver, driver_name, sizeof (info->driver) - 1);
+	strncpy(info->version, DRIVER_VERSION, sizeof (info->version) - 1);
+	usb_make_path(pegasus->usb, info->bus_info, sizeof (info->bus_info));
+}
 
-	if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
-		return -EFAULT;
+#ifdef	CONFIG_MII
+static int pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	mii_ethtool_gset(&pegasus->mii, ecmd);
+	return 0;
+}
+static int pegasus_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	return mii_ethtool_sset(&pegasus->mii, &ecmd);
+}
 
-	switch (ethcmd) {
-	/* get driver-specific version/etc. info */
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo info;
-			memset (&info, 0, sizeof (info));
-			info.cmd = ETHTOOL_GDRVINFO;
-			strncpy(info.driver, driver_name,
-				sizeof (info.driver) - 1);
-			strncpy(info.version, DRIVER_VERSION,
-				sizeof (info.version) - 1);
-			usb_make_path(pegasus->usb, info.bus_info,
-				      sizeof (info.bus_info));
-			if (copy_to_user(useraddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
+static int pegasus_nway_reset(struct net_device *dev)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	return mii_nway_restart(&pegasus->mii);
+}
 
-	/* get settings */
-	case ETHTOOL_GSET:{
-			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
-			mii_ethtool_gset(&pegasus->mii, &ecmd);
-			if (copy_to_user(useraddr, &ecmd, sizeof (ecmd)))
-				return -EFAULT;
-			return 0;
-		}
-	/* set settings */
-	case ETHTOOL_SSET:{
-			int r;
-			struct ethtool_cmd ecmd;
-			if (copy_from_user(&ecmd, useraddr, sizeof (ecmd)))
-				return -EFAULT;
-			r = mii_ethtool_sset(&pegasus->mii, &ecmd);
-			return r;
-		}
-	/* restart autonegotiation */
-	case ETHTOOL_NWAY_RST:{
-			return mii_nway_restart(&pegasus->mii);
-		}
+static u32 pegasus_get_link(struct net_device *dev)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	return mii_link_ok(&pegasus->mii);
+}
 
-	/* get link status */
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-			edata.data = mii_link_ok(&pegasus->mii);
-			if (copy_to_user(useraddr, &edata, sizeof (edata)))
-				return -EFAULT;
-			return 0;
-		}
-	/* get message-level */
-	case ETHTOOL_GMSGLVL:{
-			struct ethtool_value edata = { ETHTOOL_GMSGLVL };
-			/* edata.data = pegasus->msg_enable; FIXME */
-			if (copy_to_user(useraddr, &edata, sizeof (edata)))
-				return -EFAULT;
-			return 0;
-		}
-	/* set message-level */
-	case ETHTOOL_SMSGLVL:{
-			struct ethtool_value edata;
-			if (copy_from_user(&edata, useraddr, sizeof (edata)))
-				return -EFAULT;
-			/* sp->msg_enable = edata.data; FIXME */
-			return 0;
-		}
+static u32 pegasus_get_msglevel(struct net_device *dev)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	/* return pegasus->msg_enable; FIXME */
+	return 0;
+}
 
-	}
+static void pegasus_set_msglevel(struct net_device *dev, u32 v)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	/* pegasus->msg_enable = edata.data; FIXME */
+}
 
-	return -EOPNOTSUPP;
+static struct ethtool_ops ops = {
+	.get_drvinfo = pegasus_get_drvinfo,
+	.get_settings = pegasus_get_settings,
+	.set_settings = pegasus_set_settings,
+	.nway_reset = pegasus_nway_reset,
+	.get_link = pegasus_get_link,
+	.get_msglevel = pegasus_get_msglevel,
+	.set_msglevel = pegasus_set_msglevel,
+};
 
-}
 #else
-static int pegasus_ethtool_ioctl(struct net_device *net, void __user *uaddr)
-{
-	pegasus_t *pegasus;
-	int cmd;
-
-	pegasus = net->priv;
-	if (get_user(cmd, (int __user *) uaddr))
-		return -EFAULT;
-	switch (cmd) {
-	case ETHTOOL_GDRVINFO:{
-			struct ethtool_drvinfo info;
-			memset (&info, 0, sizeof (info));
-			info.cmd = ETHTOOL_GDRVINFO;
-			strncpy(info.driver, driver_name,
-				sizeof (info.driver) - 1);
-			strncpy(info.version, DRIVER_VERSION,
-				sizeof (info.version) - 1);
-			usb_make_path(pegasus->usb, info.bus_info,
-				      sizeof (info.bus_info));
-			if (copy_to_user(uaddr, &info, sizeof (info)))
-				return -EFAULT;
-			return 0;
-		}
-	case ETHTOOL_GSET:{
-			struct ethtool_cmd ecmd;
-			short lpa, bmcr;
-			u8 port;
-
-			memset(&ecmd, 0, sizeof (ecmd));
-			ecmd.supported = (SUPPORTED_10baseT_Half |
-					  SUPPORTED_10baseT_Full |
-					  SUPPORTED_100baseT_Half |
-					  SUPPORTED_100baseT_Full |
-					  SUPPORTED_Autoneg |
-					  SUPPORTED_TP | SUPPORTED_MII);
-			get_registers(pegasus, Reg7b, 1, &port);
-			if (port == 0)
-				ecmd.port = PORT_MII;
-			else
-				ecmd.port = PORT_TP;
-			ecmd.transceiver = XCVR_INTERNAL;
-			ecmd.phy_address = pegasus->phy;
-			read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
-			read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
-			if (bmcr & BMCR_ANENABLE) {
-				ecmd.autoneg = AUTONEG_ENABLE;
-				ecmd.speed = lpa & (LPA_100HALF | LPA_100FULL) ?
-				    SPEED_100 : SPEED_10;
-				if (ecmd.speed == SPEED_100)
-					ecmd.duplex = lpa & LPA_100FULL ?
-					    DUPLEX_FULL : DUPLEX_HALF;
-				else
-					ecmd.duplex = lpa & LPA_10FULL ?
-					    DUPLEX_FULL : DUPLEX_HALF;
-			} else {
-				ecmd.autoneg = AUTONEG_DISABLE;
-				ecmd.speed = bmcr & BMCR_SPEED100 ?
-				    SPEED_100 : SPEED_10;
-				ecmd.duplex = bmcr & BMCR_FULLDPLX ?
-				    DUPLEX_FULL : DUPLEX_HALF;
-			}
-			if (copy_to_user(uaddr, &ecmd, sizeof (ecmd)))
-				return -EFAULT;
 
-			return 0;
-		}
-	case ETHTOOL_SSET:{
-			return -EOPNOTSUPP;
-		}
-	case ETHTOOL_GLINK:{
-			struct ethtool_value edata = { ETHTOOL_GLINK };
-			edata.data = netif_carrier_ok(net);
-			if (copy_to_user(uaddr, &edata, sizeof (edata)))
-				return -EFAULT;
-			return 0;
-		}
-	default:
-		return -EOPNOTSUPP;
+static int pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	pegasus_t *pegasus = netdev_priv(dev);
+	short lpa, bmcr;
+	u8 port;
+
+	ecmd->supported = (SUPPORTED_10baseT_Half |
+			  SUPPORTED_10baseT_Full |
+			  SUPPORTED_100baseT_Half |
+			  SUPPORTED_100baseT_Full |
+			  SUPPORTED_Autoneg |
+			  SUPPORTED_TP | SUPPORTED_MII);
+	get_registers(pegasus, Reg7b, 1, &port);
+	if (port == 0)
+		ecmd->port = PORT_MII;
+	else
+		ecmd->port = PORT_TP;
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = pegasus->phy;
+	read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
+	read_mii_word(pegasus, pegasus->phy, MII_LPA, &lpa);
+	if (bmcr & BMCR_ANENABLE) {
+		ecmd->autoneg = AUTONEG_ENABLE;
+		ecmd->speed = lpa & (LPA_100HALF | LPA_100FULL) ?
+		    SPEED_100 : SPEED_10;
+		if (ecmd->speed == SPEED_100)
+			ecmd->duplex = lpa & LPA_100FULL ?
+			    DUPLEX_FULL : DUPLEX_HALF;
+		else
+			ecmd->duplex = lpa & LPA_10FULL ?
+			    DUPLEX_FULL : DUPLEX_HALF;
+	} else {
+		ecmd->autoneg = AUTONEG_DISABLE;
+		ecmd->speed = bmcr & BMCR_SPEED100 ?
+		    SPEED_100 : SPEED_10;
+		ecmd->duplex = bmcr & BMCR_FULLDPLX ?
+		    DUPLEX_FULL : DUPLEX_HALF;
 	}
+	return 0;
 }
+
+static struct ethtool_ops ops = {
+	.get_drvinfo = pegasus_get_drvinfo,
+	.get_settings = pegasus_get_settings,
+	.get_link = ethtool_op_get_link,
+};
 #endif
+
 static int pegasus_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
 {
 	__u16 *data = (__u16 *) & rq->ifr_ifru;
-	pegasus_t *pegasus = net->priv;
+	pegasus_t *pegasus = netdev_priv(net);
 	int res;
 
 	switch (cmd) {
-	case SIOCETHTOOL:
-		res = pegasus_ethtool_ioctl(net, rq->ifr_data);
-		break;
 	case SIOCDEVPRIVATE:
 		data[0] = pegasus->phy;
 	case SIOCDEVPRIVATE + 1:
@@ -1135,7 +1073,7 @@ static int pegasus_ioctl(struct net_devi
 
 static void pegasus_set_multicast(struct net_device *net)
 {
-	pegasus_t *pegasus = net->priv;
+	pegasus_t *pegasus = netdev_priv(net);
 
 	if (net->flags & IFF_PROMISC) {
 		pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
@@ -1211,11 +1149,13 @@ static int pegasus_probe(struct usb_inte
 	int res = -ENOMEM;
 
 	usb_get_dev(dev);
-	if (!(pegasus = kmalloc(sizeof (struct pegasus), GFP_KERNEL))) {
+	net = alloc_etherdev(sizeof(struct pegasus));
+	if (!net) {
 		err("out of memory allocating device structure");
 		goto out;
 	}
 
+	pegasus = netdev_priv(net);
 	memset(pegasus, 0, sizeof (struct pegasus));
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head(&pegasus->ctrl_wait);
@@ -1223,16 +1163,11 @@ static int pegasus_probe(struct usb_inte
 	if (!alloc_urbs(pegasus))
 		goto out1;
 
-	net = alloc_etherdev(0);
-	if (!net)
-		goto out2;
-
 	tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus);
 
 	pegasus->usb = dev;
 	pegasus->net = net;
 	SET_MODULE_OWNER(net);
-	net->priv = pegasus;
 	net->open = pegasus_open;
 	net->stop = pegasus_close;
 	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
@@ -1242,6 +1177,7 @@ static int pegasus_probe(struct usb_inte
 	net->set_multicast_list = pegasus_set_multicast;
 	net->get_stats = pegasus_netdev_stats;
 	net->mtu = PEGASUS_MTU;
+	SET_ETHTOOL_OPS(net, &ops);
 	pegasus->mii.dev = net;
 	pegasus->mii.mdio_read = mdio_read;
 	pegasus->mii.mdio_write = mdio_write;
@@ -1254,7 +1190,7 @@ static int pegasus_probe(struct usb_inte
 	if (reset_mac(pegasus)) {
 		err("can't reset MAC");
 		res = -EIO;
-		goto out3;
+		goto out2;
 	}
 	set_ethernet_addr(pegasus);
 	fill_skb_pool(pegasus);
@@ -1271,19 +1207,17 @@ static int pegasus_probe(struct usb_inte
 	SET_NETDEV_DEV(net, &intf->dev);
 	res = register_netdev(net);
 	if (res)
-		goto out4;
+		goto out3;
 	printk("%s: %s\n", net->name, usb_dev_id[dev_index].name);
 	return 0;
 
-out4:
+out3:
 	usb_set_intfdata(intf, NULL);
 	free_skb_pool(pegasus);
-out3:
-	free_netdev(net);
 out2:
 	free_all_urbs(pegasus);
 out1:
-	kfree(pegasus);
+	free_netdev(net);
 out:
 	usb_put_dev(dev);
 	return res;
@@ -1307,7 +1241,6 @@ static void pegasus_disconnect(struct us
 	if (pegasus->rx_skb)
 		dev_kfree_skb(pegasus->rx_skb);
 	free_netdev(pegasus->net);
-	kfree(pegasus);
 }
 
 static struct usb_driver pegasus_driver = {
diff -puN drivers/usb/net/rtl8150.c~bk-netdev drivers/usb/net/rtl8150.c
--- 25/drivers/usb/net/rtl8150.c~bk-netdev	2004-09-06 18:43:15.735878168 -0700
+++ 25-akpm/drivers/usb/net/rtl8150.c	2004-09-06 18:43:15.885855368 -0700
@@ -304,15 +304,12 @@ static inline void set_ethernet_addr(rtl
 static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
 {
 	struct sockaddr *addr = p;
-	rtl8150_t *dev;
+	rtl8150_t *dev = netdev_priv(netdev);
 	int i;
 
 	if (netif_running(netdev))
 		return -EBUSY;
-	dev = netdev->priv;
-	if (dev == NULL) {
-		return -ENODEV;
-	}
+
 	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
 	dbg("%s: Setting MAC address to ", netdev->name);
 	for (i = 0; i < 5; i++)
@@ -651,16 +648,12 @@ static void disable_net_traffic(rtl8150_
 
 static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
 {
-	return &((rtl8150_t *) dev->priv)->stats;
+	return &((rtl8150_t *)netdev_priv(dev))->stats;
 }
 
 static void rtl8150_tx_timeout(struct net_device *netdev)
 {
-	rtl8150_t *dev;
-
-	dev = netdev->priv;
-	if (!dev)
-		return;
+	rtl8150_t *dev = netdev_priv(netdev);
 	warn("%s: Tx timeout.", netdev->name);
 	dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
 	usb_unlink_urb(dev->tx_urb);
@@ -669,9 +662,7 @@ static void rtl8150_tx_timeout(struct ne
 
 static void rtl8150_set_multicast(struct net_device *netdev)
 {
-	rtl8150_t *dev;
-
-	dev = netdev->priv;
+	rtl8150_t *dev = netdev_priv(netdev);
 	netif_stop_queue(netdev);
 	if (netdev->flags & IFF_PROMISC) {
 		dev->rx_creg |= cpu_to_le16(0x0001);
@@ -691,11 +682,10 @@ static void rtl8150_set_multicast(struct
 
 static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	rtl8150_t *dev;
+	rtl8150_t *dev = netdev_priv(netdev);
 	int count, res;
 
 	netif_stop_queue(netdev);
-	dev = netdev->priv;
 	count = (skb->len < 60) ? 60 : skb->len;
 	count = (count & 0x3f) ? count : count + 1;
 	dev->tx_skb = skb;
@@ -717,7 +707,7 @@ static int rtl8150_start_xmit(struct sk_
 
 static void set_carrier(struct net_device *netdev)
 {
-	rtl8150_t *dev = netdev->priv;
+	rtl8150_t *dev = netdev_priv(netdev);
 	short tmp;
 
 	get_registers(dev, CSCR, 2, &tmp);
@@ -729,13 +719,9 @@ static void set_carrier(struct net_devic
 
 static int rtl8150_open(struct net_device *netdev)
 {
-	rtl8150_t *dev;
+	rtl8150_t *dev = netdev_priv(netdev);
 	int res;
 
-	dev = netdev->priv;
-	if (dev == NULL) {
-		return -ENODEV;
-	}
 	if (dev->rx_skb == NULL)
 		dev->rx_skb = pull_skb(dev);
 	if (!dev->rx_skb)
@@ -761,13 +747,9 @@ static int rtl8150_open(struct net_devic
 
 static int rtl8150_close(struct net_device *netdev)
 {
-	rtl8150_t *dev;
+	rtl8150_t *dev = netdev_priv(netdev);
 	int res = 0;
 
-	dev = netdev->priv;
-	if (!dev)
-		return -ENODEV;
-
 	netif_stop_queue(netdev);
 	if (!test_bit(RTL8150_UNPLUG, &dev->flags))
 		disable_net_traffic(dev);
@@ -776,93 +758,64 @@ static int rtl8150_close(struct net_devi
 	return res;
 }
 
-static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr)
+static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
 {
-	rtl8150_t *dev;
-	int cmd;
-
-	dev = netdev->priv;
-	if (get_user(cmd, (int __user *) uaddr))
-		return -EFAULT;
+	rtl8150_t *dev = netdev_priv(netdev);
 
-	switch (cmd) {
-	case ETHTOOL_GDRVINFO:{
-		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-
-		strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
-		strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-		usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
-		if (copy_to_user(uaddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-		}
-	case ETHTOOL_GSET:{
-		struct ethtool_cmd ecmd;
-		short lpa, bmcr;
-
-		if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-			return -EFAULT;
-		ecmd.supported = (SUPPORTED_10baseT_Half |
-				  SUPPORTED_10baseT_Full |
-				  SUPPORTED_100baseT_Half |
-				  SUPPORTED_100baseT_Full |
-				  SUPPORTED_Autoneg |
-				  SUPPORTED_TP | SUPPORTED_MII);
-		ecmd.port = PORT_TP;
-		ecmd.transceiver = XCVR_INTERNAL;
-		ecmd.phy_address = dev->phy;
-		get_registers(dev, BMCR, 2, &bmcr);
-		get_registers(dev, ANLP, 2, &lpa);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
-			             SPEED_100 : SPEED_10;
-			if (ecmd.speed == SPEED_100)
-				ecmd.duplex = (lpa & LPA_100FULL) ?
-				    DUPLEX_FULL : DUPLEX_HALF;
-			else
-				ecmd.duplex = (lpa & LPA_10FULL) ?
-				    DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed = (bmcr & BMCR_SPEED100) ?
-			    SPEED_100 : SPEED_10;
-			ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
+	strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+	strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+	usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+}
+
+static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	rtl8150_t *dev = netdev_priv(netdev);
+	short lpa, bmcr;
+
+	ecmd->supported = (SUPPORTED_10baseT_Half |
+			  SUPPORTED_10baseT_Full |
+			  SUPPORTED_100baseT_Half |
+			  SUPPORTED_100baseT_Full |
+			  SUPPORTED_Autoneg |
+			  SUPPORTED_TP | SUPPORTED_MII);
+	ecmd->port = PORT_TP;
+	ecmd->transceiver = XCVR_INTERNAL;
+	ecmd->phy_address = dev->phy;
+	get_registers(dev, BMCR, 2, &bmcr);
+	get_registers(dev, ANLP, 2, &lpa);
+	if (bmcr & BMCR_ANENABLE) {
+		ecmd->autoneg = AUTONEG_ENABLE;
+		ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
+			     SPEED_100 : SPEED_10;
+		if (ecmd->speed == SPEED_100)
+			ecmd->duplex = (lpa & LPA_100FULL) ?
 			    DUPLEX_FULL : DUPLEX_HALF;
-		}
-		if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-			return -EFAULT;
-		return 0;
-		}
-	case ETHTOOL_SSET:
-		return -ENOTSUPP;
-	case ETHTOOL_GLINK:{
-		struct ethtool_value edata = { ETHTOOL_GLINK };
-
-		edata.data = netif_carrier_ok(netdev);
-		if (copy_to_user(uaddr, &edata, sizeof(edata)))
-			return -EFAULT;
-		return 0;
-		}
-	default:
-		return -EOPNOTSUPP;
+		else
+			ecmd->duplex = (lpa & LPA_10FULL) ?
+			    DUPLEX_FULL : DUPLEX_HALF;
+	} else {
+		ecmd->autoneg = AUTONEG_DISABLE;
+		ecmd->speed = (bmcr & BMCR_SPEED100) ?
+		    SPEED_100 : SPEED_10;
+		ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?
+		    DUPLEX_FULL : DUPLEX_HALF;
 	}
+	return 0;
 }
 
+static struct ethtool_ops ops = {
+	.get_drvinfo = rtl8150_get_drvinfo,
+	.get_settings = rtl8150_get_settings,
+	.get_link = ethtool_op_get_link
+};
+
 static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
-	rtl8150_t *dev;
-	u16 *data;
-	int res;
-
-	dev = netdev->priv;
-	data = (u16 *) & rq->ifr_ifru;
-	res = 0;
+	rtl8150_t *dev = netdev_priv(netdev);
+	u16 *data = (u16 *) & rq->ifr_ifru;
+	int res = 0;
 
 	switch (cmd) {
-	case SIOCETHTOOL:
-		res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
-		break;
 	case SIOCDEVPRIVATE:
 		data[0] = dev->phy;
 	case SIOCDEVPRIVATE + 1:
@@ -887,23 +840,18 @@ static int rtl8150_probe(struct usb_inte
 	rtl8150_t *dev;
 	struct net_device *netdev;
 
-	dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
-	if (!dev) {
+	netdev = alloc_etherdev(sizeof(rtl8150_t));
+	if (!netdev) {
 		err("Out of memory");
 		return -ENOMEM;
-	} else
-		memset(dev, 0, sizeof(rtl8150_t));
+	}
+
+	dev = netdev_priv(netdev);
+	memset(dev, 0, sizeof(rtl8150_t));
 
 	dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
 	if (!dev->intr_buff) {
-		kfree(dev);
-		return -ENOMEM;
-	}
-	netdev = alloc_etherdev(0);
-	if (!netdev) {
-		kfree(dev->intr_buff);
-		kfree(dev);
-		err("Oh boy, out of memory again?!?");
+		free_netdev(netdev);
 		return -ENOMEM;
 	}
 
@@ -913,7 +861,6 @@ static int rtl8150_probe(struct usb_inte
 	dev->udev = udev;
 	dev->netdev = netdev;
 	SET_MODULE_OWNER(netdev);
-	netdev->priv = dev;
 	netdev->open = rtl8150_open;
 	netdev->stop = rtl8150_close;
 	netdev->do_ioctl = rtl8150_ioctl;
@@ -924,6 +871,7 @@ static int rtl8150_probe(struct usb_inte
 	netdev->set_mac_address = rtl8150_set_mac_address;
 	netdev->get_stats = rtl8150_netdev_stats;
 	netdev->mtu = RTL8150_MTU;
+	SET_ETHTOOL_OPS(netdev, &ops);
 	dev->intr_interval = 100;	/* 100ms */
 
 	if (!alloc_all_urbs(dev)) {
@@ -954,7 +902,6 @@ out1:
 out:
 	kfree(dev->intr_buff);
 	free_netdev(netdev);
-	kfree(dev);
 	return -EIO;
 }
 
@@ -971,9 +918,8 @@ static void rtl8150_disconnect(struct us
 		free_skb_pool(dev);
 		if (dev->rx_skb)
 			dev_kfree_skb(dev->rx_skb);
-		free_netdev(dev->netdev);
 		kfree(dev->intr_buff);
-		kfree(dev);
+		free_netdev(dev->netdev);
 	}
 }
 
diff -puN include/linux/netdevice.h~bk-netdev include/linux/netdevice.h
--- 25/include/linux/netdevice.h~bk-netdev	2004-09-06 18:43:15.736878016 -0700
+++ 25-akpm/include/linux/netdevice.h	2004-09-06 18:43:15.886855216 -0700
@@ -304,7 +304,9 @@ struct net_device
 
 	/* List of functions to handle Wireless Extensions (instead of ioctl).
 	 * See <net/iw_handler.h> for details. Jean II */
-	struct iw_handler_def *	wireless_handlers;
+	const struct iw_handler_def *	wireless_handlers;
+	/* Instance data managed by the core of Wireless Extensions. */
+	struct iw_public_data *	wireless_data;
 
 	struct ethtool_ops *ethtool_ops;
 
diff -puN include/linux/wireless.h~bk-netdev include/linux/wireless.h
--- 25/include/linux/wireless.h~bk-netdev	2004-09-06 18:43:15.738877712 -0700
+++ 25-akpm/include/linux/wireless.h	2004-09-06 18:43:15.887855064 -0700
@@ -1,10 +1,10 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	16	2.4.03
+ * Version :	17	21.6.04
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _LINUX_WIRELESS_H
@@ -47,12 +47,12 @@
  *	# include/net/iw_handler.h
  *
  * Note as well that /proc/net/wireless implementation has now moved in :
- *	# include/linux/wireless.c
+ *	# net/core/wireless.c
  *
  * Wireless Events (2002 -> onward) :
  * --------------------------------
  * Events are defined at the end of this file, and implemented in :
- *	# include/linux/wireless.c
+ *	# net/core/wireless.c
  *
  * Other comments :
  * --------------
@@ -82,7 +82,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	16
+#define WIRELESS_EXT	17
 
 /*
  * Changes :
@@ -175,6 +175,13 @@
  *	- Remove IW_MAX_GET_SPY because conflict with enhanced spy support
  *	- Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
  *	- Add IW_ENCODE_TEMP and iw_range->encoding_login_index
+ *
+ * V16 to V17
+ * ----------
+ *	- Add flags to frequency -> auto/fixed
+ *	- Document (struct iw_quality *)->updated, add new flags (INVALID)
+ *	- Wireless Event capability in struct iw_range
+ *	- Add support for relative TxPower (yick !)
  */
 
 /**************************** CONSTANTS ****************************/
@@ -251,7 +258,7 @@
 
 /* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
 
-/* These 16 ioctl are wireless device private.
+/* These 32 ioctl are wireless device private, for 16 commands.
  * Each driver is free to use them for whatever purpose it chooses,
  * however the driver *must* export the description of those ioctls
  * with SIOCGIWPRIV and *must* use arguments as defined below.
@@ -266,8 +273,8 @@
  * We now have 32 commands, so a bit more space ;-).
  * Also, all 'odd' commands are only usable by root and don't return the
  * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command).
- * And I repeat : you are not obliged to use them with iwspy, but you
+ * convention, just use every other two command). More details in iwpriv.c.
+ * And I repeat : you are not forced to use them with iwpriv, but you
  * must be compliant with it.
  */
 
@@ -352,6 +359,18 @@
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
 #define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
+/* Statistics flags (bitmask in updated) */
+#define IW_QUAL_QUAL_UPDATED	0x1	/* Value was updated since last read */
+#define IW_QUAL_LEVEL_UPDATED	0x2
+#define IW_QUAL_NOISE_UPDATED	0x4
+#define IW_QUAL_QUAL_INVALID	0x10	/* Driver doesn't provide value */
+#define IW_QUAL_LEVEL_INVALID	0x20
+#define IW_QUAL_NOISE_INVALID	0x40
+
+/* Frequency flags */
+#define IW_FREQ_AUTO		0x00	/* Let the driver decides */
+#define IW_FREQ_FIXED		0x01	/* Force a specific value */
+
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
 #define IW_MAX_ENCODING_SIZES	8
@@ -390,6 +409,7 @@
 #define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RELATIVE	0x0002	/* Value is in arbitrary units */
 #define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
@@ -418,6 +438,25 @@
 /* Max number of char in custom event - use multiple of them if needed */
 #define IW_CUSTOM_MAX		256	/* In bytes */
 
+/* Event capability macros - in (struct iw_range *)->event_capa
+ * Because we have more than 32 possible events, we use an array of
+ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
+#define IW_EVENT_CAPA_BASE(cmd)		((cmd >= SIOCIWFIRSTPRIV) ? \
+					 (cmd - SIOCIWFIRSTPRIV + 0x60) : \
+					 (cmd - SIOCSIWCOMMIT))
+#define IW_EVENT_CAPA_INDEX(cmd)	(IW_EVENT_CAPA_BASE(cmd) >> 5)
+#define IW_EVENT_CAPA_MASK(cmd)		(1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
+/* Event capability constants - event autogenerated by the kernel
+ * This list is valid for most 802.11 devices, customise as needed... */
+#define IW_EVENT_CAPA_K_0	(IW_EVENT_CAPA_MASK(0x8B04) | \
+				 IW_EVENT_CAPA_MASK(0x8B06) | \
+				 IW_EVENT_CAPA_MASK(0x8B1A))
+#define IW_EVENT_CAPA_K_1	(IW_EVENT_CAPA_MASK(0x8B2A))
+/* "Easy" macro to set events in iw_range (less efficient) */
+#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
+#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
+
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -456,7 +495,7 @@ struct	iw_freq
 	__s32		m;		/* Mantissa */
 	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
-	__u8		pad;		/* Unused - just for alignement */
+	__u8		flags;		/* Flags (fixed/auto) */
 };
 
 /*
@@ -610,11 +649,12 @@ struct	iw_range
 	/* Old Frequency (backward compat - moved lower ) */
 	__u16		old_num_channels;
 	__u8		old_num_frequency;
-	/* Filler to keep "version" at the same offset */
-	__s32		old_freq[6];
+
+	/* Wireless event capability bitmasks */
+	__u32		event_capa[6];
 
 	/* signal level threshold range */
-	__s32	sensitivity;
+	__s32		sensitivity;
 
 	/* Quality of link & SNR stuff */
 	/* Quality range (link, level, noise)
diff -puN include/net/iw_handler.h~bk-netdev include/net/iw_handler.h
--- 25/include/net/iw_handler.h~bk-netdev	2004-09-06 18:43:15.739877560 -0700
+++ 25-akpm/include/net/iw_handler.h	2004-09-06 18:43:15.889854760 -0700
@@ -1,10 +1,10 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	5	4.12.02
+ * Version :	6	21.6.04
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 2001-2004 Jean Tourrilhes, All Rights Reserved.
  */
 
 #ifndef _IW_HANDLER_H
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	5
+#define IW_HANDLER_VERSION	6
 
 /*
  * Changes :
@@ -224,11 +224,18 @@
  * V4 to V5
  * --------
  *	- Add new spy support : struct iw_spy_data & prototypes
+ *
+ * V5 to V6
+ * --------
+ *	- Change the way we get to spy_data method for added safety
+ *	- Remove spy #ifdef, they are always on -> cleaner code
+ *	- Add IW_DESCR_FLAG_NOMAX flag for very large requests
+ *	- Start migrating get_wireless_stats to struct iw_handler_def
  */
 
 /**************************** CONSTANTS ****************************/
 
-/* Enable enhanced spy support. Disable to reduce footprint */
+/* Enhanced spy support available */
 #define IW_WIRELESS_SPY
 #define IW_WIRELESS_THRSPY
 
@@ -258,6 +265,7 @@
 #define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
 #define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
 				/* SET : Omit payload from generated iwevent */
+#define IW_DESCR_FLAG_NOMAX	0x0008	/* GET : no limit on request size */
 /* Driver level flags */
 #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
 
@@ -303,31 +311,33 @@ struct iw_handler_def
 {
 	/* Number of handlers defined (more precisely, index of the
 	 * last defined handler + 1) */
-	__u16			num_standard;
-	__u16			num_private;
+	const __u16		num_standard;
+	const __u16		num_private;
 	/* Number of private arg description */
-	__u16			num_private_args;
+	const __u16		num_private_args;
 
 	/* Array of handlers for standard ioctls
 	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
 	 */
-	iw_handler *		standard;
+	const iw_handler *	standard;
 
 	/* Array of handlers for private ioctls
 	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
 	 */
-	iw_handler *		private;
+	const iw_handler *	private;
 
 	/* Arguments of private handler. This one is just a list, so you
 	 * can put it in any order you want and should not leave holes...
 	 * We will automatically export that to user space... */
-	struct iw_priv_args *	private_args;
+	const struct iw_priv_args *	private_args;
 
-	/* Driver enhanced spy support */
-	long			spy_offset;	/* Spy data offset */
+	/* This field will be *removed* in the next version of WE */
+	const long		spy_offset;	/* DO NOT USE */
 
-	/* In the long term, get_wireless_stats will move from
-	 * 'struct net_device' to here, to minimise bloat. */
+	/* New location of get_wireless_stats, to de-bloat struct net_device.
+	 * The old pointer in struct net_device will be gradually phased
+	 * out, and drivers are encouraged to use this one... */
+	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
 };
 
 /* ---------------------- IOCTL DESCRIPTION ---------------------- */
@@ -374,18 +384,29 @@ struct iw_ioctl_description
  */
 struct iw_spy_data
 {
-#ifdef IW_WIRELESS_SPY
 	/* --- Standard spy support --- */
 	int			spy_number;
 	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
 	struct iw_quality	spy_stat[IW_MAX_SPY];
-#ifdef IW_WIRELESS_THRSPY
 	/* --- Enhanced spy support (event) */
 	struct iw_quality	spy_thr_low;	/* Low threshold */
 	struct iw_quality	spy_thr_high;	/* High threshold */
 	u_char			spy_thr_under[IW_MAX_SPY];
-#endif /* IW_WIRELESS_THRSPY */
-#endif /* IW_WIRELESS_SPY */
+};
+
+/* --------------------- DEVICE WIRELESS DATA --------------------- */
+/*
+ * This is all the wireless data specific to a device instance that
+ * is managed by the core of Wireless Extensions.
+ * We only keep pointer to those structures, so that a driver is free
+ * to share them between instances.
+ * This structure should be initialised before registering the device.
+ * Access to this data follow the same rules as any other struct net_device
+ * data (i.e. valid as long as struct net_device exist, same locking rules).
+ */
+struct iw_public_data {
+	/* Driver enhanced spy support */
+	struct iw_spy_data *	spy_data;
 };
 
 /**************************** PROTOTYPES ****************************/
@@ -394,6 +415,9 @@ struct iw_spy_data
  * Those may be called only within the kernel.
  */
 
+/* Data needed by fs/compat_ioctl.c for 32->64 bit conversion */
+extern const char iw_priv_type_size[];
+
 /* First : function strictly used inside the kernel */
 
 /* Handle /proc/net/wireless, called in net/code/dev.c */
diff -puN net/core/dev.c~bk-netdev net/core/dev.c
--- 25/net/core/dev.c~bk-netdev	2004-09-06 18:43:15.741877256 -0700
+++ 25-akpm/net/core/dev.c	2004-09-06 18:43:15.891854456 -0700
@@ -2771,7 +2771,7 @@ int dev_ioctl(unsigned int cmd, void __u
 				/* Follow me in net/core/wireless.c */
 				ret = wireless_process_ioctl(&ifr, cmd);
 				rtnl_unlock();
-				if (!ret && IW_IS_GET(cmd) &&
+				if (IW_IS_GET(cmd) &&
 				    copy_to_user(arg, &ifr,
 					    	 sizeof(struct ifreq)))
 					ret = -EFAULT;
diff -puN net/core/wireless.c~bk-netdev net/core/wireless.c
--- 25/net/core/wireless.c~bk-netdev	2004-09-06 18:43:15.743876952 -0700
+++ 25-akpm/net/core/wireless.c	2004-09-06 18:43:15.895853848 -0700
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2004 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
@@ -48,6 +48,15 @@
  *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
  *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
  *	o Add WIRELESS_EXT version display in /proc/net/wireless
+ *
+ * v6 - 18.06.04 - Jean II
+ *	o Change get_spydata() method for added safety
+ *	o Remove spy #ifdef, they are always on -> cleaner code
+ *	o Allow any size GET request is user specifies length > max
+ *	o Start migrating get_wireless_stats to struct iw_handler_def
+ *	o Add wmb() in iw_handler_set_spy() for non-coherent archs/cpus
+ * Based on patch from Pavel Roskin <proski@gnu.org> :
+ *	o Fix kernel data leak to user space in private handler handling
  */
 
 /***************************** INCLUDES *****************************/
@@ -69,10 +78,6 @@
 
 /**************************** CONSTANTS ****************************/
 
-/* Enough lenience, let's make sure things are proper... */
-#define WE_STRICT_WRITE		/* Check write buffer size */
-/* I'll probably drop both the define and kernel message in the next version */
-
 /* Debugging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
 #undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
@@ -186,6 +191,7 @@ static const struct iw_ioctl_description
 		.token_size	= sizeof(struct sockaddr) +
 				  sizeof(struct iw_quality),
 		.max_tokens	= IW_MAX_AP,
+		.flags		= IW_DESCR_FLAG_NOMAX,
 	},
 	[SIOCSIWSCAN	- SIOCIWFIRST] = {
 		.header_type	= IW_HEADER_TYPE_PARAM,
@@ -194,6 +200,7 @@ static const struct iw_ioctl_description
 		.header_type	= IW_HEADER_TYPE_POINT,
 		.token_size	= 1,
 		.max_tokens	= IW_SCAN_MAX_DATA,
+		.flags		= IW_DESCR_FLAG_NOMAX,
 	},
 	[SIOCSIWESSID	- SIOCIWFIRST] = {
 		.header_type	= IW_HEADER_TYPE_POINT,
@@ -296,7 +303,7 @@ static const int standard_event_num = (s
 				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = {
+const char iw_priv_type_size[] = {
 	0,				/* IW_PRIV_TYPE_NONE */
 	1,				/* IW_PRIV_TYPE_BYTE */
 	1,				/* IW_PRIV_TYPE_CHAR */
@@ -363,12 +370,15 @@ static inline iw_handler get_handler(str
  */
 static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
 {
+	/* New location */
+	if((dev->wireless_handlers != NULL) &&
+	   (dev->wireless_handlers->get_wireless_stats != NULL))
+		return dev->wireless_handlers->get_wireless_stats(dev);
+
+	/* Old location, will be phased out in next WE */
 	return (dev->get_wireless_stats ?
 		dev->get_wireless_stats(dev) :
 		(struct iw_statistics *) NULL);
-	/* In the future, get_wireless_stats may move from 'struct net_device'
-	 * to 'struct iw_handler_def', to de-bloat struct net_device.
-	 * Definitely worse a thought... */
 }
 
 /* ---------------------------------------------------------------- */
@@ -403,14 +413,32 @@ static inline int call_commit_handler(st
 
 /* ---------------------------------------------------------------- */
 /*
- * Number of private arguments
+ * Calculate size of private arguments
  */
 static inline int get_priv_size(__u16	args)
 {
 	int	num = args & IW_PRIV_SIZE_MASK;
 	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
 
-	return num * priv_type_size[type];
+	return num * iw_priv_type_size[type];
+}
+
+/* ---------------------------------------------------------------- */
+/*
+ * Re-calculate the size of private arguments
+ */
+static inline int adjust_priv_size(__u16		args,
+				   union iwreq_data *	wrqu)
+{
+	int	num = wrqu->data.length;
+	int	max = args & IW_PRIV_SIZE_MASK;
+	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
+
+	/* Make sure the driver doesn't goof up */
+	if (max < num)
+		num = max;
+
+	return num * iw_priv_type_size[type];
 }
 
 
@@ -440,11 +468,14 @@ static __inline__ void wireless_seq_prin
 		seq_printf(seq, "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d "
 				"%6d %6d   %6d\n",
 			   dev->name, stats->status, stats->qual.qual,
-			   stats->qual.updated & 1 ? '.' : ' ',
+			   stats->qual.updated & IW_QUAL_QUAL_UPDATED
+			   ? '.' : ' ',
 			   ((__u8) stats->qual.level),
-			   stats->qual.updated & 2 ? '.' : ' ',
+			   stats->qual.updated & IW_QUAL_LEVEL_UPDATED
+			   ? '.' : ' ',
 			   ((__u8) stats->qual.noise),
-			   stats->qual.updated & 4 ? '.' : ' ',
+			   stats->qual.updated & IW_QUAL_NOISE_UPDATED
+			   ? '.' : ' ',
 			   stats->discard.nwid, stats->discard.code,
 			   stats->discard.fragment, stats->discard.retries,
 			   stats->discard.misc, stats->miss.beacon);
@@ -555,13 +586,15 @@ static inline int ioctl_export_private(s
 	/* Check NULL pointer */
 	if(iwr->u.data.pointer == NULL)
 		return -EFAULT;
-#ifdef WE_STRICT_WRITE
+
 	/* Check if there is enough buffer up there */
 	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
-		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+		/* User space can't know in advance how large the buffer
+		 * needs to be. Give it a hint, so that we can support
+		 * any size buffer we want somewhat efficiently... */
+		iwr->u.data.length = dev->wireless_handlers->num_private_args;
 		return -E2BIG;
 	}
-#endif	/* WE_STRICT_WRITE */
 
 	/* Set the number of available ioctls. */
 	iwr->u.data.length = dev->wireless_handlers->num_private_args;
@@ -590,7 +623,6 @@ static inline int ioctl_standard_call(st
 	const struct iw_ioctl_description *	descr;
 	struct iw_request_info			info;
 	int					ret = -EINVAL;
-	int					user_size = 0;
 
 	/* Get the description of the IOCTL */
 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -621,8 +653,14 @@ static inline int ioctl_standard_call(st
 #endif	/* WE_SET_EVENT */
 	} else {
 		char *	extra;
+		int	extra_size;
+		int	user_length = 0;
 		int	err;
 
+		/* Calculate space needed by arguments. Always allocate
+		 * for max space. Easier, and won't last long... */
+		extra_size = descr->max_tokens * descr->token_size;
+
 		/* Check what user space is giving us */
 		if(IW_IS_SET(cmd)) {
 			/* Check NULL pointer */
@@ -639,18 +677,29 @@ static inline int ioctl_standard_call(st
 			if(iwr->u.data.pointer == NULL)
 				return -EFAULT;
 			/* Save user space buffer size for checking */
-			user_size = iwr->u.data.length;
+			user_length = iwr->u.data.length;
+
+			/* Don't check if user_length > max to allow forward
+			 * compatibility. The test user_length < min is
+			 * implied by the test at the end. */
+
+			/* Support for very large requests */
+			if((descr->flags & IW_DESCR_FLAG_NOMAX) &&
+			   (user_length > descr->max_tokens)) {
+				/* Allow userspace to GET more than max so
+				 * we can support any size GET requests.
+				 * There is still a limit : -ENOMEM. */
+				extra_size = user_length * descr->token_size;
+			}
 		}
 
 #ifdef WE_IOCTL_DEBUG
 		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
-		       dev->name, descr->max_tokens * descr->token_size);
+		       dev->name, extra_size);
 #endif	/* WE_IOCTL_DEBUG */
 
-		/* Always allocate for max space. Easier, and won't last
-		 * long... */
-		extra = kmalloc(descr->max_tokens * descr->token_size,
-				GFP_KERNEL);
+		/* Create the kernel buffer */
+		extra = kmalloc(extra_size, GFP_KERNEL);
 		if (extra == NULL) {
 			return -ENOMEM;
 		}
@@ -676,14 +725,11 @@ static inline int ioctl_standard_call(st
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
-#ifdef WE_STRICT_WRITE
 			/* Check if there is enough buffer up there */
-			if(user_size < iwr->u.data.length) {
-				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+			if(user_length < iwr->u.data.length) {
 				kfree(extra);
 				return -E2BIG;
 			}
-#endif	/* WE_STRICT_WRITE */
 
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   iwr->u.data.length *
@@ -746,7 +792,7 @@ static inline int ioctl_private_call(str
 				     iw_handler		handler)
 {
 	struct iwreq *			iwr = (struct iwreq *) ifr;
-	struct iw_priv_args *		descr = NULL;
+	const struct iw_priv_args *	descr = NULL;
 	struct iw_request_info		info;
 	int				extra_size = 0;
 	int				i;
@@ -786,7 +832,7 @@ static inline int ioctl_private_call(str
 			   ((extra_size + offset) <= IFNAMSIZ))
 				extra_size = 0;
 		} else {
-			/* Size of set arguments */
+			/* Size of get arguments */
 			extra_size = get_priv_size(descr->get_args);
 
 			/* Does it fits in iwr ? */
@@ -816,7 +862,7 @@ static inline int ioctl_private_call(str
 				return -EFAULT;
 
 			/* Does it fits within bounds ? */
-			if(iwr->u.data.length > (descr->set_args &
+			if(iwr->u.data.length > (descr->get_args &
 						 IW_PRIV_SIZE_MASK))
 				return -E2BIG;
 		} else {
@@ -856,6 +902,14 @@ static inline int ioctl_private_call(str
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
+
+			/* Adjust for the actual length if it's variable,
+			 * avoid leaking kernel bits outside. */
+			if (!(descr->get_args & IW_PRIV_SIZE_FIXED)) {
+				extra_size = adjust_priv_size(descr->get_args,
+							      &(iwr->u));
+			}
+
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   extra_size);
 			if (err)
@@ -1127,9 +1181,25 @@ void wireless_send_event(struct net_devi
  * One of the main advantage of centralising spy support here is that
  * it becomes much easier to improve and extend it without having to touch
  * the drivers. One example is the addition of the Spy-Threshold events.
- * Note : IW_WIRELESS_SPY is defined in iw_handler.h
  */
 
+/* ---------------------------------------------------------------- */
+/*
+ * Return the pointer to the spy data in the driver.
+ * Because this is called on the Rx path via wireless_spy_update(),
+ * we want it to be efficient...
+ */
+static inline struct iw_spy_data * get_spydata(struct net_device *dev)
+{
+	/* This is the new way */
+	if(dev->wireless_data)
+		return(dev->wireless_data->spy_data);
+
+	/* This is the old way. Doesn't work for multi-headed drivers.
+	 * It will be removed in the next version of WE. */
+	return (dev->priv + dev->wireless_handlers->spy_offset);
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Standard Wireless Handler : set Spy List
@@ -1139,16 +1209,30 @@ int iw_handler_set_spy(struct net_device
 		       union iwreq_data *	wrqu,
 		       char *			extra)
 {
-#ifdef IW_WIRELESS_SPY
-	struct iw_spy_data *	spydata = (dev->priv +
-					   dev->wireless_handlers->spy_offset);
+	struct iw_spy_data *	spydata = get_spydata(dev);
 	struct sockaddr *	address = (struct sockaddr *) extra;
 
+	if(!dev->wireless_data)
+		/* Help user know that driver needs updating */
+		printk(KERN_DEBUG "%s (WE) : Driver using old/buggy spy support, please fix driver !\n",
+		       dev->name);
+	/* Make sure driver is not buggy or using the old API */
+	if(!spydata)
+		return -EOPNOTSUPP;
+
 	/* Disable spy collection while we copy the addresses.
-	 * As we don't disable interrupts, we need to do this to avoid races.
-	 * As we are the only writer, this is good enough. */
+	 * While we copy addresses, any call to wireless_spy_update()
+	 * will NOP. This is OK, as anyway the addresses are changing. */
 	spydata->spy_number = 0;
 
+	/* We want to operate without locking, because wireless_spy_update()
+	 * most likely will happen in the interrupt handler, and therefore
+	 * have it own locking constraints and needs performance.
+	 * The rtnl_lock() make sure we don't race with the other iw_handlers.
+	 * This make sure wireless_spy_update() "see" that the spy list
+	 * is temporarily disabled. */
+	wmb();
+
 	/* Are there are addresses to copy? */
 	if(wrqu->data.length > 0) {
 		int i;
@@ -1174,13 +1258,14 @@ int iw_handler_set_spy(struct net_device
 			       spydata->spy_address[i][5]);
 #endif	/* WE_SPY_DEBUG */
 	}
+
+	/* Make sure above is updated before re-enabling */
+	wmb();
+
 	/* Enable addresses */
 	spydata->spy_number = wrqu->data.length;
 
 	return 0;
-#else /* IW_WIRELESS_SPY */
-	return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_SPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1192,12 +1277,14 @@ int iw_handler_get_spy(struct net_device
 		       union iwreq_data *	wrqu,
 		       char *			extra)
 {
-#ifdef IW_WIRELESS_SPY
-	struct iw_spy_data *	spydata = (dev->priv +
-					   dev->wireless_handlers->spy_offset);
+	struct iw_spy_data *	spydata = get_spydata(dev);
 	struct sockaddr *	address = (struct sockaddr *) extra;
 	int			i;
 
+	/* Make sure driver is not buggy or using the old API */
+	if(!spydata)
+		return -EOPNOTSUPP;
+
 	wrqu->data.length = spydata->spy_number;
 
 	/* Copy addresses. */
@@ -1214,9 +1301,6 @@ int iw_handler_get_spy(struct net_device
 	for(i = 0; i < spydata->spy_number; i++)
 		spydata->spy_stat[i].updated = 0;
 	return 0;
-#else /* IW_WIRELESS_SPY */
-	return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_SPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1228,11 +1312,13 @@ int iw_handler_set_thrspy(struct net_dev
 			  union iwreq_data *	wrqu,
 			  char *		extra)
 {
-#ifdef IW_WIRELESS_THRSPY
-	struct iw_spy_data *	spydata = (dev->priv +
-					   dev->wireless_handlers->spy_offset);
+	struct iw_spy_data *	spydata = get_spydata(dev);
 	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
 
+	/* Make sure driver is not buggy or using the old API */
+	if(!spydata)
+		return -EOPNOTSUPP;
+
 	/* Just do it */
 	memcpy(&(spydata->spy_thr_low), &(threshold->low),
 	       2 * sizeof(struct iw_quality));
@@ -1245,9 +1331,6 @@ int iw_handler_set_thrspy(struct net_dev
 #endif	/* WE_SPY_DEBUG */
 
 	return 0;
-#else /* IW_WIRELESS_THRSPY */
-	return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_THRSPY */
 }
 
 /*------------------------------------------------------------------*/
@@ -1259,22 +1342,20 @@ int iw_handler_get_thrspy(struct net_dev
 			  union iwreq_data *	wrqu,
 			  char *		extra)
 {
-#ifdef IW_WIRELESS_THRSPY
-	struct iw_spy_data *	spydata = (dev->priv +
-					   dev->wireless_handlers->spy_offset);
+	struct iw_spy_data *	spydata = get_spydata(dev);
 	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
 
+	/* Make sure driver is not buggy or using the old API */
+	if(!spydata)
+		return -EOPNOTSUPP;
+
 	/* Just do it */
 	memcpy(&(threshold->low), &(spydata->spy_thr_low),
 	       2 * sizeof(struct iw_quality));
 
 	return 0;
-#else /* IW_WIRELESS_THRSPY */
-	return -EOPNOTSUPP;
-#endif /* IW_WIRELESS_THRSPY */
 }
 
-#ifdef IW_WIRELESS_THRSPY
 /*------------------------------------------------------------------*/
 /*
  * Prepare and send a Spy Threshold event
@@ -1312,7 +1393,6 @@ static void iw_send_thrspy_event(struct 
 	/* Send event to user space */
 	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
 }
-#endif /* IW_WIRELESS_THRSPY */
 
 /* ---------------------------------------------------------------- */
 /*
@@ -1325,12 +1405,14 @@ void wireless_spy_update(struct net_devi
 			 unsigned char *	address,
 			 struct iw_quality *	wstats)
 {
-#ifdef IW_WIRELESS_SPY
-	struct iw_spy_data *	spydata = (dev->priv +
-					   dev->wireless_handlers->spy_offset);
+	struct iw_spy_data *	spydata = get_spydata(dev);
 	int			i;
 	int			match = -1;
 
+	/* Make sure driver is not buggy or using the old API */
+	if(!spydata)
+		return;
+
 #ifdef WE_SPY_DEBUG
 	printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
 #endif	/* WE_SPY_DEBUG */
@@ -1342,7 +1424,7 @@ void wireless_spy_update(struct net_devi
 			       sizeof(struct iw_quality));
 			match = i;
 		}
-#ifdef IW_WIRELESS_THRSPY
+
 	/* Generate an event if we cross the spy threshold.
 	 * To avoid event storms, we have a simple hysteresis : we generate
 	 * event only when we go under the low threshold or above the
@@ -1362,8 +1444,6 @@ void wireless_spy_update(struct net_devi
 			}
 		}
 	}
-#endif /* IW_WIRELESS_THRSPY */
-#endif /* IW_WIRELESS_SPY */
 }
 
 EXPORT_SYMBOL(iw_handler_get_spy);
diff -puN net/irda/irlan/irlan_client.c~bk-netdev net/irda/irlan/irlan_client.c
--- 25/net/irda/irlan/irlan_client.c~bk-netdev	2004-09-06 18:43:15.744876800 -0700
+++ 25-akpm/net/irda/irlan/irlan_client.c	2004-09-06 18:43:15.896853696 -0700
@@ -234,7 +234,7 @@ static void irlan_client_ctrl_disconnect
 	ASSERT(tsap == self->client.tsap_ctrl, return;);
 
        	/* Remove frames queued on the control channel */
-	while ((skb = skb_dequeue(&self->client.txq))) {
+	while ((skb = skb_dequeue(&self->client.txq)) != NULL) {
 		dev_kfree_skb(skb);
 	}
 	self->client.tx_busy = FALSE;
_