Initial import of ethtool version 3 + a few patches.
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b2b9043
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+David Miller <davem@redhat.com>
+Jakub Jelinek <jj@ultra.linux.cz>
+Jeff Garzik <jgarzik@mandrakesoft.com>
+Tim Hockin <thockin@sun.com>
+Eli Kupermann <eli.kupermann@intel.com>
+Chris Leech <christopher.leech@intel.com>
+Scott Feldman <scott.feldman@intel.com>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..379c0bb
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,351 @@
+
+
+NOTE:  For further changelog entries, see BitKeeper repository.
+
+
+Tue Aug 17 2004  Jeff Garzik <jgarzik@pobox.com>
+
+	* NEWS, configure.ac:  Release version 2
+
+Fri Jul  2 2004  Jeff Garzik <jgarzik@pobox.com>
+
+	Merged
+	* fec_8xx.c, ethtool-util.h, Makefile.am: Add fec_8xx register dump.
+	Contributed by Pantelis Antoniou <panto@intracom.gr>
+
+	* Update ethtool.c to iterate through a list of drivers
+	* Fixed fec_8xx.c warnings on 64-bit
+
+Fri Jul  2 2004  Jim Lewis <jim@jklewis.com>
+
+	* pcnet32.c, ethtool-util.h, Makefile.am: Add pcnet32 register dump.
+
+Fri Apr  9 2004  Jason Lunz <lunz@reflexsecurity.com>
+
+	* ethtool.c: Remove incorrect restriction on ethernet interface
+	names.
+
+Fri Apr  9 2004  OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
+
+	* ethtool.c: This fixes the bogus tail backslash that I did.
+
+Fri Apr  9 2004  Jim Lewis <jim@jklewis.com>
+
+	* ethtool.c:  Return results of self-test back to OS,
+	via exit(2).
+
+Fri Apr  9 2004  Jeb Cramer  <cramerj@intel.com>
+
+	* e1000.c: Update device id list and add printout of phy type in
+	register dump.  Set default mac_type to 82543 since register offsets
+	haven't changed.
+
+Fri Apr  9 2004  Jeff Garzik  <jgarzik@pobox.com>
+
+	* configure.ac, Makefile.am, ethtool.c, etc.:
+	convert to more recent autoconf.
+
+Sat Aug 30 2003  OGAWA Hirofumi  <hirofumi@mail.parknet.co.jp>
+
+	* ethtool.8, ethtool.c: ethtool register dump raw mode
+
+Sat Jul 19 2003  Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.8, ethtool.c, ethtool-copy.h:
+	Add support for TSO get/set.  Corresponds to NETIF_F_TSO.
+	Extended -k|K option to included tso, and changed meaning from
+	just "checksum/sg" to more general "offload".  Now covers Rx/Tx
+	csum, SG, and TSO.
+
+Thu May 28 2003  Ganesh Venkatesan  <ganesh.venkatesan@intel.com>
+
+	* ethtool-copy.h: new definitions for 10GbE
+
+Thu May 28 2003  Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.c: Add ethtool -E to write EEPROM byte.
+	* e100.c: Added MDI/MDI-X status to register dump.
+
+Thu May 28 2003   Reeja John  <reeja.john@amd.com>
+
+	* amd8111e.c: new file, support for AMD-8111e NICs
+	* ethtool.c: properly set ecmd.advertising
+
+Sat Mar 29 2003   OGAWA Hirofumi  <hirofumi@mail.parknet.co.jp>
+
+	* realtek.c: clean up chip enumeration, support additional chips
+
+Fri Mar 28 2003   Jeb Cramer  <cramerj@intel.com>
+
+	* e1000.c: Update supported devices (82541 & 82547).  Add bus type,
+	speed and width to register dump printout.
+	* ethtool.c (show_usage): Add -S to printout of supported commands.
+
+Tue Jan 22 2003   Jeff Garzik  <jgarzik@pobox.com>
+
+	* natsemi.c (PRINT_INTR, __print_intr): Decompose PRINT_INTR
+	macro into macro abuse and function call portions.  Move the
+	actual function body to new static functoin __print_intr.
+
+	This eliminates the annoying build warning :)
+
+Thu Jan 16 2003   Jeb Cramer  <jeb.j.cramer@intel.com>
+
+	* ethtool.c (do_regs, dump_eeprom): Fix memory leaks on failed
+	operations.  Add error handling of dump_regs().  Modify printout of
+	eeprom dump to accomodate larger eeproms.
+	* e1000.c: Update supported devices.  Add error conditions for
+	unsupported devices.
+
+Mon Oct 21 2002   Ben Collins  <bcollins@debian.org>
+
+	* ethtool.c: Add new parameters to -e, for raw EEPROM output, and
+	offset and length options.
+	* natsemi.c (natsemi_dump_eeprom): Show correct offset using new
+	offset feature above.
+	* tg3.c: New file, implements tg3_dump_eeprom.
+	* Makefile.am: Add it to the build sources.
+	* ethtool-util.h: Prototype tg3_dump_eeprom.
+	* ethtool.8: Document new -e options.
+
+Thu Oct 17 2002   Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: make calls to strtol() use base 0
+
+Wed Sep 18 2002   Scott Feldman  <scott.feldman@intel.com>
+
+	* ethtool.c (dump_regs): call e100_dump_regs if e100
+	* e100.c: new file
+	* ethtool-util.h: prototype e100_dump_regs
+
+Thu Jun 20 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.8: document new -S stats dump argument
+	* configure.in, NEWS: release version 1.6
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c (realtek_dump_regs): dump legacy 8139 registers
+	* ethtool.c (do_gstats, doit, parse_cmdline):
+	support dumping of NIC-specific statistics
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c (realtek_dump_regs): dump RTL8139C+ registers
+
+Fri Jun 14 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* realtek.c: new file, dumps RealTek RTL8169 PCI NIC's registers
+	* Makefile.am, ethtool.c, ethtool-util.h: use it
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* NEWS: list new commands added recently
+	* ethtool.c (do_gcoalesce, do_scoalesce, dump_coalesce): new
+	(parse_cmdline, doit): handle get/set coalesce parameters (-c,-C)
+	(do_[gs]*): convert to use table-driven cmd line parsing
+	* ethtool.8: document -c and -C
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c (do_gring, do_sring, dump_ring,
+	parse_ring_cmdline): new functions
+	(parse_cmdline, doit): handle get/set ring parameters (-g,-G)
+	(do_spause): fix off-by-one bugs
+	* ethtool.8: document -g and -G
+
+Tue Jun 11 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c (do_gpause, do_spause, dump_pause,
+	parse_pause_cmdline): new functions
+	(parse_cmdline, doit): handle get/set pause parameters (-a,-A)
+	* ethtool.8: document -a, -A, -e, and -p
+
+Wed May 22 2002  Chris Leech <christopher.leech@intel.com>
+            Scott Feldman <scott.feldman@intel.com>
+
+	* ethtool-copy.h: add support for ETHTOOL_PHYS_ID function.
+	* ethtool.c: add support for ETHTOOL_PHYS_ID function, add
+	  support for e1000 reg dump.
+	* Makefile.am: add e1000.c
+	* e1000.c: reg dump support for Intel(R) PRO/1000 adapters.
+	* ethtool-util.h: add e1000 reg dump support.
+
+Sat May 11 2002  Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.c (do_test): add support for online/offline test modes
+	Elsewhere: document "-t" arg usage, and handle usage
+
+Sat May 11 2002  Jes Sorensen  <jes@wildopensource.com>
+
+	* ethtool.c (dump_ecmd): If unknown value is
+	encountered in speed, duplex, or port ETHTOOL_GSET
+	return data, print the numeric value returned.
+
+Wed May 1 2002  Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.8: document new -t test option
+
+Wed May 1 2002  Christoph Hellwig  <hch@lst.de>
+
+	* Makefile.am (dist-hook): Use $(top-srcdir) for refering to sources.
+
+Mon Apr 29 2002  Christoph Hellwig  <hch@lst.de>
+
+	* Makefile.am (SUBDIRS): Remove.
+	(RPMSRCS): Likewise.
+	(TMPDIR): Likewise.
+	(rpm): Likewise.
+	(EXTRA_DIST): Add ethtool.spec.in.
+	(dist-hook): New rule.  Create rpm specfile.
+	* configure.in (AC_OUTPUT): Add ethtool.spec.
+	* ethtool.spec.in: New file.  Rpm specfile template.
+	* redhat/ethtool.spec.in: Removed.
+	* redhat/Makefile.am: Removed.
+
+Wed Mar 20 2002   Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool-copy.h: Merge coalescing param, ring
+	param, and pause param ioctl structs from kernel 2.5.7.
+	Merge ethtool_test changes fromkernel 2.5.7.
+	* ethtool: Update for ethtool_test cleanups.
+
+Wed Mar 20 2002   Eli Kupermann  <eli.kupermann@intel.com>
+
+	* ethtool.c: (do_test): new function
+	Elsewhere: add support for 'perform test' function,
+	via a new "-t" arg, by calling do_test.
+
+Sun Mar  3 2002   Brad Hards  <bhards@bigpond.net.au>
+
+	* ethtool.c (parse_cmdline): Support "usb"
+	as well as "eth" network interfaces.  USB networking
+	uses a different prefix.
+
+Fri Feb  8 2002  "Noam, Amir" <amir.noam@intel.com>,
+		 "Kupermann, Eli" <eli.kupermann@intel.com>
+
+	* ethtool.c (dump_advertised): new function.
+	(dump_ecmd): Call it.
+	Elsewhere: reformat code.
+
+Wed Nov 28 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* configure.in, Makefile.am, redhat/Makefile.am:
+	make sure redhat spec is included in dist tarball.
+
+Tue Nov 27 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: strings changes
+	* ethtool.c: print messagelevel as hex (netif_msg_* shows better :)
+
+Sun Nov 18 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* NEWS: update with recent changes
+	* ethtool.8: phy address can be used if implemented in the
+	  driver, so remove "Not used yet" remark.
+
+Sun Nov 18 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Makefile.am, de2104x.c, ethtool-util.h, ethtool.c:
+	  Support register dumps for de2104x driver.
+
+Tue Nov 13 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c, ethtool.c: use u8 data for ethtool_regs
+	* ethtool-copy.h: latest from kernel
+	* natsemi.c, ethtool.c: support ETHTOOL_GEEPROM via -e param
+
+Mon Nov 12 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: check version, conditionally print RFCR-indexed data
+
+Wed Nov 07 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: print less errors for unsupported ioctl()s
+	* ethtool.c: warn if all ioctl()s are unsupported or failed
+	* ethtool.c: change autoneg-restart mechanism to -r (as per jgarzik)
+	* ethtool.c: check for "eth" in devicename (per jg)
+	* ethtool.c: remove 'extraneous' braces
+
+Wed Nov 07 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c, ethtool.8: support bnc port/media
+
+Tue Nov 06 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: clean up output for unhandled register dumps
+	* natsemi.c: finish pretty-printing register dumps
+	* ethtool.8: document -d option
+	* various: add copyright info, where applicable
+	* ethtool.c: be nicer about unsupported ioctl()s where possible
+	  and be more verbose where nice is not an option.
+
+Mon Nov 05 2001  Tim Hockin  <thockin@sun.com>
+
+	* natsemi.c: first cut at 'pretty-printing' register dumps
+
+Fri Nov 02 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: add support for ETHTOOL_GREGS via -d (dump) flag
+	* ethtool.c: add support for device-specific dumps for known devices
+	* ethtool.c: make mode-specific handling allocate ifr_data
+	* Makefile.am: import ChangeLog to rpm specfile
+	* natsemi.c: added
+	* ethtool-util.h: added
+
+Thu Nov 01 2001  Tim Hockin  <thockin@sun.com>
+
+	* ethtool.c: add support for ETHTOOL_GLINK in output
+	* ethtool.c: add support for ETHTOOL_NWAY_RST via 'autoneg restart'
+	* ethtool.c: add support for ETHTOOL_[GS]MSGLVL via 'msglvl' param
+	* ethtool.8: add documentation for above
+	* ethtool-copy.h: updated to sync with kernel
+
+Fri Oct 26 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.8: Update contributors list, home page URL.
+	* ethtool.8: Much cleanup, no content change.
+	Contributed by Andre Majorel.
+	* ethtool.c: Clean up '-h' usage message.
+	Contributed by Andre Majorel.
+
+Fri Oct 26 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Configure.in: bump version to 1.4cvs
+	* Makefile.am: include ethtool-copy.h in list of sources
+	* ethtool-copy.h:
+	Import ethtool.h from kernel 2.4.13.
+	* ethtool.c:
+	Define SIOCETHTOOL if it is missing,
+	trim trailing whitespace.
+	* NEWS: update for these changes
+
+Wed Sep 19 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* ethtool.c, ethtool-copy.h:
+	Import copy of kernel 2.4.10-pre12's ethtool.h.
+
+Wed Sep 19 2001  Tim Hockin  <thockin@sun.com>
+
+	* Makefile.am, redhat/ethtool.spec.in:
+	Basic "make rpm" support.
+
+Wed Sep 19 2001  Tim Hockin  <thockin@sun.com>
+
+	* AUTHORS, NEWS, ethtool.8, ethtool.c:
+	Wake-on-LAN support.
+
+Thu May 17 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* configure.in, NEWS, README: Version 1.2 release
+
+	* ethtool.c: Support ETHTOOL_GDRVINFO.
+	* ethtool.8: Document it.
+
+Fri Mar 20 2001  Jeff Garzik  <jgarzik@mandrakesoft.com>
+
+	* Makefile.am, configure.in, autogen.sh, NEWS,
+	  ChangeLog, AUTHORS, README:
+	  Add autoconf/automake support.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..e6b83cd
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,13 @@
+AM_CFLAGS = -Wall
+
+man_MANS = ethtool.8
+EXTRA_DIST = ethtool.8 ethtool.spec.in aclocal.m4 ChangeLog autogen.sh
+
+sbin_PROGRAMS = ethtool
+ethtool_SOURCES = de2104x.c ethtool.c ethtool-copy.h ethtool-util.h natsemi.c \
+                  e1000.c realtek.c e100.c tg3.c amd8111e.c pcnet32.c \
+		  fec_8xx.c
+
+dist-hook:
+	cp $(top_srcdir)/ethtool.spec $(distdir)
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..3e0086f
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,78 @@
+
+Version 3 - January 27, 2005
+
+	* Feature: r8159 register dump support
+	* Feature / bug fix: Support advertising gigabit ethernet
+	* Bug fix: make sure to advertise 10baseT-HD
+	* Other minor bug fixes.
+
+Version 2 - August 17, 2004
+
+	* Feature: ethtool register dump raw mode
+	* Feature: return results of self-test back to OS via exit(2)
+	* Feature: add verbose register dump for pcnet32, fec_8xx
+	* Maintenance: update to more recent autoconf
+	* Maintenance: minor updates to e1000-specific module
+	* Bug fix: Remove silly restriction on ethernet interface naming
+
+Version 1.8 - July 19, 2003
+
+	* Feature: Support amd8111e register dumps
+	* Feature: Support TSO enable/disable
+	* Feature: Support 10 gigabit ethernet
+	* Feature: Support writing EEPROM data
+	* Feature: Output e100 MDI/MDI-x status in register dump
+	* Feature: Clean up RealTek (RTL) chip output, support new chips.
+	* Feature: More supported e1000 devices.
+	* Bug fix: Properly set ecmd.advertising
+	* Bug fix: Fix leaks, handle some error conditions better.
+
+Version 1.7 - October 21, 2002
+
+	* Feature: Support e100 register dumps
+	* Feature: Support tg3 eeprom dumps
+	* Feature: Support partial eeprom dumps (with non-zero offsets)
+	* Feature: Support decimal/octal/hex numbers transparently,
+	  at the user's discretion.
+
+Version 1.6 - June 20, 2002
+
+	* Feature: Support e1000 register dumps
+	* Feature: Support RealTek RTL-8139C+ and RTL-8169 register dumps
+	* Feature: Support coalescing config (ETHTOOL_[GS]COALESCE)
+	* Feature: Support ring param config (ETHTOOL_[GS]RINGPARAM)
+	* Feature: Support pause param config (ETHTOOL_[GS]PAUSEPARAM)
+	* Feature: Support physical NIC identification (ETHTOOL_PHYS_ID)
+	* Feature: Support NIC self-testing (ETHTOOL_TEST)
+	* Feature: Support NIC checksum/scatter-gather configuration
+		(ETHTOOL_[GS]RXCSUM, ETHTOOL_[GS]TXCSUM, ETHTOOL_[GS]SG)
+
+Version 1.5 - Mar 4, 2002
+
+	* Fix: support usb network interfaces
+	* Fix: include redhat spec file in autoconf build system
+	* Fix: minor fixes to natsemi register dump
+	* Feature: report advertised as well as supported media,
+	  when printing device settings.
+
+Version 1.4 - Nov 19, 2001
+
+	* Support builds on configurations missing SIOCETHTOOL constant.
+	* Import ethtool.h from kernel 2.4.15-pre6.
+	* Support retrieval/setting of per-driver debug levels
+	  (ETHTOOL G/SMSGLVL)
+	* Support pretty-printing register dumps on natsemi, de2104x
+	  (ETHTOOL GREGS)
+	* Support restarting autonegotiation (ETHTOOL NWAY_RST)
+	* Support obtaining link status (ETHTOOL GLINK)
+
+Version 1.3 - Aug 02, 2001
+
+	* Support Wake-on-LAN (ETHTOOL GWOL and ETHTOOL SWOL ioctl).
+
+Version 1.2 - May 17, 2001
+
+	* Support ETHTOOL_GDRVINFO ioctl, which obtains
+	  information from the ethernet driver associated
+	  with the specified interface.
+
diff --git a/README b/README
new file mode 100644
index 0000000..9e03205
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+ethtool is a small utility for examining and tuning your ethernet-based
+network interface.  See the man page for more details.
diff --git a/amd8111e.c b/amd8111e.c
new file mode 100644
index 0000000..b4cd65d
--- /dev/null
+++ b/amd8111e.c
@@ -0,0 +1,305 @@
+
+/* Copyright (C) 2003  Advanced Micro Devices Inc. */
+#include <stdio.h>
+#include "ethtool-util.h"
+
+typedef enum {
+	/* VAL2 */
+	RDMD0			= (1 << 16),
+	/* VAL1 */
+	TDMD3			= (1 << 11),
+	TDMD2			= (1 << 10),
+	TDMD1			= (1 << 9),
+	TDMD0			= (1 << 8),
+	/* VAL0 */
+	UINTCMD			= (1 << 6),
+	RX_FAST_SPND		= (1 << 5),
+	TX_FAST_SPND		= (1 << 4),
+	RX_SPND			= (1 << 3),
+	TX_SPND			= (1 << 2),
+	INTREN			= (1 << 1),
+	RUN			= (1 << 0),
+
+	CMD0_CLEAR 		= 0x000F0F7F,   /* Command style register */
+
+}CMD0_BITS;
+typedef enum {
+
+	/* VAL3 */
+	CONDUIT_MODE		= (1 << 29),
+	/* VAL2 */
+	RPA			= (1 << 19),
+	DRCVPA			= (1 << 18),
+	DRCVBC			= (1 << 17),
+	PROM			= (1 << 16),
+	/* VAL1 */
+	ASTRP_RCV		= (1 << 13),
+	RCV_DROP0	  	= (1 << 12),
+	EMBA			= (1 << 11),
+	DXMT2PD			= (1 << 10),
+	LTINTEN			= (1 << 9),
+	DXMTFCS			= (1 << 8),
+	/* VAL0 */
+	APAD_XMT		= (1 << 6),
+	DRTY			= (1 << 5),
+	INLOOP			= (1 << 4),
+	EXLOOP			= (1 << 3),
+	REX_RTRY		= (1 << 2),
+	REX_UFLO		= (1 << 1),
+	REX_LCOL		= (1 << 0),
+
+	CMD2_CLEAR 		= 0x3F7F3F7F,   /* Command style register */
+
+}CMD2_BITS;
+typedef enum {
+
+	/* VAL3 */
+	ASF_INIT_DONE_ALIAS	= (1 << 29),
+	/* VAL2 */
+	JUMBO			= (1 << 21),
+	VSIZE			= (1 << 20),
+	VLONLY			= (1 << 19),
+	VL_TAG_DEL		= (1 << 18),
+	/* VAL1 */
+	EN_PMGR			= (1 << 14),
+	INTLEVEL		= (1 << 13),
+	FORCE_FULL_DUPLEX	= (1 << 12),
+	FORCE_LINK_STATUS	= (1 << 11),
+	APEP			= (1 << 10),
+	MPPLBA			= (1 << 9),
+	/* VAL0 */
+	RESET_PHY_PULSE		= (1 << 2),
+	RESET_PHY		= (1 << 1),
+	PHY_RST_POL		= (1 << 0),
+
+}CMD3_BITS;
+typedef enum {
+
+	INTR			= (1 << 31),
+	PCSINT			= (1 << 28),
+	LCINT			= (1 << 27),
+	APINT5			= (1 << 26),
+	APINT4			= (1 << 25),
+	APINT3			= (1 << 24),
+	TINT_SUM		= (1 << 23),
+	APINT2			= (1 << 22),
+	APINT1			= (1 << 21),
+	APINT0			= (1 << 20),
+	MIIPDTINT		= (1 << 19),
+	MCCINT			= (1 << 17),
+	MREINT			= (1 << 16),
+	RINT_SUM		= (1 << 15),
+	SPNDINT			= (1 << 14),
+	MPINT			= (1 << 13),
+	SINT			= (1 << 12),
+	TINT3			= (1 << 11),
+	TINT2			= (1 << 10),
+	TINT1			= (1 << 9),
+	TINT0			= (1 << 8),
+	UINT			= (1 << 7),
+	STINT			= (1 << 4),
+	RINT0			= (1 << 0),
+
+}INT0_BITS;
+typedef enum {
+
+	/* VAL3 */
+	LCINTEN			= (1 << 27),
+	APINT5EN		= (1 << 26),
+	APINT4EN		= (1 << 25),
+	APINT3EN		= (1 << 24),
+	/* VAL2 */
+	APINT2EN		= (1 << 22),
+	APINT1EN		= (1 << 21),
+	APINT0EN		= (1 << 20),
+	MIIPDTINTEN		= (1 << 19),
+	MCCIINTEN		= (1 << 18),
+	MCCINTEN		= (1 << 17),
+	MREINTEN		= (1 << 16),
+	/* VAL1 */
+	SPNDINTEN		= (1 << 14),
+	MPINTEN			= (1 << 13),
+	TINTEN3			= (1 << 11),
+	SINTEN			= (1 << 12),
+	TINTEN2			= (1 << 10),
+	TINTEN1			= (1 << 9),
+	TINTEN0			= (1 << 8),
+	/* VAL0 */
+	STINTEN			= (1 << 4),
+	RINTEN0			= (1 << 0),
+
+	INTEN0_CLEAR 		= 0x1F7F7F1F, /* Command style register */
+
+}INTEN0_BITS;
+
+typedef enum {
+
+	PMAT_DET		= (1 << 12),
+	MP_DET		        = (1 << 11),
+	LC_DET			= (1 << 10),
+	SPEED_MASK		= (1 << 9)|(1 << 8)|(1 << 7),
+	FULL_DPLX		= (1 << 6),
+	LINK_STATS		= (1 << 5),
+	AUTONEG_COMPLETE	= (1 << 4),
+	MIIPD			= (1 << 3),
+	RX_SUSPENDED		= (1 << 2),
+	TX_SUSPENDED		= (1 << 1),
+	RUNNING			= (1 << 0),
+
+}STAT0_BITS;
+
+#define PHY_SPEED_10		0x2
+#define PHY_SPEED_100		0x3
+
+
+int amd8111e_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+
+	u32 *reg_buff = (u32 *)regs->data;
+	u32 reg;
+
+	fprintf(stdout, "Descriptor Registers\n");
+	fprintf(stdout, "---------------------\n");
+
+	/* Transmit descriptor base address register */
+	reg = reg_buff[0];
+	fprintf(stdout,
+		"0x00100: Transmit descriptor base address register %08X\n",reg);
+
+	/* Transmit descriptor length register */
+	reg = reg_buff[1];
+	fprintf(stdout,
+		"0x00140: Transmit descriptor length register 0x%08X\n",reg);
+
+	/* Receive descriptor base address register */
+	reg = reg_buff[2];
+	fprintf(stdout,
+		"0x00120: Receive descriptor base address register %08X\n",reg);
+
+	/* Receive descriptor length register */
+	reg = reg_buff[3];
+	fprintf(stdout,
+		"0x00150: Receive descriptor length register 0x%08X\n",reg);
+
+	fprintf(stdout, "\n");
+
+
+	fprintf(stdout, "Command Registers\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Command 0 Register */
+	reg = reg_buff[4];
+	fprintf(stdout,
+		"0x00048: Command 0 register  0x%08X\n"
+		"	Interrupts:				%s\n"
+		"	Device:					%s\n",
+		reg,
+		reg & INTREN   		? "Enabled"     : "Disabled",
+		reg & RUN    		? "Running"     : "Stopped");
+
+	/* Command 2 Register */
+	reg = reg_buff[5];
+	fprintf(stdout,
+		"0x00050: Command 2 register  0x%08X\n"
+		"	Promiscuous mode:			%s\n"
+		"	Retransmit on underflow:		%s\n",
+		reg,
+		reg & PROM   		? "Enabled"     : "Disabled",
+		reg & REX_UFLO   	? "Enabled"     : "Disabled");
+	/* Command 3 Register */
+	reg = reg_buff[6];
+	fprintf(stdout,
+		"0x00054: Command 3 register  0x%08X\n"
+		"	Jumbo frame:				%s\n"
+		"	Admit only VLAN frame:	 		%s\n"
+		"	Delete VLAN tag:			%s\n",
+		reg,
+		reg & JUMBO  		? "Enabled"     : "Disabled",
+		reg &  VLONLY 		? "Yes"     : "No",
+		reg &  VL_TAG_DEL 		? "Yes"     : "No");
+
+	/* Command 7 Register */
+	reg = reg_buff[7];
+	fprintf(stdout,
+		"0x00064: Command 7 register  0x%08X\n",
+		 reg);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Interrupt Registers\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Interrupt 0 Register */
+	reg = reg_buff[8];
+	fprintf(stdout,
+		"0x00038: Interrupt register  0x%08X\n"
+		"	Any interrupt is set: 			%s\n"
+		"	Link change interrupt:	  		%s\n"
+		"	Register 0 auto-poll interrupt:		%s\n"
+		"	Transmit interrupt:			%s\n"
+		"	Software timer interrupt:		%s\n"
+		"	Receive interrupt:			%s\n",
+		 reg,
+		 reg &   INTR		? "Yes"     : "No",
+		 reg &   LCINT		? "Yes"     : "No",
+		 reg &   APINT0		? "Yes"     : "No",
+		 reg &   TINT0		? "Yes"     : "No",
+		 reg &   STINT		? "Yes"     : "No",
+		 reg &   RINT0		? "Yes"     : "No"
+		 );
+	/* Interrupt 0 enable Register */
+	reg = reg_buff[9];
+	fprintf(stdout,
+		"0x00040: Interrupt enable register  0x%08X\n"
+		"	Link change interrupt:	  		%s\n"
+		"	Register 0 auto-poll interrupt:		%s\n"
+		"	Transmit interrupt:			%s\n"
+		"	Software timer interrupt:		%s\n"
+		"	Receive interrupt:			%s\n",
+		 reg,
+		 reg &   LCINTEN		? "Enabled"     : "Disabled",
+		 reg &   APINT0EN		? "Enabled"     : "Disabled",
+		 reg &   TINTEN0		? "Enabled"     : "Disabled",
+		 reg &   STINTEN		? "Enabled"     : "Disabled",
+		 reg &   RINTEN0		? "Enabled"     : "Disabled"
+		);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Logical Address Filter Register\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Logical Address Filter Register */
+	fprintf(stdout,
+		"0x00168: Logical address filter register  0x%08X%08X\n",
+		 reg_buff[11],reg_buff[10]);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Link status Register\n");
+	fprintf(stdout, "-------------------\n");
+
+	/* Status 0  Register */
+	reg = reg_buff[12];
+	if(reg & LINK_STATS){
+	fprintf(stdout,
+		"0x00030: Link status register  0x%08X\n"
+		"	Link status:	  		%s\n"
+		"	Auto negotiation complete	%s\n"
+		"	Duplex				%s\n"
+		"	Speed				%s\n",
+		reg,
+		reg &  LINK_STATS 		? "Valid"     : "Invalid",
+		reg &  AUTONEG_COMPLETE		? "Yes"	      : "No",
+		reg &  FULL_DPLX 		? "Full"      : "Half",
+		((reg & SPEED_MASK) >> 7 == PHY_SPEED_10) ? "10Mbits/ Sec":
+							"100Mbits/Sec");
+
+	}
+	else{
+	fprintf(stdout,
+		"0x00030: Link status register  0x%08X\n"
+		"	Link status:	  		%s\n",
+		reg,
+		reg &  LINK_STATS 		? "Valid"     : "Invalid");
+	}
+	return 0;
+
+}
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..9f98ef8
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# You need autoconf 2.5x, preferably 2.57 or later
+# You need automake 1.7 or later. 1.6 might work.
+
+set -e
+
+aclocal
+autoheader
+automake --gnu --add-missing --copy
+autoconf
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..40fd39c
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,26 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(ethtool, 3, [Jeff Garzik <jgarzik@pobox.com>])
+AC_PREREQ(2.52)
+AC_CONFIG_SRCDIR([ethtool.c])
+AM_INIT_AUTOMAKE([gnu])
+AC_CONFIG_HEADERS([ethtool-config.h])
+
+AM_MAINTAINER_MODE
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_GCC_TRADITIONAL
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_CHECK_HEADERS(sys/ioctl.h)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+
+dnl Checks for library functions.
+AC_HEADER_STDC
+AC_CHECK_FUNCS(socket strtol)
+
+AC_CONFIG_FILES([Makefile ethtool.spec])
+AC_OUTPUT
diff --git a/de2104x.c b/de2104x.c
new file mode 100644
index 0000000..f64e1b2
--- /dev/null
+++ b/de2104x.c
@@ -0,0 +1,783 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include "ethtool-util.h"
+
+static const char * const csr0_tap[4] = {
+	"No transmit automatic polling",
+	"Transmit automatic polling every 200 seconds",
+	"Transmit automatic polling every 800 seconds",
+	"Transmit automatic polling every 1.6 milliseconds",
+};
+
+static const char * const csr0_cache_al[4] = {
+	"not used",
+	"8-longword boundary alignment",
+	"16-longword boundary alignment",
+	"32-longword boundary alignment",
+};
+
+static const char * const csr5_buserr[8] = {
+	"      Bus error: parity",
+	"      Bus error: master abort",
+	"      Bus error: target abort",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+	"      Bus error: (unknown code, reserved)",
+};
+
+static const int csr6_tx_thresh[4] = {
+	72,
+	96,
+	128,
+	160,
+};
+
+static const char * const csr6_om[4] = {
+	"normal",
+	"internal loopback",
+	"external loopback",
+	"unknown (not used)",
+};
+
+static const char * const csr5_tx_state[8] = {
+	"stopped",
+	"running: fetch desc",
+	"running: wait xmit end",
+	"running: read buf",
+	"unknown (reserved)",
+	"running: setup packet",
+	"suspended",
+	"running: close desc",
+};
+
+static const char * const csr5_rx_state[8] = {
+	"stopped",
+	"running: fetch desc",
+	"running: chk pkt end",
+	"running: wait for pkt",
+	"suspended",
+	"running: close",
+	"running: flush",
+	"running: queue",
+};
+
+static const char * const csr12_nway_state[8] = {
+	"Autonegotiation disable",
+	"Transmit disable",
+	"Ability detect",
+	"Acknowledge detect",
+	"Complete acknowledge",
+	"FLP link good, nway complete",
+	"Link check",
+	"unknown (reserved)",
+};
+
+static const char * const csr14_tp_comp[4] = {
+	"Compensation Disabled Mode",
+	"Compensation Disabled Mode",
+	"High Power Mode",
+	"Normal Compensation Mode",
+};
+
+static void
+print_ring_addresses(u32 csr3, u32 csr4)
+{
+	fprintf(stdout,
+		"0x18: CSR3 (Rx Ring Base Address)        0x%08x\n"
+		"0x20: CSR4 (Tx Ring Base Address)        0x%08x\n"
+		,
+		csr3,
+		csr4);
+}
+
+static void
+print_rx_missed(u32 csr8)
+{
+	fprintf(stdout,
+		"0x40: CSR8 (Missed Frames Counter)       0x%08x\n", csr8);
+	if (csr8 & (1 << 16))
+		fprintf(stdout,
+		"      Counter overflow\n");
+	else {
+		unsigned int rx_missed = csr8 & 0xffff;
+		if (!rx_missed)
+			fprintf(stdout,
+			"      No missed frames\n");
+		else
+			fprintf(stdout,
+			"      %u missed frames\n", rx_missed);
+	}
+}
+
+static void
+de21040_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 tmp, v, *data = (u32 *)regs->data;
+
+	fprintf(stdout, "21040 Registers\n");
+	fprintf(stdout, "---------------\n");
+
+	/*
+	 * CSR0
+	 */
+	v = data[0];
+	fprintf(stdout,
+		"0x00: CSR0 (Bus Mode)                    0x%08x\n"
+		"      %s\n"
+		"      %s address space\n"
+		"      Cache alignment: %s\n"
+		,
+		v,
+		csr0_tap[(v >> 17) & 3],
+		v & (1 << 16) ? "Diagnostic" : "Standard",
+		csr0_cache_al[(v >> 14) & 3]);
+	tmp = (v >> 8) & 0x3f;
+	if (tmp == 0)
+		fprintf(stdout, "      Programmable burst length unlimited\n");
+	else
+		fprintf(stdout,
+			"      Programmable burst length %d longwords\n",
+			tmp);
+	fprintf(stdout,
+		"      %s endian data buffers\n"
+		"      Descriptor skip length %d longwords\n"
+		"      %s bus arbitration scheme\n"
+		,
+		v & (1 << 7) ? "Big" : "Little",
+		(v >> 2) & 0x1f,
+		v & (1 << 1) ? "Round-robin" : "RX-has-priority");
+	if (v & (1 << 0))
+		fprintf(stdout, "      Software reset asserted\n");
+
+	/*
+	 * CSR3, 4
+	 */
+	print_ring_addresses(data[3], data[4]);
+
+	/*
+	 * CSR5
+	 */
+	v = data[5];
+	fprintf(stdout,
+		"0x28: CSR5 (Status)                      0x%08x\n"
+		"%s"
+		"      Transmit process %s\n"
+		"      Receive process %s\n"
+		"      Link %s\n"
+		,
+		v,
+		v & (1 << 13) ? csr5_buserr[(v >> 23) & 0x7] : "",
+		csr5_tx_state[(v >> 20) & 0x7],
+		csr5_rx_state[(v >> 17) & 0x7],
+		v & (1 << 12) ? "fail" : "OK");
+	if (v & (1 << 16))
+		fprintf(stdout,
+		"      Normal interrupts: %s%s%s\n"
+		,
+		v & (1 << 0) ? "TxOK " : "",
+		v & (1 << 2) ? "TxNoBufs " : "",
+		v & (1 << 6) ? "RxOK" : "");
+	if (v & (1 << 15))
+		fprintf(stdout,
+		"      Abnormal intr: %s%s%s%s%s%s%s%s\n"
+		,
+		v & (1 << 1) ? "TxStop " : "",
+		v & (1 << 3) ? "TxJabber " : "",
+		v & (1 << 5) ? "TxUnder " : "",
+		v & (1 << 7) ? "RxNoBufs " : "",
+		v & (1 << 8) ? "RxStopped " : "",
+		v & (1 << 9) ? "RxTimeout " : "",
+		v & (1 << 10) ? "AUI_TP " : "",
+		v & (1 << 11) ? "FD_Short " : "");
+
+	/*
+	 * CSR6
+	 */
+	v = data[6];
+	fprintf(stdout,
+		"0x30: CSR6 (Operating Mode)              0x%08x\n"
+		"%s"
+		"%s"
+		"      Transmit threshold %d bytes\n"
+		"      Transmit DMA %sabled\n"
+		"%s"
+		"      Operating mode: %s\n"
+		"      %s duplex\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      Receive DMA %sabled\n"
+		"      %s filtering mode\n"
+		,
+		v,
+		v & (1<<17) ? "      Capture effect enabled\n" : "",
+		v & (1<<16) ? "      Back pressure enabled\n" : "",
+		csr6_tx_thresh[(v >> 14) & 3],
+		v & (1<<13) ? "en" : "dis",
+		v & (1<<12) ? "      Forcing collisions\n" : "",
+		csr6_om[(v >> 10) & 3],
+		v & (1<<9) ? "Full" : "Half",
+		v & (1<<8) ? "      Flaky oscillator disable\n" : "",
+		v & (1<<7) ? "      Pass All Multicast\n" : "",
+		v & (1<<6) ? "      Promisc Mode\n" : "",
+		v & (1<<5) ? "      Start/Stop Backoff Counter\n" : "",
+		v & (1<<4) ? "      Inverse Filtering\n" : "",
+		v & (1<<3) ? "      Pass Bad Frames\n" : "",
+		v & (1<<2) ? "      Hash-only Filtering\n" : "",
+		v & (1<<1) ? "en" : "dis",
+		v & (1<<0) ? "Hash" : "Perfect");
+
+	/*
+	 * CSR7
+	 */
+	v = data[7];
+	fprintf(stdout,
+		"0x38: CSR7 (Interrupt Mask)              0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<16) ? "      Normal interrupt summary\n" : "",
+		v & (1<<15) ? "      Abnormal interrupt summary\n" : "",
+		v & (1<<13) ? "      System error\n" : "",
+		v & (1<<12) ? "      Link fail\n" : "",
+		v & (1<<11) ? "      Full duplex\n" : "",
+		v & (1<<10) ? "      AUI_TP pin\n" : "",
+		v & (1<<9) ? "      Receive watchdog timeout\n" : "",
+		v & (1<<8) ? "      Receive stopped\n" : "",
+		v & (1<<7) ? "      Receive buffer unavailable\n" : "",
+		v & (1<<6) ? "      Receive interrupt\n" : "",
+		v & (1<<5) ? "      Transmit underflow\n" : "",
+		v & (1<<3) ? "      Transmit jabber timeout\n" : "",
+		v & (1<<2) ? "      Transmit buffer unavailable\n" : "",
+		v & (1<<1) ? "      Transmit stopped\n" : "",
+		v & (1<<0) ? "      Transmit interrupt\n" : "");
+
+	/*
+	 * CSR8
+	 */
+	print_rx_missed(data[8]);
+
+	/*
+	 * CSR9
+	 */
+	v = data[9];
+	fprintf(stdout,
+		"0x48: CSR9 (Ethernet Address ROM)        0x%08x\n", v);
+
+	/*
+	 * CSR11
+	 */
+	v = data[11];
+	fprintf(stdout,
+		"0x58: CSR11 (Full Duplex Autoconfig)     0x%08x\n", v);
+
+	/*
+	 * CSR12
+	 */
+	v = data[12];
+	fprintf(stdout,
+		"0x60: CSR12 (SIA Status)                 0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      AUI_TP pin: %s\n"
+		,
+		v,
+		v & (1<<7) ? "      PLL sampler high\n" : "",
+		v & (1<<6) ? "      PLL sampler low\n" : "",
+		v & (1<<5) ? "      PLL self-test pass\n" : "",
+		v & (1<<4) ? "      PLL self-test done\n" : "",
+		v & (1<<3) ? "      Autopolarity state\n" : "",
+		v & (1<<2) ? "      Link fail\n" : "",
+		v & (1<<1) ? "      Network connection error\n" : "",
+		v & (1<<0) ? "AUI" : "TP");
+
+	/*
+	 * CSR13
+	 */
+	v = data[13];
+	fprintf(stdout,
+		"0x68: CSR13 (SIA Connectivity)           0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      External port output multiplexer select: %u%u%u%u\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s interface selected\n"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      Enable pins 5, 6, 7\n" : "",
+		v & (1<<14) ? "      Enable pins 2, 4\n" : "",
+		v & (1<<13) ? "      Enable pins 1, 3\n" : "",
+		v & (1<<12) ? "      Input enable\n" : "",
+		v & (1<<11) ? 1 : 0,
+		v & (1<<10) ? 1 : 0,
+		v & (1<<9) ? 1 : 0,
+		v & (1<<8) ? 1 : 0,
+		v & (1<<7) ? "      APLL start\n" : "",
+		v & (1<<6) ? "      Serial interface input multiplexer\n" : "",
+		v & (1<<5) ? "      Encoder input multiplexer\n" : "",
+		v & (1<<4) ? "      SIA PLL external input enable\n" : "",
+		v & (1<<3) ? "AUI" : "10base-T",
+		v & (1<<2) ? "      CSR autoconfiguration\n" : "",
+		v & (1<<1) ? "      AUI_TP pin autoconfiguration\n" : "",
+		v & (1<<0) ? "      SIA reset\n" : "");
+
+	/*
+	 * CSR14
+	 */
+	v = data[14];
+	fprintf(stdout,
+		"0x70: CSR14 (SIA Transmit and Receive)   0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<14) ? "      Set polarity plus\n" : "",
+		v & (1<<13) ? "      Autopolarity enable\n" : "",
+		v & (1<<12) ? "      Link test enable\n" : "",
+		v & (1<<11) ? "      Heartbeat enable\n" : "",
+		v & (1<<10) ? "      Collision detect enable\n" : "",
+		v & (1<<9) ? "      Collision squelch enable\n" : "",
+		v & (1<<8) ? "      Receive squelch enable\n" : "",
+		csr14_tp_comp[(v >> 4) & 0x3],
+		v & (1<<3) ? "      Link pulse send enable\n" : "",
+		v & (1<<2) ? "      Driver enable\n" : "",
+		v & (1<<1) ? "      Loopback enable\n" : "",
+		v & (1<<0) ? "      Encoder enable\n" : "");
+
+	/*
+	 * CSR15
+	 */
+	v = data[15];
+	fprintf(stdout,
+		"0x78: CSR15 (SIA General)                0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<13) ? "      Force receiver low\n" : "",
+		v & (1<<12) ? "      PLL self-test start\n" : "",
+		v & (1<<11) ? "      Force link fail\n" : "",
+		v & (1<<9) ? "      Force unsquelch\n" : "",
+		v & (1<<8) ? "      Test clock\n" : "",
+		v & (1<<5) ? "      Receive watchdog release\n" : "",
+		v & (1<<4) ? "      Receive watchdog disable\n" : "",
+		v & (1<<2) ? "      Jabber clock\n" : "",
+		v & (1<<1) ? "      Host unjab\n" : "",
+		v & (1<<0) ? "      Jabber disable\n" : "");
+}
+
+static void
+de21041_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 tmp, v, *data = (u32 *)regs->data;
+
+	fprintf(stdout, "21041 Registers\n");
+	fprintf(stdout, "---------------\n");
+
+	/*
+	 * CSR0
+	 */
+	v = data[0];
+	fprintf(stdout,
+		"0x00: CSR0 (Bus Mode)                    0x%08x\n"
+		"      %s endian descriptors\n"
+		"      %s\n"
+		"      %s address space\n"
+		"      Cache alignment: %s\n"
+		,
+		v,
+		v & (1 << 20) ? "Big" : "Little",
+		csr0_tap[(v >> 17) & 3],
+		v & (1 << 16) ? "Diagnostic" : "Standard",
+		csr0_cache_al[(v >> 14) & 3]);
+	tmp = (v >> 8) & 0x3f;
+	if (tmp == 0)
+		fprintf(stdout, "      Programmable burst length unlimited\n");
+	else
+		fprintf(stdout,
+			"      Programmable burst length %d longwords\n",
+			tmp);
+	fprintf(stdout,
+		"      %s endian data buffers\n"
+		"      Descriptor skip length %d longwords\n"
+		"      %s bus arbitration scheme\n"
+		,
+		v & (1 << 7) ? "Big" : "Little",
+		(v >> 2) & 0x1f,
+		v & (1 << 1) ? "Round-robin" : "RX-has-priority");
+	if (v & (1 << 0))
+		fprintf(stdout, "      Software reset asserted\n");
+
+	/*
+	 * CSR3, 4
+	 */
+	print_ring_addresses(data[3], data[4]);
+
+	/*
+	 * CSR5
+	 */
+	v = data[5];
+	fprintf(stdout,
+		"0x28: CSR5 (Status)                      0x%08x\n"
+		"%s"
+		"      Transmit process %s\n"
+		"      Receive process %s\n"
+		"      Link %s\n"
+		,
+		v,
+		v & (1 << 13) ? csr5_buserr[(v >> 23) & 0x7] : "",
+		csr5_tx_state[(v >> 20) & 0x7],
+		csr5_rx_state[(v >> 17) & 0x7],
+		v & (1 << 12) ? "fail" : "OK");
+	if (v & (1 << 16))
+		fprintf(stdout,
+		"      Normal interrupts: %s%s%s%s%s\n"
+		,
+		v & (1 << 0) ? "TxOK " : "",
+		v & (1 << 2) ? "TxNoBufs " : "",
+		v & (1 << 6) ? "RxOK" : "",
+		v & (1 << 11) ? "TimerExp " : "",
+		v & (1 << 14) ? "EarlyRx " : "");
+	if (v & (1 << 15))
+		fprintf(stdout,
+		"      Abnormal intr: %s%s%s%s%s%s%s\n"
+		,
+		v & (1 << 1) ? "TxStop " : "",
+		v & (1 << 3) ? "TxJabber " : "",
+		v & (1 << 4) ? "ANC " : "",
+		v & (1 << 5) ? "TxUnder " : "",
+		v & (1 << 7) ? "RxNoBufs " : "",
+		v & (1 << 8) ? "RxStopped " : "",
+		v & (1 << 9) ? "RxTimeout " : "");
+
+	/*
+	 * CSR6
+	 */
+	v = data[6];
+	fprintf(stdout,
+		"0x30: CSR6 (Operating Mode)              0x%08x\n"
+		"%s"
+		"%s"
+		"      Transmit threshold %d bytes\n"
+		"      Transmit DMA %sabled\n"
+		"%s"
+		"      Operating mode: %s\n"
+		"      %s duplex\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      Receive DMA %sabled\n"
+		"      %s filtering mode\n"
+		,
+		v,
+		v & (1<<31) ? "      Special capture effect enabled\n" : "",
+		v & (1<<17) ? "      Capture effect enabled\n" : "",
+		csr6_tx_thresh[(v >> 14) & 3],
+		v & (1<<13) ? "en" : "dis",
+		v & (1<<12) ? "      Forcing collisions\n" : "",
+		csr6_om[(v >> 10) & 3],
+		v & (1<<9) ? "Full" : "Half",
+		v & (1<<8) ? "      Flaky oscillator disable\n" : "",
+		v & (1<<7) ? "      Pass All Multicast\n" : "",
+		v & (1<<6) ? "      Promisc Mode\n" : "",
+		v & (1<<5) ? "      Start/Stop Backoff Counter\n" : "",
+		v & (1<<4) ? "      Inverse Filtering\n" : "",
+		v & (1<<3) ? "      Pass Bad Frames\n" : "",
+		v & (1<<2) ? "      Hash-only Filtering\n" : "",
+		v & (1<<1) ? "en" : "dis",
+		v & (1<<0) ? "Hash" : "Perfect");
+
+	/*
+	 * CSR7
+	 */
+	v = data[7];
+	fprintf(stdout,
+		"0x38: CSR7 (Interrupt Mask)              0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<16) ? "      Normal interrupt summary\n" : "",
+		v & (1<<15) ? "      Abnormal interrupt summary\n" : "",
+		v & (1<<14) ? "      Early receive interrupt\n" : "",
+		v & (1<<13) ? "      System error\n" : "",
+		v & (1<<12) ? "      Link fail\n" : "",
+		v & (1<<11) ? "      Timer expired\n" : "",
+		v & (1<<9) ? "      Receive watchdog timeout\n" : "",
+		v & (1<<8) ? "      Receive stopped\n" : "",
+		v & (1<<7) ? "      Receive buffer unavailable\n" : "",
+		v & (1<<6) ? "      Receive interrupt\n" : "",
+		v & (1<<5) ? "      Transmit underflow\n" : "",
+		v & (1<<4) ? "      Link pass\n" : "",
+		v & (1<<3) ? "      Transmit jabber timeout\n" : "",
+		v & (1<<2) ? "      Transmit buffer unavailable\n" : "",
+		v & (1<<1) ? "      Transmit stopped\n" : "",
+		v & (1<<0) ? "      Transmit interrupt\n" : "");
+
+	/*
+	 * CSR8
+	 */
+	print_rx_missed(data[8]);
+
+	/*
+	 * CSR9
+	 */
+	v = data[9];
+	fprintf(stdout,
+		"0x48: CSR9 (Boot and Ethernet ROMs)      0x%08x\n"
+		"      Select bits: %s%s%s%s%s%s\n"
+		"      Data: %d%d%d%d%d%d%d%d\n"
+		,
+		v,
+		v & (1<<15) ? "Mode " : "",
+		v & (1<<14) ? "Read " : "",
+		v & (1<<13) ? "Write " : "",
+		v & (1<<12) ? "BootROM " : "",
+		v & (1<<11) ? "SROM " : "",
+		v & (1<<10) ? "ExtReg " : "",
+		v & (1<<7) ? 1 : 0,
+		v & (1<<6) ? 1 : 0,
+		v & (1<<5) ? 1 : 0,
+		v & (1<<4) ? 1 : 0,
+		v & (1<<3) ? 1 : 0,
+		v & (1<<2) ? 1 : 0,
+		v & (1<<1) ? 1 : 0,
+		v & (1<<0) ? 1 : 0);
+
+	/*
+	 * CSR10
+	 */
+	v = data[10];
+	fprintf(stdout,
+		"0x50: CSR10 (Boot ROM Address)           0x%08x\n", v);
+
+	/*
+	 * CSR11
+	 */
+	v = data[11];
+	fprintf(stdout,
+		"0x58: CSR11 (General Purpose Timer)      0x%08x\n"
+		"%s"
+		"      Timer value: %u cycles\n"
+		,
+		v,
+		v & (1<<16) ? "      Continuous mode\n" : "",
+		v & 0xffff);
+
+	/*
+	 * CSR12
+	 */
+	v = data[12];
+	fprintf(stdout,
+		"0x60: CSR12 (SIA Status)                 0x%08x\n"
+		"      Link partner code word 0x%04x\n"
+		"%s"
+		"      NWay state: %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v >> 16,
+		v & (1<<15) ? "      Link partner negotiable\n" : "",
+		csr12_nway_state[(v >> 12) & 0x7],
+		v & (1<<11) ? "      Transmit remote fault\n" : "",
+		v & (1<<10) ? "      Unstable NLP detected\n" : "",
+		v & (1<<9) ? "      Non-selected port receive activity\n" : "",
+		v & (1<<8) ? "      Selected port receive activity\n" : "",
+		v & (1<<7) ? "      PLL sampler high\n" : "",
+		v & (1<<6) ? "      PLL sampler low\n" : "",
+		v & (1<<5) ? "      PLL self-test pass\n" : "",
+		v & (1<<4) ? "      PLL self-test done\n" : "",
+		v & (1<<3) ? "      Autopolarity state\n" : "",
+		v & (1<<2) ? "      Link fail\n" : "",
+		v & (1<<1) ? "      Network connection error\n" : "");
+
+	/*
+	 * CSR13
+	 */
+	v = data[13];
+	fprintf(stdout,
+		"0x68: CSR13 (SIA Connectivity)           0x%08x\n"
+		"      SIA Diagnostic Mode 0x%04x\n"
+		"      %s\n"
+		"%s"
+		"%s"
+		,
+		v,
+		(v >> 4) & 0xfff,
+		v & (1<<3) ? "AUI/BNC port" : "10base-T port",
+		v & (1<<2) ? "      CSR autoconfiguration enabled\n" : "",
+		v & (1<<0) ? "      SIA register reset asserted\n" : "");
+
+	/*
+	 * CSR14
+	 */
+	v = data[14];
+	fprintf(stdout,
+		"0x70: CSR14 (SIA Transmit and Receive)   0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      10base-T/AUI autosensing\n" : "",
+		v & (1<<14) ? "      Set polarity plus\n" : "",
+		v & (1<<13) ? "      Autopolarity enable\n" : "",
+		v & (1<<12) ? "      Link test enable\n" : "",
+		v & (1<<11) ? "      Heartbeat enable\n" : "",
+		v & (1<<10) ? "      Collision detect enable\n" : "",
+		v & (1<<9) ? "      Collision squelch enable\n" : "",
+		v & (1<<8) ? "      Receive squelch enable\n" : "",
+		v & (1<<7) ? "      Autonegotiation enable\n" : "",
+		v & (1<<6) ? "      Must Be One\n" : "",
+		csr14_tp_comp[(v >> 4) & 0x3],
+		v & (1<<3) ? "      Link pulse send enable\n" : "",
+		v & (1<<2) ? "      Driver enable\n" : "",
+		v & (1<<1) ? "      Loopback enable\n" : "",
+		v & (1<<0) ? "      Encoder enable\n" : "");
+
+	/*
+	 * CSR15
+	 */
+	v = data[15];
+	fprintf(stdout,
+		"0x78: CSR15 (SIA General)                0x%08x\n"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"%s"
+		"      %s port selected\n"
+		"%s"
+		"%s"
+		"%s"
+		,
+		v,
+		v & (1<<15) ? "      GP LED2 on\n" : "",
+		v & (1<<14) ? "      GP LED2 enable\n" : "",
+		v & (1<<13) ? "      Force receiver low\n" : "",
+		v & (1<<12) ? "      PLL self-test start\n" : "",
+		v & (1<<11) ? "      LED stretch disable\n" : "",
+		v & (1<<10) ? "      Force link fail\n" : "",
+		v & (1<<9) ? "      Force unsquelch\n" : "",
+		v & (1<<8) ? "      Test clock\n" : "",
+		v & (1<<7) ? "      GP LED1 on\n" : "",
+		v & (1<<6) ? "      GP LED1 enable\n" : "",
+		v & (1<<5) ? "      Receive watchdog release\n" : "",
+		v & (1<<4) ? "      Receive watchdog disable\n" : "",
+		v & (1<<3) ? "AUI" : "BNC",
+		v & (1<<2) ? "      Jabber clock\n" : "",
+		v & (1<<1) ? "      Host unjab\n" : "",
+		v & (1<<0) ? "      Jabber disable\n" : "");
+}
+
+int
+de2104x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	unsigned int de21040 = regs->version & 1;
+
+	if (de21040)
+		de21040_dump_regs(info, regs);
+	else
+		de21041_dump_regs(info, regs);
+
+	return 0;
+}
+
diff --git a/e100.c b/e100.c
new file mode 100644
index 0000000..4d1cef3
--- /dev/null
+++ b/e100.c
@@ -0,0 +1,238 @@
+/* Copyright (c) 2002 Intel Corporation */
+#include <stdio.h>
+#include "ethtool-util.h"
+
+#define D102_REV_ID		12
+
+#define MDI_MDIX_CONFIG_IS_OK	0x0010
+#define MDI_MDIX_STATUS		0x0020
+
+#define SOFT_INT            	0x0200		/* Generate a S/W interrupt */
+
+/* Interrupt masks */
+#define ALL_INT_MASK        	0x0100		/* Mask interrupts */
+#define FCP_INT_MASK        	0x0400		/* Flow Control Pause */
+#define ER_INT_MASK         	0x0800		/* Early Receive */
+#define RNR_INT_MASK        	0x1000		/* RU Not Ready */
+#define CNA_INT_MASK        	0x2000		/* CU Not Active */
+#define FR_INT_MASK         	0x4000		/* Frame Received */
+#define CX_INT_MASK         	0x8000		/* CU eXecution w/ I-bit done */
+
+/* Interrupts pending */
+#define FCP_INT_PENDING         0x0100		/* Flow Control Pause */
+#define ER_INT_PENDING          0x0200		/* Early Receive */
+#define SWI_INT_PENDING         0x0400		/* S/W generated interrupt */
+#define MDI_INT_PENDING         0x0800		/* MDI read or write done */
+#define RNR_INT_PENDING         0x1000		/* RU Became Not Ready */
+#define CNA_INT_PENDING         0x2000		/* CU Became Inactive (IDLE) */
+#define FR_INT_PENDING          0x4000		/* RU Received A Frame */
+#define CX_INT_PENDING          0x8000		/* CU Completed Action Cmd */
+
+/* Status */
+#define CU_STATUS		0x00C0
+#define RU_STATUS		0x003C
+
+/* Commands */
+#define CU_CMD			0x00F0
+#define RU_CMD			0x0007
+
+int
+e100_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u8 version = (u8)(regs->version >> 24);
+	u8 rev_id = (u8)(regs->version);
+	u8 regs_len = regs->len / sizeof(u32);
+	u32 reg;
+	u16 scb_status, scb_cmd;
+
+	if(version != 1)
+		return -1;
+
+	reg = regs_buff[0];
+	scb_status = reg & 0x0000ffff;
+	scb_cmd = reg >> 16;
+	fprintf(stdout,
+		"SCB Status Word (Lower Word)             0x%04X\n",
+		scb_status);
+
+	switch ((scb_status & RU_STATUS) >> 2) {
+	case 0:
+		fprintf(stdout,
+		"      RU Status:               Idle\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      RU Status:               Suspended\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      RU Status:               No Resources\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      RU Status:               Ready\n");
+		break;
+	case 9:
+		fprintf(stdout,
+		"      RU Status:               Suspended with no more RBDs\n");
+		break;
+	case 10:
+		fprintf(stdout,
+		"      RU Status:               No Resources due to no more RBDs\n");
+		break;
+	case 12:
+		fprintf(stdout,
+		"      RU Status:               Ready with no RBDs present\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      RU Status:               Unknown State\n");
+		break;
+	}
+
+	switch ((scb_status & CU_STATUS) >> 6) {
+	case 0:
+		fprintf(stdout,
+		"      CU Status:               Idle\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      CU Status:               Suspended\n");
+		break;
+        case 2:
+                fprintf(stdout,
+                "      CU Status:              Active\n");
+                break;
+	default:
+		fprintf(stdout,
+		"      CU Status:               Unknown State\n");
+		break;
+	}
+
+	fprintf(stdout,
+	        "      ---- Interrupts Pending ----\n"
+		"      Flow Control Pause:                %s\n"
+		"      Early Receive:                     %s\n"
+		"      Software Generated Interrupt:      %s\n"
+		"      MDI Done:                          %s\n"
+		"      RU Not In Ready State:             %s\n"
+		"      CU Not in Active State:            %s\n"
+		"      RU Received Frame:                 %s\n"
+		"      CU Completed Command:              %s\n",
+		scb_status & FCP_INT_PENDING     ? "yes"     : "no",
+		scb_status & ER_INT_PENDING      ? "yes"     : "no",
+		scb_status & SWI_INT_PENDING     ? "yes"     : "no",
+		scb_status & MDI_INT_PENDING     ? "yes"     : "no",
+		scb_status & RNR_INT_PENDING     ? "yes"     : "no",
+		scb_status & CNA_INT_PENDING     ? "yes"     : "no",
+		scb_status & FR_INT_PENDING      ? "yes"     : "no",
+		scb_status & CX_INT_PENDING      ? "yes"     : "no");
+
+	fprintf(stdout,
+		"SCB Command Word (Upper Word)            0x%04X\n",
+		scb_cmd);
+
+	switch (scb_cmd & RU_CMD) {
+	case 0:
+		fprintf(stdout,
+		"      RU Command:              No Command\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      RU Command:              RU Start\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      RU Command:              RU Resume\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      RU Command:              RU Abort\n");
+		break;
+	case 6:
+		fprintf(stdout,
+		"      RU Command:              Load RU Base\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      RU Command:              Unknown\n");
+		break;
+	}
+
+	switch ((scb_cmd & CU_CMD) >> 4) {
+	case 0:
+		fprintf(stdout,
+		"      CU Command:              No Command\n");
+		break;
+	case 1:
+		fprintf(stdout,
+		"      CU Command:              CU Start\n");
+		break;
+	case 2:
+		fprintf(stdout,
+		"      CU Command:              CU Resume\n");
+		break;
+	case 4:
+		fprintf(stdout,
+		"      CU Command:              Load Dump Counters Address\n");
+		break;
+	case 5:
+		fprintf(stdout,
+		"      CU Command:              Dump Counters\n");
+		break;
+	case 6:
+		fprintf(stdout,
+		"      CU Command:              Load CU Base\n");
+		break;
+	case 7:
+		fprintf(stdout,
+		"      CU Command:              Dump & Reset Counters\n");
+		break;
+	default:
+		fprintf(stdout,
+		"      CU Command:              Unknown\n");
+		break;
+	}
+
+	fprintf(stdout,
+		"      Software Generated Interrupt:      %s\n",
+		scb_cmd & SOFT_INT     ? "yes"     : "no");
+
+	fprintf(stdout,
+	        "      ---- Interrupts Masked ----\n"
+		"      ALL Interrupts:                    %s\n"
+		"      Flow Control Pause:                %s\n"
+		"      Early Receive:                     %s\n"
+		"      RU Not In Ready State:             %s\n"
+		"      CU Not in Active State:            %s\n"
+		"      RU Received Frame:                 %s\n"
+		"      CU Completed Command:              %s\n",
+		scb_cmd & ALL_INT_MASK     ? "yes"     : "no",
+		scb_cmd & FCP_INT_MASK     ? "yes"     : "no",
+		scb_cmd & ER_INT_MASK      ? "yes"     : "no",
+		scb_cmd & RNR_INT_MASK     ? "yes"     : "no",
+		scb_cmd & CNA_INT_MASK     ? "yes"     : "no",
+		scb_cmd & FR_INT_MASK      ? "yes"     : "no",
+		scb_cmd & CX_INT_MASK      ? "yes"     : "no");
+
+	if(regs_len > 1) {
+		fprintf(stdout, "MDI/MDI-X Status:                        ");
+		if(rev_id < D102_REV_ID)
+			fprintf(stdout, "MDI\n");
+		else {
+			u16 ctrl_reg = regs_buff[1];
+
+			if(ctrl_reg & MDI_MDIX_CONFIG_IS_OK) {
+				if(ctrl_reg & MDI_MDIX_STATUS)
+					fprintf(stdout, "MDI-X\n");
+				else
+					fprintf(stdout, "MDI\n");
+			} else
+				fprintf(stdout, "Unknown\n");
+		}
+	}
+
+	return 0;
+}
+
diff --git a/e1000.c b/e1000.c
new file mode 100644
index 0000000..dca7d9d
--- /dev/null
+++ b/e1000.c
@@ -0,0 +1,438 @@
+/* Copyright (c) 2002 Intel Corporation */
+#include <stdio.h>
+#include "ethtool-util.h"
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001      /* Software reset */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS        0x00000300      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+#define E1000_RCTL_SZ           0x00030000      /* rx buffer size */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82545GM_COPPER      0x1026
+#define E1000_DEV_ID_82545GM_FIBER       0x1027
+#define E1000_DEV_ID_82545GM_SERDES      0x1028
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
+#define E1000_DEV_ID_82541EI             0x1013
+#define E1000_DEV_ID_82541EI_MOBILE      0x1018
+#define E1000_DEV_ID_82541ER             0x1078
+#define E1000_DEV_ID_82547GI             0x1075
+#define E1000_DEV_ID_82541GI             0x1076
+#define E1000_DEV_ID_82541GI_MOBILE      0x1077
+#define E1000_DEV_ID_82546GB_COPPER      0x1079
+#define E1000_DEV_ID_82546GB_FIBER       0x107A
+#define E1000_DEV_ID_82546GB_SERDES      0x107B
+#define E1000_DEV_ID_82547EI             0x1019
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+enum e1000_mac_type {
+	e1000_undefined = 0,
+	e1000_82542_rev2_0,
+	e1000_82542_rev2_1,
+	e1000_82543,
+	e1000_82544,
+	e1000_82540,
+	e1000_82545,
+	e1000_82545_rev_3,
+	e1000_82546,
+	e1000_82546_rev_3,
+	e1000_82541,
+	e1000_82541_rev_2,
+	e1000_82547,
+	e1000_82547_rev_2,
+	e1000_num_macs
+};
+
+static enum e1000_mac_type
+e1000_get_mac_type(u16 device_id, u8 revision_id)
+{
+	enum e1000_mac_type mac_type = e1000_undefined;
+
+	switch (device_id) {
+	case E1000_DEV_ID_82542:
+		switch (revision_id) {
+		case E1000_82542_2_0_REV_ID:
+			mac_type = e1000_82542_rev2_0;
+			break;
+		case E1000_82542_2_1_REV_ID:
+			mac_type = e1000_82542_rev2_1;
+			break;
+		default:
+			mac_type = e1000_82542_rev2_0;
+		}
+		break;
+	case E1000_DEV_ID_82543GC_FIBER:
+	case E1000_DEV_ID_82543GC_COPPER:
+		mac_type = e1000_82543;
+		break;
+	case E1000_DEV_ID_82544EI_COPPER:
+	case E1000_DEV_ID_82544EI_FIBER:
+	case E1000_DEV_ID_82544GC_COPPER:
+	case E1000_DEV_ID_82544GC_LOM:
+		mac_type = e1000_82544;
+		break;
+	case E1000_DEV_ID_82540EM:
+	case E1000_DEV_ID_82540EM_LOM:
+	case E1000_DEV_ID_82540EP:
+	case E1000_DEV_ID_82540EP_LOM:
+	case E1000_DEV_ID_82540EP_LP:
+		mac_type = e1000_82540;
+		break;
+	case E1000_DEV_ID_82545EM_COPPER:
+	case E1000_DEV_ID_82545EM_FIBER:
+		mac_type = e1000_82545;
+		break;
+	case E1000_DEV_ID_82545GM_COPPER:
+	case E1000_DEV_ID_82545GM_FIBER:
+	case E1000_DEV_ID_82545GM_SERDES:
+		mac_type = e1000_82545_rev_3;
+		break;
+	case E1000_DEV_ID_82546EB_COPPER:
+	case E1000_DEV_ID_82546EB_FIBER:
+	case E1000_DEV_ID_82546EB_QUAD_COPPER:
+		mac_type = e1000_82546;
+		break;
+	case E1000_DEV_ID_82546GB_COPPER:
+	case E1000_DEV_ID_82546GB_FIBER:
+	case E1000_DEV_ID_82546GB_SERDES:
+		mac_type = e1000_82546_rev_3;
+		break;
+	case E1000_DEV_ID_82541EI:
+	case E1000_DEV_ID_82541EI_MOBILE:
+		mac_type = e1000_82541;
+		break;
+	case E1000_DEV_ID_82541ER:
+	case E1000_DEV_ID_82541GI:
+	case E1000_DEV_ID_82541GI_MOBILE:
+		mac_type = e1000_82541_rev_2;
+		break;
+	case E1000_DEV_ID_82547EI:
+		mac_type = e1000_82547;
+		break;
+	case E1000_DEV_ID_82547GI:
+		mac_type = e1000_82547_rev_2;
+		break;
+	default:
+		/* list of supported devices probably needs updating */
+		mac_type = e1000_82543;
+		break;
+	}
+
+	return mac_type;
+}
+
+int
+e1000_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 *regs_buff = (u32 *)regs->data;
+	u16 hw_device_id = (u16)regs->version;
+	u8 hw_revision_id = (u8)(regs->version >> 16);
+	u8 version = (u8)(regs->version >> 24);
+	enum e1000_mac_type mac_type;
+	u32 reg;
+
+	if(version != 1)
+		return -1;
+
+	mac_type = e1000_get_mac_type(hw_device_id, hw_revision_id);
+
+	if(mac_type == e1000_undefined)
+		return -1;
+
+	fprintf(stdout, "MAC Registers\n");
+	fprintf(stdout, "-------------\n");
+
+	/* Device control register */
+	reg = regs_buff[0];
+	fprintf(stdout,
+		"0x00000: CTRL (Device control register)  0x%08X\n"
+		"      Duplex:                            %s\n"
+		"      Endian mode (buffers):             %s\n"
+		"      Link reset:                        %s\n"
+		"      Set link up:                       %s\n"
+		"      Invert Loss-Of-Signal:             %s\n"
+		"      Receive flow control:              %s\n"
+		"      Transmit flow control:             %s\n"
+		"      VLAN mode:                         %s\n",
+		reg,
+		reg & E1000_CTRL_FD     ? "full"     : "half",
+		reg & E1000_CTRL_BEM    ? "big"      : "little",
+		reg & E1000_CTRL_LRST   ? "reset"    : "normal",
+		reg & E1000_CTRL_SLU    ? "1"        : "0",
+		reg & E1000_CTRL_ILOS   ? "yes"      : "no",
+		reg & E1000_CTRL_RFCE   ? "enabled"  : "disabled",
+		reg & E1000_CTRL_TFCE   ? "enabled"  : "disabled",
+		reg & E1000_CTRL_VME    ? "enabled"  : "disabled");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Auto speed detect:                 %s\n"
+		"      Speed select:                      %s\n"
+		"      Force speed:                       %s\n"
+		"      Force duplex:                      %s\n",
+		reg & E1000_CTRL_ASDE   ? "enabled"  : "disabled",
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_10   ? "10Mb/s"   :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_100  ? "100Mb/s"  :
+		(reg & E1000_CTRL_SPD_SEL) == E1000_CTRL_SPD_1000 ? "1000Mb/s" :
+		"not used",
+		reg & E1000_CTRL_FRCSPD ? "yes"      : "no",
+		reg & E1000_CTRL_FRCDPX ? "yes"      : "no");
+	}
+
+	/* Device status register */
+	reg = regs_buff[1];
+	fprintf(stdout,
+		"0x00008: STATUS (Device status register) 0x%08X\n"
+		"      Duplex:                            %s\n"
+		"      Link up:                           %s\n",
+		reg,
+		reg & E1000_STATUS_FD      ? "full"        : "half",
+		reg & E1000_STATUS_LU      ? "link config" : "no link config");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      TBI mode:                          %s\n"
+		"      Link speed:                        %s\n"
+		"      Bus type:                          %s\n"
+		"      Bus speed:                         %s\n"
+		"      Bus width:                         %s\n",
+		reg & E1000_STATUS_TBIMODE ? "enabled"     : "disabled",
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_10   ?
+		"10Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_100  ?
+		"100Mb/s" :
+		(reg & E1000_STATUS_SPEED_MASK) == E1000_STATUS_SPEED_1000 ?
+		"1000Mb/s" : "not used",
+		(reg & E1000_STATUS_PCIX_MODE) ? "PCI-X" : "PCI",
+		(reg & E1000_STATUS_PCIX_MODE) ?
+			((reg & E1000_STATUS_PCIX_SPEED_133) ? "133MHz" :
+			(reg & E1000_STATUS_PCIX_SPEED_100) ? "100MHz" :
+			"66MHz")	       :
+			((reg & E1000_STATUS_PCI66) ? "66MHz" : "33MHz"),
+		(reg & E1000_STATUS_BUS64) ? "64-bit" : "32-bit");
+	}
+
+	/* Receive control register */
+	reg = regs_buff[2];
+	fprintf(stdout,
+		"0x00100: RCTL (Receive control register) 0x%08X\n"
+		"      Receiver:                          %s\n"
+		"      Store bad packets:                 %s\n"
+		"      Unicast promiscuous:               %s\n"
+		"      Multicast promiscuous:             %s\n"
+		"      Long packet:                       %s\n"
+		"      Descriptor minimum threshold size: %s\n"
+		"      Broadcast accept mode:             %s\n"
+		"      VLAN filter:                       %s\n"
+		"      Cononical form indicator:          %s\n"
+		"      Discard pause frames:              %s\n"
+		"      Pass MAC control frames:           %s\n",
+		reg,
+		reg & E1000_RCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_RCTL_SBP     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_UPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_MPE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_LPE     ? "enabled"  : "disabled",
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_HALF  ? "1/2" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_QUAT  ? "1/4" :
+		(reg & E1000_RCTL_RDMTS) == E1000_RCTL_RDMTS_EIGTH ? "1/8" :
+		"reserved",
+		reg & E1000_RCTL_BAM     ? "accept"   : "ignore",
+		reg & E1000_RCTL_VFE     ? "enabled"  : "disabled",
+		reg & E1000_RCTL_CFIEN   ? "enabled"  : "disabled",
+		reg & E1000_RCTL_DPF     ? "ignored"  : "filtered",
+		reg & E1000_RCTL_PMCF    ? "pass"     : "don't pass");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Receive buffer size:               %s\n",
+		reg & E1000_RCTL_BSEX    ?
+			((reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_16384 ? "16384" :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_8192  ? "8192"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_4096  ? "4096"  :
+			 "reserved")     :
+			((reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_2048  ? "2048"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_1024  ? "1024"  :
+			 (reg & E1000_RCTL_SZ)==E1000_RCTL_SZ_512   ? "512"   :
+			 "256"));
+	} else {
+	fprintf(stdout,
+		"      Receive buffer size:               %s\n",
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_2048  ? "2048"  :
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_1024  ? "1024"  :
+		(reg & E1000_RCTL_SZ) == E1000_RCTL_SZ_512   ? "512"   :
+		"256");
+	}
+
+	/* Receive descriptor registers */
+	fprintf(stdout,
+		"0x02808: RDLEN (Receive desc length)     0x%08X\n",
+		regs_buff[3]);
+	fprintf(stdout,
+		"0x02810: RDH   (Receive desc head)       0x%08X\n",
+		regs_buff[4]);
+	fprintf(stdout,
+		"0x02818: RDT   (Receive desc tail)       0x%08X\n",
+		regs_buff[5]);
+	fprintf(stdout,
+		"0x02820: RDTR  (Receive delay timer)     0x%08X\n",
+		regs_buff[6]);
+
+	/* Transmit control register */
+	reg = regs_buff[7];
+	fprintf(stdout,
+		"0x00400: TCTL (Transmit ctrl register)   0x%08X\n"
+		"      Transmitter:                       %s\n"
+		"      Pad short packets:                 %s\n"
+		"      Software XOFF Transmission:        %s\n",
+		reg,
+		reg & E1000_TCTL_EN      ? "enabled"  : "disabled",
+		reg & E1000_TCTL_PSP     ? "enabled"  : "disabled",
+		reg & E1000_TCTL_SWXOFF  ? "enabled"  : "disabled");
+	if(mac_type >= e1000_82543) {
+	fprintf(stdout,
+		"      Re-transmit on late collision:     %s\n",
+		reg & E1000_TCTL_RTLC    ? "enabled"  : "disabled");
+	}
+
+	/* Transmit descriptor registers */
+	fprintf(stdout,
+		"0x03808: TDLEN (Transmit desc length)    0x%08X\n",
+		regs_buff[8]);
+	fprintf(stdout,
+		"0x03810: TDH   (Transmit desc head)      0x%08X\n",
+		regs_buff[9]);
+	fprintf(stdout,
+		"0x03818: TDT   (Transmit desc tail)      0x%08X\n",
+		regs_buff[10]);
+	fprintf(stdout,
+		"0x03820: TIDV  (Transmit delay timer)    0x%08X\n",
+		regs_buff[11]);
+
+	/* PHY type */
+	fprintf(stdout,
+		"PHY type:                                %s\n",
+		regs_buff[12] == 0 ? "M88" : "IGP");
+
+	return 0;
+}
+
diff --git a/ethtool-copy.h b/ethtool-copy.h
new file mode 100644
index 0000000..41aae0d
--- /dev/null
+++ b/ethtool-copy.h
@@ -0,0 +1,366 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ *                                christopher.leech@intel.com,
+ *                                scott.feldman@intel.com)
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+
+/* This should work for both 32 and 64 bit userland. */
+struct ethtool_cmd {
+	u32	cmd;
+	u32	supported;	/* Features this interface supports */
+	u32	advertising;	/* Features this interface advertises */
+	u16	speed;		/* The forced speed, 10Mb, 100Mb, gigabit */
+	u8	duplex;		/* Duplex, half or full */
+	u8	port;		/* Which connector port */
+	u8	phy_address;
+	u8	transceiver;	/* Which tranceiver to use */
+	u8	autoneg;	/* Enable or disable autonegotiation */
+	u32	maxtxpkt;	/* Tx pkts before generating tx int */
+	u32	maxrxpkt;	/* Rx pkts before generating rx int */
+	u32	reserved[4];
+};
+
+#define ETHTOOL_BUSINFO_LEN	32
+/* these strings are set to whatever the driver author decides... */
+struct ethtool_drvinfo {
+	u32	cmd;
+	char	driver[32];	/* driver short name, "tulip", "eepro100" */
+	char	version[32];	/* driver version string */
+	char	fw_version[32];	/* firmware version string, if applicable */
+	char	bus_info[ETHTOOL_BUSINFO_LEN];	/* Bus info for this IF. */
+				/* For PCI devices, use pci_dev->slot_name. */
+	char	reserved1[32];
+	char	reserved2[16];
+	u32	n_stats;	/* number of u64's from ETHTOOL_GSTATS */
+	u32	testinfo_len;
+	u32	eedump_len;	/* Size of data from ETHTOOL_GEEPROM (bytes) */
+	u32	regdump_len;	/* Size of data from ETHTOOL_GREGS (bytes) */
+};
+
+#define SOPASS_MAX	6
+/* wake-on-lan settings */
+struct ethtool_wolinfo {
+	u32	cmd;
+	u32	supported;
+	u32	wolopts;
+	u8	sopass[SOPASS_MAX]; /* SecureOn(tm) password */
+};
+
+/* for passing single values */
+struct ethtool_value {
+	u32	cmd;
+	u32	data;
+};
+
+/* for passing big chunks of data */
+struct ethtool_regs {
+	u32	cmd;
+	u32	version; /* driver-specific, indicates different chips/revs */
+	u32	len; /* bytes */
+	u8	data[0];
+};
+
+/* for passing EEPROM chunks */
+struct ethtool_eeprom {
+	u32	cmd;
+	u32	magic;
+	u32	offset; /* in bytes */
+	u32	len; /* in bytes */
+	u8	data[0];
+};
+
+/* for configuring coalescing parameters of chip */
+struct ethtool_coalesce {
+	u32	cmd;	/* ETHTOOL_{G,S}COALESCE */
+
+	/* How many usecs to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	rx_coalesce_usecs;
+
+	/* How many packets to delay an RX interrupt after
+	 * a packet arrives.  If 0, only rx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause RX interrupts to never be
+	 * generated.
+	 */
+	u32	rx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being services by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	rx_coalesce_usecs_irq;
+	u32	rx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_max_coalesced_frames
+	 * is used.
+	 */
+	u32	tx_coalesce_usecs;
+
+	/* How many packets to delay a TX interrupt after
+	 * a packet is sent.  If 0, only tx_coalesce_usecs is
+	 * used.  It is illegal to set both usecs and max frames
+	 * to zero as this would cause TX interrupts to never be
+	 * generated.
+	 */
+	u32	tx_max_coalesced_frames;
+
+	/* Same as above two parameters, except that these values
+	 * apply while an IRQ is being services by the host.  Not
+	 * all cards support this feature and the values are ignored
+	 * in that case.
+	 */
+	u32	tx_coalesce_usecs_irq;
+	u32	tx_max_coalesced_frames_irq;
+
+	/* How many usecs to delay in-memory statistics
+	 * block updates.  Some drivers do not have an in-memory
+	 * statistic block, and in such cases this value is ignored.
+	 * This value must not be zero.
+	 */
+	u32	stats_block_coalesce_usecs;
+
+	/* Adaptive RX/TX coalescing is an algorithm implemented by
+	 * some drivers to improve latency under low packet rates and
+	 * improve throughput under high packet rates.  Some drivers
+	 * only implement one of RX or TX adaptive coalescing.  Anything
+	 * not implemented by the driver causes these values to be
+	 * silently ignored.
+	 */
+	u32	use_adaptive_rx_coalesce;
+	u32	use_adaptive_tx_coalesce;
+
+	/* When the packet rate (measured in packets per second)
+	 * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+	 * used.
+	 */
+	u32	pkt_rate_low;
+	u32	rx_coalesce_usecs_low;
+	u32	rx_max_coalesced_frames_low;
+	u32	tx_coalesce_usecs_low;
+	u32	tx_max_coalesced_frames_low;
+
+	/* When the packet rate is below pkt_rate_high but above
+	 * pkt_rate_low (both measured in packets per second) the
+	 * normal {rx,tx}_* coalescing parameters are used.
+	 */
+
+	/* When the packet rate is (measured in packets per second)
+	 * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+	 * used.
+	 */
+	u32	pkt_rate_high;
+	u32	rx_coalesce_usecs_high;
+	u32	rx_max_coalesced_frames_high;
+	u32	tx_coalesce_usecs_high;
+	u32	tx_max_coalesced_frames_high;
+
+	/* How often to do adaptive coalescing packet rate sampling,
+	 * measured in seconds.  Must not be zero.
+	 */
+	u32	rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+	u32	cmd;	/* ETHTOOL_{G,S}RINGPARAM */
+
+	/* Read only attributes.  These indicate the maximum number
+	 * of pending RX/TX ring entries the driver will allow the
+	 * user to set.
+	 */
+	u32	rx_max_pending;
+	u32	rx_mini_max_pending;
+	u32	rx_jumbo_max_pending;
+	u32	tx_max_pending;
+
+	/* Values changeable by the user.  The valid values are
+	 * in the range 1 to the "*_max_pending" counterpart above.
+	 */
+	u32	rx_pending;
+	u32	rx_mini_pending;
+	u32	rx_jumbo_pending;
+	u32	tx_pending;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+	u32	cmd;	/* ETHTOOL_{G,S}PAUSEPARAM */
+
+	/* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+	 * being true) the user may set 'autonet' here non-zero to have the
+	 * pause parameters be auto-negotiated too.  In such a case, the
+	 * {rx,tx}_pause values below determine what capabilities are
+	 * advertised.
+	 *
+	 * If 'autoneg' is zero or the link is not being auto-negotiated,
+	 * then {rx,tx}_pause force the driver to use/not-use pause
+	 * flow control.
+	 */
+	u32	autoneg;
+	u32	rx_pause;
+	u32	tx_pause;
+};
+
+#define ETH_GSTRING_LEN		32
+enum ethtool_stringset {
+	ETH_SS_TEST		= 0,
+	ETH_SS_STATS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+	u32	cmd;		/* ETHTOOL_GSTRINGS */
+	u32	string_set;	/* string set id e.c. ETH_SS_TEST, etc*/
+	u32	len;		/* number of strings in the string set */
+	u8	data[0];
+};
+
+enum ethtool_test_flags {
+	ETH_TEST_FL_OFFLINE	= (1 << 0),	/* online / offline */
+	ETH_TEST_FL_FAILED	= (1 << 1),	/* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+	u32	cmd;		/* ETHTOOL_TEST */
+	u32	flags;		/* ETH_TEST_FL_xxx */
+	u32	reserved;
+	u32	len;		/* result length, in number of u64 elements */
+	u64	data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+	u32	cmd;		/* ETHTOOL_GSTATS */
+	u32	n_stats;	/* number of u64's being returned */
+	u64	data[0];
+};
+
+/* CMDs currently supported */
+#define ETHTOOL_GSET		0x00000001 /* Get settings. */
+#define ETHTOOL_SSET		0x00000002 /* Set settings, privileged. */
+#define ETHTOOL_GDRVINFO	0x00000003 /* Get driver info. */
+#define ETHTOOL_GREGS		0x00000004 /* Get NIC registers, privileged. */
+#define ETHTOOL_GWOL		0x00000005 /* Get wake-on-lan options. */
+#define ETHTOOL_SWOL		0x00000006 /* Set wake-on-lan options, priv. */
+#define ETHTOOL_GMSGLVL		0x00000007 /* Get driver message level */
+#define ETHTOOL_SMSGLVL		0x00000008 /* Set driver msg level, priv. */
+#define ETHTOOL_NWAY_RST	0x00000009 /* Restart autonegotiation, priv. */
+#define ETHTOOL_GLINK		0x0000000a /* Get link status (ethtool_value) */
+#define ETHTOOL_GEEPROM		0x0000000b /* Get EEPROM data */
+#define ETHTOOL_SEEPROM		0x0000000c /* Set EEPROM data, priv. */
+#define ETHTOOL_GCOALESCE	0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE	0x0000000f /* Set coalesce config, priv. */
+#define ETHTOOL_GRINGPARAM	0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM	0x00000011 /* Set ring parameters, priv. */
+#define ETHTOOL_GPAUSEPARAM	0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM	0x00000013 /* Set pause parameters, priv. */
+#define ETHTOOL_GRXCSUM		0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM		0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM		0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM		0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG		0x00000018 /* Get scatter-gather enable
+					    * (ethtool_value) */
+#define ETHTOOL_SSG		0x00000019 /* Set scatter-gather enable
+					    * (ethtool_value), priv. */
+#define ETHTOOL_TEST		0x0000001a /* execute NIC self-test, priv. */
+#define ETHTOOL_GSTRINGS	0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID		0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS		0x0000001d /* get NIC-specific statistics */
+#define ETHTOOL_GTSO		0x0000001e /* Get TSO enable (ethtool_value) */
+#define ETHTOOL_STSO		0x0000001f /* Set TSO enable (ethtool_value) */
+
+/* compatibility with older code */
+#define SPARC_ETH_GSET		ETHTOOL_GSET
+#define SPARC_ETH_SSET		ETHTOOL_SSET
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half		(1 << 0)
+#define SUPPORTED_10baseT_Full		(1 << 1)
+#define SUPPORTED_100baseT_Half		(1 << 2)
+#define SUPPORTED_100baseT_Full		(1 << 3)
+#define SUPPORTED_1000baseT_Half	(1 << 4)
+#define SUPPORTED_1000baseT_Full	(1 << 5)
+#define SUPPORTED_Autoneg		(1 << 6)
+#define SUPPORTED_TP			(1 << 7)
+#define SUPPORTED_AUI			(1 << 8)
+#define SUPPORTED_MII			(1 << 9)
+#define SUPPORTED_FIBRE			(1 << 10)
+#define SUPPORTED_BNC			(1 << 11)
+#define SUPPORTED_10000baseT_Full	(1 << 12)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half		(1 << 0)
+#define ADVERTISED_10baseT_Full		(1 << 1)
+#define ADVERTISED_100baseT_Half	(1 << 2)
+#define ADVERTISED_100baseT_Full	(1 << 3)
+#define ADVERTISED_1000baseT_Half	(1 << 4)
+#define ADVERTISED_1000baseT_Full	(1 << 5)
+#define ADVERTISED_Autoneg		(1 << 6)
+#define ADVERTISED_TP			(1 << 7)
+#define ADVERTISED_AUI			(1 << 8)
+#define ADVERTISED_MII			(1 << 9)
+#define ADVERTISED_FIBRE		(1 << 10)
+#define ADVERTISED_BNC			(1 << 11)
+#define ADVERTISED_10000baseT_Full	(1 << 12)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things.  When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */
+#define SPEED_10		10
+#define SPEED_100		100
+#define SPEED_1000		1000
+#define SPEED_10000		10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF		0x00
+#define DUPLEX_FULL		0x01
+
+/* Which connector port. */
+#define PORT_TP			0x00
+#define PORT_AUI		0x01
+#define PORT_MII		0x02
+#define PORT_FIBRE		0x03
+#define PORT_BNC		0x04
+
+/* Which tranceiver to use. */
+#define XCVR_INTERNAL		0x00
+#define XCVR_EXTERNAL		0x01
+#define XCVR_DUMMY1		0x02
+#define XCVR_DUMMY2		0x03
+#define XCVR_DUMMY3		0x04
+
+/* Enable or disable autonegotiation.  If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE		0x00
+#define AUTONEG_ENABLE		0x01
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY		(1 << 0)
+#define WAKE_UCAST		(1 << 1)
+#define WAKE_MCAST		(1 << 2)
+#define WAKE_BCAST		(1 << 3)
+#define WAKE_ARP		(1 << 4)
+#define WAKE_MAGIC		(1 << 5)
+#define WAKE_MAGICSECURE	(1 << 6) /* only meaningful if WAKE_MAGIC */
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/ethtool-util.h b/ethtool-util.h
new file mode 100644
index 0000000..a69fa86
--- /dev/null
+++ b/ethtool-util.h
@@ -0,0 +1,42 @@
+/* Portions Copyright 2001 Sun Microsystems (thockin@sun.com) */
+/* Portions Copyright 2002 Intel (scott.feldman@intel.com) */
+#ifndef ETHTOOL_UTIL_H__
+#define ETHTOOL_UTIL_H__
+
+#include <sys/types.h>
+typedef unsigned long long u64;         /* hack, so we may include kernel's ethtool.h */
+typedef __uint32_t u32;         /* ditto */
+typedef __uint16_t u16;         /* ditto */
+typedef __uint8_t u8;           /* ditto */
+#include "ethtool-copy.h"
+
+/* National Semiconductor DP83815, DP83816 */
+int natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+int natsemi_dump_eeprom(struct ethtool_drvinfo *info,
+	struct ethtool_eeprom *ee);
+
+/* Digital/Intel 21040 and 21041 */
+int de2104x_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Intel(R) PRO/1000 Gigabit Adapter Family */
+int e1000_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* RealTek PCI */
+int realtek_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Intel(R) PRO/100 Fast Ethernet Adapter Family */
+int e100_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Tigon3 */
+int tg3_dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee);
+
+/* Advanced Micro Devices  AMD8111 based Adapter */
+int amd8111e_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Advanced Micro Devices PCnet32 Adapter */
+int pcnet32_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+/* Motorola 8xx FEC Ethernet controller */
+int fec_8xx_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+#endif
diff --git a/ethtool.8 b/ethtool.8
new file mode 100644
index 0000000..d760907
--- /dev/null
+++ b/ethtool.8
@@ -0,0 +1,384 @@
+.\" -*- nroff -*-
+.\" Copyright 1999 by David S. Miller.  All Rights Reserved.
+.\" Portions Copyright 2001 Sun Microsystems
+.\" This file may be copied under the terms of the GNU Public License.
+.\" 
+.\"	.An - list of n alternative values as in "flav vanilla|strawberry"
+.\"
+.de A1
+\\fB\\$1\\fP|\\fB\\$2\\fP
+..
+.de A2
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP
+..
+.de A3
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP
+..
+.de A4
+\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP|\\fB\\$5\\fP
+..
+.\" 
+.\"	.Bn - same as above but framed by square brackets
+.\"
+.de B1
+[\\fB\\$1\\fP|\\fB\\$2\\fP]
+..
+.de B2
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP]
+..
+.de B3
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP]
+..
+.de B4
+[\\fB\\$1\\fP\ \\fB\\$2\\fP|\\fB\\$3\\fP|\\fB\\$4\\fP|\\fB\\$5\\fP]
+..
+.\"
+.\"	\(*MA - mac address
+.\"
+.ds MA \fIxx\fP\fB:\fP\fIyy\fP\fB:\fP\fIzz\fP\fB:\fP\fIaa\fP\fB:\fP\fIbb\fP\fB:\fP\fIcc\fP
+.\"
+.\"	\(*WO - wol flags
+.\"
+.ds WO \fBp\fP|\fBu\fP|\fBm\fP|\fBb\fP|\fBa\fP|\fBg\fP|\fBs\fP|\fBd\fP...
+.TH ETHTOOL 8 "January 2005" "Ethtool version 3"
+.SH NAME
+ethtool \- Display or change ethernet card settings
+.SH SYNOPSIS
+.B ethtool
+.I ethX
+
+.B ethtool \-h
+
+.B ethtool \-a
+.I ethX
+
+.B ethtool \-A
+.I ethX
+.B2 autoneg on off
+.B2 rx on off
+.B2 tx on off
+
+.B ethtool \-c
+.I ethX
+
+.B ethtool \-C
+.I ethX
+.B2 adaptive-rx on off
+.B2 adaptive-tx on off
+.RB [ rx-usecs
+.IR N ]
+.RB [ rx-frames
+.IR N ]
+.RB [ rx-usecs-irq
+.IR N ]
+.RB [ rx-frames-irq
+.IR N ]
+.RB [ tx-usecs
+.IR N ]
+.RB [ tx-frames
+.IR N ]
+.RB [ tx-usecs-irq
+.IR N ]
+.RB [ tx-frames-irq
+.IR N ]
+.RB [ stats-block-usecs
+.IR N ]
+.RB [ pkt-rate-low
+.IR N ]
+.RB [ rx-usecs-low
+.IR N ]
+.RB [ rx-frames-low
+.IR N ]
+.RB [ tx-usecs-low
+.IR N ]
+.RB [ tx-frames-low
+.IR N ]
+.RB [ pkt-rate-high
+.IR N ]
+.RB [ rx-usecs-high
+.IR N ]
+.RB [ rx-frames-high
+.IR N ]
+.RB [ tx-usecs-high
+.IR N ]
+.RB [ tx-frames-high
+.IR N ]
+.RB [ sample-interval
+.IR N ]
+
+.B ethtool \-g
+.I ethX
+
+.B ethtool \-G
+.I ethX
+.RB [ rx
+.IR N ]
+.RB [ rx-mini
+.IR N ]
+.RB [ rx-jumbo
+.IR N ]
+.RB [ tx
+.IR N ]
+
+.B ethtool \-i
+.I ethX
+
+.B ethtool \-d
+.I ethX
+.B2 raw on off
+
+.B ethtool \-e
+.I ethX
+.B2 raw on off
+.RB [ offset
+.IR N ]
+.RB [ length
+.IR N ]
+
+.B ethtool \-E
+.I ethX
+.RB [ magic
+.IR N ]
+.RB [ offset
+.IR N ]
+.RB [ value
+.IR N ]
+
+.B ethtool \-k
+.I ethX
+
+.B ethtool \-K
+.I ethX
+.B2 rx on off
+.B2 tx on off
+.B2 sg on off
+.B2 tso on off
+
+.B ethtool \-p
+.I ethX
+.IR [ N ]
+
+.B ethtool \-r
+.I ethX
+
+.B ethtool \-S
+.I ethX
+
+.B ethtool \-t
+.I ethX
+.B1 offline online
+
+.B ethtool \-s
+.I ethX
+.B3 speed 10 100 1000
+.B2 duplex half full
+.B4 port tp aui bnc mii fibre
+.B2 autoneg on off
+.RB [ phyad
+.IR N ]
+.B2 xcvr internal external
+.RB [ wol \ \*(WO]
+.RB [ sopass \ \*(MA]
+.RB [ msglvl
+.IR N ]
+.SH DESCRIPTION
+.BI ethtool
+is used for querying settings of an ethernet device and changing them.
+
+.I ethX
+is the name of the ethernet device to work on.
+
+.SH OPTIONS
+.B ethtool
+with a single argument specifying the device name prints current
+setting of the specified device.
+.TP
+.B \-h
+shows a short help message.
+.TP
+.B \-a
+queries the specified ethernet device for pause parameter information.
+.TP
+.B \-A
+change the pause parameters of the specified ethernet device.
+.TP
+.A2 autoneg on off
+Specify if pause autonegotiation is enabled.
+.TP
+.A2 rx on off
+Specify if RX pause is enabled.
+.TP
+.A2 tx on off
+Specify if TX pause is enabled.
+.TP
+.B \-c
+queries the specified ethernet device for coalescing information.
+.TP
+.B \-C
+change the coalescing settings of the specified ethernet device.
+.TP
+.B \-g
+queries the specified ethernet device for rx/tx ring parameter information.
+.TP
+.B \-G
+change the rx/tx ring parameters of the specified ethernet device.
+.TP
+.BI rx \ N
+Change number of ring entries for the Rx ring.
+.TP
+.BI rx-mini \ N
+Change number of ring entries for the Rx Mini ring.
+.TP
+.BI rx-jumbo \ N
+Change number of ring entries for the Rx Jumbo ring.
+.TP
+.BI tx \ N
+Change number of ring entries for the Tx ring.
+.TP
+.B \-i
+queries the specified ethernet device for associated driver information.
+.TP
+.B \-d
+retrieves and prints a register dump for the specified ethernet device.
+When raw is enabled, then it dumps the raw register data to stdout.
+.TP
+.B \-e
+retrieves and prints an EEPROM dump for the specified ethernet device.
+When raw is enabled, then it dumps the raw EEPROM data to stdout. The
+length and offset parameters allow dumping certain portions of the EEPROM.
+Default is to dump the entire EEPROM.
+.TP
+.B \-E
+Changes EEPROM byte for the specified ethernet device.  offset and value
+specify which byte and it's new value.  Because of the persistent nature
+of writing to the EEPROM, a device-specific magic key must be specified
+to prevent the accidental writing to the EEPROM.
+.TP
+.B \-k
+queries the specified ethernet device for offload information.
+.TP
+.B \-K
+change the offload parameters of the specified ethernet device.
+.TP
+.A2 rx on off
+Specify if RX checksumming is enabled.
+.TP
+.A2 tx on off
+Specify if TX checksumming is enabled.
+.TP
+.A2 sg on off
+Specify if scatter-gather is enabled.
+.TP
+.A2 tso on off
+Specify if tcp segmentation offload is enabled.
+.TP
+.B \-p
+initiates adapter-specific action intended to enable an operator to
+easily identify the adapter by sight.  typically this involves
+blinking one or more LEDs on the specific ethernet port.
+.TP
+.B N
+Length of time to perform phys-id, in seconds.
+.TP
+.B \-r
+restarts auto-negotiation on the specified ethernet device, if
+auto-negotiation is enabled.
+.TP
+.B \-S
+queries the specified ethernet device for NIC- and driver-specific
+statistics.
+.TP
+.B \-t
+executes adapter selftest on the specified ethernet device. Possible test modes are:
+.TP
+.A1 offline online
+defines test type: 
+.B offline
+(default) means to perform full set of tests possibly causing normal operation interruption during the tests,
+.B online
+means to perform limited set of tests do not interrupting normal adapter operation.
+.TP
+.B \-s
+option allows changing some or all settings of the specified ethernet device.
+All following options only apply if
+.B \-s
+was specified.
+.TP
+.A3 speed 10 100 1000
+Set speed in Mb/s.
+.B ethtool
+with single argument will show you the supported device speeds.
+.TP
+.A2 duplex half full
+Set full or half duplex mode.
+.TP
+.A4 port tp aui bnc mii fibre
+Select device port.
+.TP
+.A2 autoneg on off
+Specify if autonegotiation is enabled. In the usual case it is, but might
+cause some problems with some network devices, so you can turn it off.
+.TP
+.BI phyad \ N
+PHY address.
+.TP
+.A2 xcvr internal external
+Select transceiver type. Currently only internal and external can be
+specified, in the future further types might be added.
+.TP
+.BR wol \ \*(WO
+Set Wake-on-LAN options.  Not all devices support this.  The argument to 
+this option is a string of characters specifying which options to enable.
+.RS
+.PD 0
+.TP 3
+.B p
+Wake on phy activity
+.TP 3
+.B u
+Wake on unicast messages
+.TP 3
+.B m
+Wake on multicast messages
+.TP 3
+.B b
+Wake on broadcast messages
+.TP 3
+.B a
+Wake on ARP
+.TP 3
+.B g
+Wake on MagicPacket(tm)
+.TP 3
+.B s
+Enable SecureOn(tm) password for MagicPacket(tm)
+.TP 3
+.B d
+Disable (wake on nothing).  This option clears all previous options.
+.PD
+.RE
+.TP
+.B sopass \*(MA\c
+Set the SecureOn(tm) password.  The argument to this option must be 6
+bytes in ethernet MAC hex format (\*(MA).
+.TP
+.BI msglvl \ N
+Set the driver message level. Meanings differ per driver.
+.SH BUGS
+Not supported (in part or whole) on all ethernet drivers.
+.SH AUTHOR
+.B ethtool
+was written by David Miller.
+
+Modifications by 
+Jeff Garzik, 
+Tim Hockin,
+Jakub Jelinek,
+Andre Majorel,
+Eli Kupermann,
+Scott Feldman.
+.SH AVAILABILITY
+.B ethtool
+is available over the Web on the SourceForge site at
+http://sourceforge.net/projects/gkernel/
+
diff --git a/ethtool.c b/ethtool.c
new file mode 100644
index 0000000..1eceb63
--- /dev/null
+++ b/ethtool.c
@@ -0,0 +1,2003 @@
+/*
+ * ethtool.c: Linux ethernet device configuration tool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com)
+ * Portions Copyright 2001 Sun Microsystems
+ * Kernel 2.4 update Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Wake-on-LAN,natsemi,misc support by Tim Hockin <thockin@sun.com>
+ * Portions Copyright 2002 Intel
+ * do_test support by Eli Kupermann <eli.kupermann@intel.com>
+ * ETHTOOL_PHYS_ID support by Chris Leech <christopher.leech@intel.com>
+ * e1000 support by Scott Feldman <scott.feldman@intel.com>
+ * e100 support by Wen Tao <wen-hwa.tao@intel.com>
+ * amd8111e support by Reeja John <reeja.john@amd.com>
+ *
+ * TODO:
+ *   * no-args => summary of each device (mii-tool style)
+ *   * better man page (steal from mii-tool?)
+ *   * fall back on SIOCMII* ioctl()s and possibly SIOCDEVPRIVATE*
+ *   * abstract ioctls to allow for fallback modes of data gathering
+ *   * symbolic names for msglvl bitmask
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "ethtool-config.h"
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <net/if.h>
+
+#include <linux/sockios.h>
+#include "ethtool-util.h"
+
+#ifndef SIOCETHTOOL
+#define SIOCETHTOOL     0x8946
+#endif
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
+static int parse_wolopts(char *optstr, int *data);
+static char *unparse_wolopts(int wolopts);
+static int parse_sopass(char *src, unsigned char *dest);
+static int do_gdrv(int fd, struct ifreq *ifr);
+static int do_gset(int fd, struct ifreq *ifr);
+static int do_sset(int fd, struct ifreq *ifr);
+static int do_gregs(int fd, struct ifreq *ifr);
+static int do_nway_rst(int fd, struct ifreq *ifr);
+static int do_geeprom(int fd, struct ifreq *ifr);
+static int do_seeprom(int fd, struct ifreq *ifr);
+static int do_test(int fd, struct ifreq *ifr);
+static int do_phys_id(int fd, struct ifreq *ifr);
+static int do_gpause(int fd, struct ifreq *ifr);
+static int do_spause(int fd, struct ifreq *ifr);
+static int do_gring(int fd, struct ifreq *ifr);
+static int do_sring(int fd, struct ifreq *ifr);
+static int do_gcoalesce(int fd, struct ifreq *ifr);
+static int do_scoalesce(int fd, struct ifreq *ifr);
+static int do_goffload(int fd, struct ifreq *ifr);
+static int do_soffload(int fd, struct ifreq *ifr);
+static int do_gstats(int fd, struct ifreq *ifr);
+
+/* Syntax:
+ *
+ *	ethtool DEVNAME
+ *	ethtool -a DEVNAME
+ *	ethtool -A DEVNAME \
+ *		[ autoneg on|off ] \
+ *		[ rx on|off ] \
+ *		[ tx on|off ]
+ *	ethtool -c DEVNAME
+ *	ethtool -C DEVNAME \
+ *		[adaptive-rx on|off] \
+ *		[adaptive-tx on|off] \
+ *		[rx-usecs N] \
+ *		[rx-frames N] \
+ *		[rx-usecs-irq N] \
+ *		[rx-frames-irq N] \
+ *		[tx-usecs N] \
+ *		[tx-frames N] \
+ *		[tx-usecs-irq N] \
+ *		[tx-frames-irq N] \
+ *		[stats-block-usecs N] \
+ *		[pkt-rate-low N] \
+ *		[rx-usecs-low N] \
+ *		[rx-frames-low N] \
+ *		[tx-usecs-low N] \
+ *		[tx-frames-low N] \
+ *		[pkt-rate-high N] \
+ *		[rx-usecs-high N] \
+ *		[rx-frames-high N] \
+ *		[tx-usecs-high N] \
+ *		[tx-frames-high N] \
+ *		[sample-interval N]
+ *	ethtool -g DEVNAME
+ *	ethtool -G DEVNAME \
+ *		[ rx N ] \
+ *		[ rx-mini N ] \
+ *		[ rx-jumbo N ] \
+ *		[ tx N ]
+ *	ethtool -i DEVNAME
+ *	ethtool -d DEVNAME [ raw on|off ]
+ *	ethtool -e DEVNAME \
+ *		[ raw on|off ] \
+ *		[ offset N ] \
+ *		[ len N ]
+ *	ethtool -E DEVNAME \
+ *		[ magic N ] \
+ *		[ offset N ] \
+ *		[ value N ] \
+ *	ethtool -k DEVNAME
+ *	ethtool -K DEVNAME \
+ *		[ rx on|off ] \
+ *		[ tx on|off ] \
+ *		[ sg on|off ] \
+ *		[ tso on|off ]
+ *	ethtool -r DEVNAME
+ *	ethtool -p DEVNAME [ %d ]
+ *	ethtool -t DEVNAME [ online|offline ]
+ *	ethtool -s DEVNAME [ speed 10|100|1000 ] \
+ *		[ duplex half|full ] \
+ *		[ port tp|aui|bnc|mii|fibre ] \
+ *		[ autoneg on|off ] \
+ *		[ phyad %d ] \
+ *		[ xcvr internal|external ] \
+ *		[ wol p|u|m|b|a|g|s|d... ] \
+ *		[ sopass %x:%x:%x:%x:%x:%x ] \
+ *		[ msglvl %d ]
+ *	ethtool -S DEVNAME
+ */
+
+static void show_usage(int badarg)
+{
+	fprintf(stderr, PACKAGE " version " VERSION "\n");
+	fprintf(stderr,
+		"Usage:\n"
+		"	ethtool DEVNAME\n"
+		"	ethtool -a DEVNAME\n"
+		"	ethtool -A DEVNAME \\\n"
+		"		[ autoneg on|off ] \\\n"
+		"		[ rx on|off ] \\\n"
+		"		[ tx on|off ]\n"
+		"	ethtool -c DEVNAME\n"
+		"	ethtool -C DEVNAME \\\n"
+		"		[adaptive-rx on|off] \\\n"
+		"		[adaptive-tx on|off] \\\n"
+		"		[rx-usecs N] \\\n"
+		"		[rx-frames N] \\\n"
+		"		[rx-usecs-irq N] \\\n"
+		"		[rx-frames-irq N] \\\n"
+		"		[tx-usecs N] \\\n"
+		"		[tx-frames N] \\\n"
+		"		[tx-usecs-irq N] \\\n"
+		"		[tx-frames-irq N] \\\n"
+		"		[stats-block-usecs N] \\\n"
+		"		[pkt-rate-low N] \\\n"
+		"		[rx-usecs-low N] \\\n"
+		"		[rx-frames-low N] \\\n"
+		"		[tx-usecs-low N] \\\n"
+		"		[tx-frames-low N] \\\n"
+		"		[pkt-rate-high N] \\\n"
+		"		[rx-usecs-high N] \\\n"
+		"		[rx-frames-high N] \\\n"
+		"		[tx-usecs-high N] \\\n"
+		"		[tx-frames-high N] \\\n"
+		"		[sample-interval N]\n"
+		"	ethtool -g DEVNAME\n"
+		"	ethtool -G DEVNAME \\\n"
+		"		[ rx N ] \\\n"
+		"		[ rx-mini N ] \\\n"
+		"		[ rx-jumbo N ] \\\n"
+		"		[ tx N ]\n"
+		"	ethtool -i DEVNAME\n"
+		"	ethtool -d DEVNAME [ raw on|off ]\n"
+		"	ethtool -e DEVNAME \\\n"
+		"		[ raw on|off ] \\\n"
+		"		[ offset N ] \\\n"
+		"		[ length N ]\n"
+ 		"	ethtool -E DEVNAME \\\n"
+		"		[ magic N ] \\\n"
+		"		[ offset N ] \\\n"
+		"		[ value N ]\n"
+		"	ethtool -k DEVNAME\n"
+		"	ethtool -K DEVNAME \\\n"
+		"		[ rx on|off ] \\\n"
+		"		[ tx on|off ] \\\n"
+		"		[ sg on|off ] \\\n"
+		"		[ tso on|off ]\n"
+		"	ethtool -r DEVNAME\n"
+		"	ethtool -p DEVNAME [ %%d ]\n"
+		"	ethtool -t DEVNAME [online|(offline)]\n"
+		"	ethtool -s DEVNAME \\\n"
+		"		[ speed 10|100|1000 ] \\\n"
+		"		[ duplex half|full ]	\\\n"
+		"		[ port tp|aui|bnc|mii|fibre ] \\\n"
+		"		[ autoneg on|off ] \\\n"
+		"		[ phyad %%d ] \\\n"
+		"		[ xcvr internal|external ] \\\n"
+		"		[ wol p|u|m|b|a|g|s|d... ] \\\n"
+		"		[ sopass %%x:%%x:%%x:%%x:%%x:%%x ] \\\n"
+		"		[ msglvl %%d ] \n"
+		"	ethtool -S DEVNAME\n"
+	);
+	exit(badarg);
+}
+
+static char *devname = NULL;
+static enum {
+	MODE_GSET=0,
+	MODE_SSET,
+	MODE_GDRV,
+	MODE_GREGS,
+	MODE_NWAY_RST,
+	MODE_GEEPROM,
+	MODE_SEEPROM,
+	MODE_TEST,
+	MODE_PHYS_ID,
+	MODE_GPAUSE,
+	MODE_SPAUSE,
+	MODE_GCOALESCE,
+	MODE_SCOALESCE,
+	MODE_GRING,
+	MODE_SRING,
+	MODE_GOFFLOAD,
+	MODE_SOFFLOAD,
+	MODE_GSTATS,
+} mode = MODE_GSET;
+
+static int goffload_changed = 0;
+static int off_csum_rx_wanted = -1;
+static int off_csum_tx_wanted = -1;
+static int off_sg_wanted = -1;
+static int off_tso_wanted = -1;
+
+static struct ethtool_pauseparam epause;
+static int gpause_changed = 0;
+static int pause_autoneg_wanted = -1;
+static int pause_rx_wanted = -1;
+static int pause_tx_wanted = -1;
+
+static struct ethtool_ringparam ering;
+static int gring_changed = 0;
+static int ring_rx_wanted = -1;
+static int ring_rx_mini_wanted = -1;
+static int ring_rx_jumbo_wanted = -1;
+static int ring_tx_wanted = -1;
+
+static struct ethtool_coalesce ecoal;
+static int gcoalesce_changed = 0;
+static int coal_stats_wanted = -1;
+static int coal_adaptive_rx_wanted = -1;
+static int coal_adaptive_tx_wanted = -1;
+static int coal_sample_rate_wanted = -1;
+static int coal_pkt_rate_low_wanted = -1;
+static int coal_pkt_rate_high_wanted = -1;
+static int coal_rx_usec_wanted = -1;
+static int coal_rx_frames_wanted = -1;
+static int coal_rx_usec_irq_wanted = -1;
+static int coal_rx_frames_irq_wanted = -1;
+static int coal_tx_usec_wanted = -1;
+static int coal_tx_frames_wanted = -1;
+static int coal_tx_usec_irq_wanted = -1;
+static int coal_tx_frames_irq_wanted = -1;
+static int coal_rx_usec_low_wanted = -1;
+static int coal_rx_frames_low_wanted = -1;
+static int coal_tx_usec_low_wanted = -1;
+static int coal_tx_frames_low_wanted = -1;
+static int coal_rx_usec_high_wanted = -1;
+static int coal_rx_frames_high_wanted = -1;
+static int coal_tx_usec_high_wanted = -1;
+static int coal_tx_frames_high_wanted = -1;
+
+static int speed_wanted = -1;
+static int duplex_wanted = -1;
+static int port_wanted = -1;
+static int autoneg_wanted = -1;
+static int phyad_wanted = -1;
+static int xcvr_wanted = -1;
+static int advertising_wanted = -1;
+static int gset_changed = 0; /* did anything in GSET change? */
+static u32  wol_wanted = 0;
+static int wol_change = 0;
+static u8 sopass_wanted[SOPASS_MAX];
+static int sopass_change = 0;
+static int gwol_changed = 0; /* did anything in GWOL change? */
+static int msglvl_wanted = -1;
+static int phys_id_time = 0;
+static int gregs_changed = 0;
+static int gregs_dump_raw = 0;
+static int geeprom_changed = 0;
+static int geeprom_dump_raw = 0;
+static int geeprom_offset = 0;
+static int geeprom_length = -1;
+static int seeprom_changed = 0;
+static int seeprom_magic = 0;
+static int seeprom_offset = -1;
+static int seeprom_value = 0;
+static enum {
+	ONLINE=0,
+	OFFLINE,
+} test_type = OFFLINE;
+
+typedef enum {
+	CMDL_NONE,
+	CMDL_BOOL,
+	CMDL_INT,
+} cmdline_type_t;
+
+struct cmdline_info {
+	const char *name;
+	cmdline_type_t type;
+	void *wanted_val;
+	void *ioctl_val;
+};
+
+static struct cmdline_info cmdline_gregs[] = {
+	{ "raw", CMDL_BOOL, &gregs_dump_raw, NULL },
+};
+
+static struct cmdline_info cmdline_geeprom[] = {
+	{ "offset", CMDL_INT, &geeprom_offset, NULL },
+	{ "length", CMDL_INT, &geeprom_length, NULL },
+	{ "raw", CMDL_BOOL, &geeprom_dump_raw, NULL },
+};
+
+static struct cmdline_info cmdline_seeprom[] = {
+	{ "magic", CMDL_INT, &seeprom_magic, NULL },
+	{ "offset", CMDL_INT, &seeprom_offset, NULL },
+	{ "value", CMDL_INT, &seeprom_value, NULL },
+};
+
+static struct cmdline_info cmdline_offload[] = {
+	{ "rx", CMDL_BOOL, &off_csum_rx_wanted, NULL },
+	{ "tx", CMDL_BOOL, &off_csum_tx_wanted, NULL },
+	{ "sg", CMDL_BOOL, &off_sg_wanted, NULL },
+	{ "tso", CMDL_BOOL, &off_tso_wanted, NULL },
+};
+
+static struct cmdline_info cmdline_pause[] = {
+	{ "autoneg", CMDL_BOOL, &pause_autoneg_wanted, &epause.autoneg },
+	{ "rx", CMDL_BOOL, &pause_rx_wanted, &epause.rx_pause },
+	{ "tx", CMDL_BOOL, &pause_tx_wanted, &epause.tx_pause },
+};
+
+static struct cmdline_info cmdline_ring[] = {
+	{ "rx", CMDL_INT, &ring_rx_wanted, &ering.rx_pending },
+	{ "rx-mini", CMDL_INT, &ring_rx_mini_wanted, &ering.rx_mini_pending },
+	{ "rx-jumbo", CMDL_INT, &ring_rx_jumbo_wanted, &ering.rx_jumbo_pending },
+	{ "tx", CMDL_INT, &ring_tx_wanted, &ering.tx_pending },
+};
+
+static struct cmdline_info cmdline_coalesce[] = {
+	{ "adaptive-rx", CMDL_BOOL, &coal_adaptive_rx_wanted, &ecoal.use_adaptive_rx_coalesce },
+	{ "adaptive-tx", CMDL_BOOL, &coal_adaptive_tx_wanted, &ecoal.use_adaptive_tx_coalesce },
+	{ "sample-interval", CMDL_INT, &coal_sample_rate_wanted, &ecoal.rate_sample_interval },
+	{ "stats-block-usecs", CMDL_INT, &coal_stats_wanted, &ecoal.stats_block_coalesce_usecs },
+	{ "pkt-rate-low", CMDL_INT, &coal_pkt_rate_low_wanted, &ecoal.pkt_rate_low },
+	{ "pkt-rate-high", CMDL_INT, &coal_pkt_rate_high_wanted, &ecoal.pkt_rate_high },
+	{ "rx-usecs", CMDL_INT, &coal_rx_usec_wanted, &ecoal.rx_coalesce_usecs },
+	{ "rx-frames", CMDL_INT, &coal_rx_frames_wanted, &ecoal.rx_max_coalesced_frames },
+	{ "rx-usecs-irq", CMDL_INT, &coal_rx_usec_irq_wanted, &ecoal.rx_coalesce_usecs_irq },
+	{ "rx-frames-irq", CMDL_INT, &coal_rx_frames_irq_wanted, &ecoal.rx_max_coalesced_frames_irq },
+	{ "tx-usecs", CMDL_INT, &coal_tx_usec_wanted, &ecoal.tx_coalesce_usecs },
+	{ "tx-frames", CMDL_INT, &coal_tx_frames_wanted, &ecoal.tx_max_coalesced_frames },
+	{ "tx-usecs-irq", CMDL_INT, &coal_tx_usec_irq_wanted, &ecoal.tx_coalesce_usecs_irq },
+	{ "tx-frames-irq", CMDL_INT, &coal_tx_frames_irq_wanted, &ecoal.tx_max_coalesced_frames_irq },
+	{ "rx-usecs-low", CMDL_INT, &coal_rx_usec_low_wanted, &ecoal.rx_coalesce_usecs_low },
+	{ "rx-frames-low", CMDL_INT, &coal_rx_frames_low_wanted, &ecoal.rx_max_coalesced_frames_low },
+	{ "tx-usecs-low", CMDL_INT, &coal_tx_usec_low_wanted, &ecoal.tx_coalesce_usecs_low },
+	{ "tx-frames-low", CMDL_INT, &coal_tx_frames_low_wanted, &ecoal.tx_max_coalesced_frames_low },
+	{ "rx-usecs-high", CMDL_INT, &coal_rx_usec_high_wanted, &ecoal.rx_coalesce_usecs_high },
+	{ "rx-frames-high", CMDL_INT, &coal_rx_frames_high_wanted, &ecoal.rx_max_coalesced_frames_high },
+	{ "tx-usecs-high", CMDL_INT, &coal_tx_usec_high_wanted, &ecoal.tx_coalesce_usecs_high },
+	{ "tx-frames-high", CMDL_INT, &coal_tx_frames_high_wanted, &ecoal.tx_max_coalesced_frames_high },
+};
+
+static void parse_generic_cmdline(int argc, char **argp,
+				  int first_arg, int *changed,
+				  struct cmdline_info *info,
+				  unsigned int n_info)
+{
+	int i, idx, *p;
+
+	for (i = first_arg; i < argc; i++) {
+		for (idx = 0; idx < n_info; idx++) {
+			if (!strcmp(info[idx].name, argp[i])) {
+				*changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				p = info[idx].wanted_val;
+				if (info[idx].type == CMDL_BOOL) {
+					if (!strcmp(argp[i], "on"))
+						*p = 1;
+					else if (!strcmp(argp[i], "off"))
+						*p = 0;
+					else
+						show_usage(1);
+				} else if (info[idx].type == CMDL_INT) {
+					long v;
+					v = strtol(argp[i], NULL, 0);
+					if (v < 0)
+						show_usage(1);
+					*p = (int) v;
+				} else {
+					show_usage(1);
+				}
+			}
+		}
+	}
+}
+
+static void parse_cmdline(int argc, char **argp)
+{
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		switch (i) {
+		case 1:
+			if (!strcmp(argp[i], "-s"))
+				mode = MODE_SSET;
+			else if (!strcmp(argp[i], "-a"))
+				mode = MODE_GPAUSE;
+			else if (!strcmp(argp[i], "-A"))
+				mode = MODE_SPAUSE;
+			else if (!strcmp(argp[i], "-c"))
+				mode = MODE_GCOALESCE;
+			else if (!strcmp(argp[i], "-C"))
+				mode = MODE_SCOALESCE;
+			else if (!strcmp(argp[i], "-g"))
+				mode = MODE_GRING;
+			else if (!strcmp(argp[i], "-G"))
+				mode = MODE_SRING;
+			else if (!strcmp(argp[i], "-k"))
+				mode = MODE_GOFFLOAD;
+			else if (!strcmp(argp[i], "-K"))
+				mode = MODE_SOFFLOAD;
+			else if (!strcmp(argp[i], "-i"))
+				mode = MODE_GDRV;
+			else if (!strcmp(argp[i], "-d"))
+				mode = MODE_GREGS;
+			else if (!strcmp(argp[i], "-e"))
+				mode = MODE_GEEPROM;
+			else if (!strcmp(argp[i], "-E"))
+				mode = MODE_SEEPROM;
+			else if (!strcmp(argp[i], "-r"))
+				mode = MODE_NWAY_RST;
+			else if (!strcmp(argp[i], "-p"))
+				mode = MODE_PHYS_ID;
+			else if (!strcmp(argp[i], "-t"))
+				mode = MODE_TEST;
+			else if (!strcmp(argp[i], "-S"))
+				mode = MODE_GSTATS;
+			else if (!strcmp(argp[i], "-h"))
+				show_usage(0);
+			else
+				devname = argp[i];
+			break;
+		case 2:
+			if ((mode == MODE_SSET) ||
+			    (mode == MODE_GDRV) ||
+			    (mode == MODE_GREGS)||
+			    (mode == MODE_NWAY_RST) ||
+			    (mode == MODE_TEST) ||
+			    (mode == MODE_GEEPROM) ||
+			    (mode == MODE_SEEPROM) ||
+			    (mode == MODE_GPAUSE) ||
+			    (mode == MODE_SPAUSE) ||
+			    (mode == MODE_GCOALESCE) ||
+			    (mode == MODE_SCOALESCE) ||
+			    (mode == MODE_GRING) ||
+			    (mode == MODE_SRING) ||
+			    (mode == MODE_GOFFLOAD) ||
+			    (mode == MODE_SOFFLOAD) ||
+			    (mode == MODE_GSTATS) ||
+			    (mode == MODE_PHYS_ID)) {
+				devname = argp[i];
+				break;
+			}
+			/* fallthrough */
+		case 3:
+			if (mode == MODE_TEST) {
+				if (!strcmp(argp[i], "online")) {
+					test_type = ONLINE;
+				} else if (!strcmp(argp[i], "offline")) {
+					test_type = OFFLINE;
+				} else {
+					show_usage(1);
+				}
+				break;
+			} else if (mode == MODE_PHYS_ID) {
+				phys_id_time = strtol(argp[i], NULL, 0);
+				if (phys_id_time < 0)
+					show_usage(1);
+				break;
+			}
+			/* fallthrough */
+		default:
+			if (mode == MODE_GREGS) {
+				parse_generic_cmdline(argc, argp, i,
+					&gregs_changed,
+					cmdline_gregs,
+					ARRAY_SIZE(cmdline_gregs));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_GEEPROM) {
+				parse_generic_cmdline(argc, argp, i,
+					&geeprom_changed,
+					cmdline_geeprom,
+					ARRAY_SIZE(cmdline_geeprom));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_SEEPROM) {
+				parse_generic_cmdline(argc, argp, i,
+					&seeprom_changed,
+					cmdline_seeprom,
+					ARRAY_SIZE(cmdline_seeprom));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_SPAUSE) {
+				parse_generic_cmdline(argc, argp, i,
+					&gpause_changed,
+			      		cmdline_pause,
+			      		ARRAY_SIZE(cmdline_pause));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_SRING) {
+				parse_generic_cmdline(argc, argp, i,
+					&gring_changed,
+			      		cmdline_ring,
+			      		ARRAY_SIZE(cmdline_ring));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_SCOALESCE) {
+				parse_generic_cmdline(argc, argp, i,
+					&gcoalesce_changed,
+			      		cmdline_coalesce,
+			      		ARRAY_SIZE(cmdline_coalesce));
+				i = argc;
+				break;
+			}
+			if (mode == MODE_SOFFLOAD) {
+				parse_generic_cmdline(argc, argp, i,
+					&goffload_changed,
+			      		cmdline_offload,
+			      		ARRAY_SIZE(cmdline_offload));
+				i = argc;
+				break;
+			}
+			if (mode != MODE_SSET)
+				show_usage(1);
+			if (!strcmp(argp[i], "speed")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "10"))
+					speed_wanted = SPEED_10;
+				else if (!strcmp(argp[i], "100"))
+					speed_wanted = SPEED_100;
+				else if (!strcmp(argp[i], "1000"))
+					speed_wanted = SPEED_1000;
+				else
+					show_usage(1);
+				break;
+			} else if (!strcmp(argp[i], "duplex")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "half"))
+					duplex_wanted = DUPLEX_HALF;
+				else if (!strcmp(argp[i], "full"))
+					duplex_wanted = DUPLEX_FULL;
+				else
+					show_usage(1);
+				break;
+			} else if (!strcmp(argp[i], "port")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "tp"))
+					port_wanted = PORT_TP;
+				else if (!strcmp(argp[i], "aui"))
+					port_wanted = PORT_AUI;
+				else if (!strcmp(argp[i], "bnc"))
+					port_wanted = PORT_BNC;
+				else if (!strcmp(argp[i], "mii"))
+					port_wanted = PORT_MII;
+				else if (!strcmp(argp[i], "fibre"))
+					port_wanted = PORT_FIBRE;
+				else
+					show_usage(1);
+				break;
+			} else if (!strcmp(argp[i], "autoneg")) {
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "on")) {
+					gset_changed = 1;
+					autoneg_wanted = AUTONEG_ENABLE;
+				} else if (!strcmp(argp[i], "off")) {
+					gset_changed = 1;
+					autoneg_wanted = AUTONEG_DISABLE;
+				} else {
+					show_usage(1);
+				}
+				break;
+			} else if (!strcmp(argp[i], "phyad")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				phyad_wanted = strtol(argp[i], NULL, 0);
+				if (phyad_wanted < 0)
+					show_usage(1);
+				break;
+			} else if (!strcmp(argp[i], "xcvr")) {
+				gset_changed = 1;
+				i += 1;
+				if (i >= argc)
+					show_usage(1);
+				if (!strcmp(argp[i], "internal"))
+					xcvr_wanted = XCVR_INTERNAL;
+				else if (!strcmp(argp[i], "external"))
+					xcvr_wanted = XCVR_EXTERNAL;
+				else
+					show_usage(1);
+				break;
+			} else if (!strcmp(argp[i], "wol")) {
+				gwol_changed = 1;
+				i++;
+				if (i >= argc)
+					show_usage(1);
+				if (parse_wolopts(argp[i], &wol_wanted) < 0)
+					show_usage(1);
+				wol_change = 1;
+				break;
+			} else if (!strcmp(argp[i], "sopass")) {
+				gwol_changed = 1;
+				i++;
+				if (i >= argc)
+					show_usage(1);
+				if (parse_sopass(argp[i], sopass_wanted) < 0)
+					show_usage(1);
+				sopass_change = 1;
+				break;
+			} else if (!strcmp(argp[i], "msglvl")) {
+				i++;
+				if (i >= argc)
+					show_usage(1);
+				msglvl_wanted = strtol(argp[i], NULL, 0);
+				if (msglvl_wanted < 0)
+					show_usage(1);
+				break;
+			}
+			show_usage(1);
+		}
+	}
+
+	if (autoneg_wanted == AUTONEG_ENABLE){
+		if (speed_wanted == SPEED_10 && duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_10baseT_Half;
+		else if (speed_wanted == SPEED_10 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_10baseT_Full;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_100baseT_Half;
+		else if (speed_wanted == SPEED_100 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_100baseT_Full;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_HALF)
+			advertising_wanted = ADVERTISED_1000baseT_Half;
+		else if (speed_wanted == SPEED_1000 &&
+			 duplex_wanted == DUPLEX_FULL)
+			advertising_wanted = ADVERTISED_1000baseT_Full;
+		else
+			/* auto negotiate without forcing */
+			advertising_wanted = ADVERTISED_100baseT_Full |
+				ADVERTISED_100baseT_Half |
+				ADVERTISED_10baseT_Full |
+				ADVERTISED_10baseT_Half | 
+				ADVERTISED_1000baseT_Full |
+				ADVERTISED_1000baseT_Half;
+
+	}
+
+	if (devname == NULL) {
+		show_usage(1);
+	}
+}
+
+static void dump_supported(struct ethtool_cmd *ep)
+{
+	u_int32_t mask = ep->supported;
+	int did1;
+
+	fprintf(stdout, "	Supported ports: [ ");
+	if (mask & SUPPORTED_TP)
+		fprintf(stdout, "TP ");
+	if (mask & SUPPORTED_AUI)
+		fprintf(stdout, "AUI ");
+	if (mask & SUPPORTED_BNC)
+		fprintf(stdout, "BNC ");
+	if (mask & SUPPORTED_MII)
+		fprintf(stdout, "MII ");
+	if (mask & SUPPORTED_FIBRE)
+		fprintf(stdout, "FIBRE ");
+	fprintf(stdout, "]\n");
+
+	fprintf(stdout, "	Supported link modes:   ");
+	did1 = 0;
+	if (mask & SUPPORTED_10baseT_Half) {
+		did1++; fprintf(stdout, "10baseT/Half ");
+	}
+	if (mask & SUPPORTED_10baseT_Full) {
+		did1++; fprintf(stdout, "10baseT/Full ");
+	}
+	if (did1 && (mask & (SUPPORTED_100baseT_Half|SUPPORTED_100baseT_Full))) {
+		fprintf(stdout, "\n");
+		fprintf(stdout, "	                        ");
+	}
+	if (mask & SUPPORTED_100baseT_Half) {
+		did1++; fprintf(stdout, "100baseT/Half ");
+	}
+	if (mask & SUPPORTED_100baseT_Full) {
+		did1++; fprintf(stdout, "100baseT/Full ");
+	}
+	if (did1 && (mask & (SUPPORTED_1000baseT_Half|SUPPORTED_1000baseT_Full))) {
+		fprintf(stdout, "\n");
+		fprintf(stdout, "	                        ");
+	}
+	if (mask & SUPPORTED_1000baseT_Half) {
+		did1++; fprintf(stdout, "1000baseT/Half ");
+	}
+	if (mask & SUPPORTED_1000baseT_Full) {
+		did1++; fprintf(stdout, "1000baseT/Full ");
+	}
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "	Supports auto-negotiation: ");
+	if (mask & SUPPORTED_Autoneg)
+		fprintf(stdout, "Yes\n");
+	else
+		fprintf(stdout, "No\n");
+}
+
+static void dump_advertised(struct ethtool_cmd *ep)
+{
+	u_int32_t mask = ep->advertising;
+	int did1;
+
+	fprintf(stdout, "	Advertised link modes:  ");
+	did1 = 0;
+	if (mask & ADVERTISED_10baseT_Half) {
+		did1++; fprintf(stdout, "10baseT/Half ");
+	}
+	if (mask & ADVERTISED_10baseT_Full) {
+		did1++; fprintf(stdout, "10baseT/Full ");
+	}
+	if (did1 && (mask & (ADVERTISED_100baseT_Half|ADVERTISED_100baseT_Full))) {
+		fprintf(stdout, "\n");
+		fprintf(stdout, "	                        ");
+	}
+	if (mask & ADVERTISED_100baseT_Half) {
+		did1++; fprintf(stdout, "100baseT/Half ");
+	}
+	if (mask & ADVERTISED_100baseT_Full) {
+		did1++; fprintf(stdout, "100baseT/Full ");
+	}
+	if (did1 && (mask & (ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full))) {
+		fprintf(stdout, "\n");
+		fprintf(stdout, "	                        ");
+	}
+	if (mask & ADVERTISED_1000baseT_Half) {
+		did1++; fprintf(stdout, "1000baseT/Half ");
+	}
+	if (mask & ADVERTISED_1000baseT_Full) {
+		did1++; fprintf(stdout, "1000baseT/Full ");
+	}
+	if (did1 == 0)
+		 fprintf(stdout, "Not reported");
+	fprintf(stdout, "\n");
+
+	fprintf(stdout, "	Advertised auto-negotiation: ");
+	if (mask & ADVERTISED_Autoneg)
+		fprintf(stdout, "Yes\n");
+	else
+		fprintf(stdout, "No\n");
+}
+
+static int dump_ecmd(struct ethtool_cmd *ep)
+{
+	dump_supported(ep);
+	dump_advertised(ep);
+
+	fprintf(stdout, "	Speed: ");
+	switch (ep->speed) {
+	case SPEED_10:
+		fprintf(stdout, "10Mb/s\n");
+		break;
+	case SPEED_100:
+		fprintf(stdout, "100Mb/s\n");
+		break;
+	case SPEED_1000:
+		fprintf(stdout, "1000Mb/s\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", ep->speed);
+		break;
+	};
+
+	fprintf(stdout, "	Duplex: ");
+	switch (ep->duplex) {
+	case DUPLEX_HALF:
+		fprintf(stdout, "Half\n");
+		break;
+	case DUPLEX_FULL:
+		fprintf(stdout, "Full\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", ep->duplex);
+		break;
+	};
+
+	fprintf(stdout, "	Port: ");
+	switch (ep->port) {
+	case PORT_TP:
+		fprintf(stdout, "Twisted Pair\n");
+		break;
+	case PORT_AUI:
+		fprintf(stdout, "AUI\n");
+		break;
+	case PORT_BNC:
+		fprintf(stdout, "BNC\n");
+		break;
+	case PORT_MII:
+		fprintf(stdout, "MII\n");
+		break;
+	case PORT_FIBRE:
+		fprintf(stdout, "FIBRE\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", ep->port);
+		break;
+	};
+
+	fprintf(stdout, "	PHYAD: %d\n", ep->phy_address);
+	fprintf(stdout, "	Transceiver: ");
+	switch (ep->transceiver) {
+	case XCVR_INTERNAL:
+		fprintf(stdout, "internal\n");
+		break;
+	case XCVR_EXTERNAL:
+		fprintf(stdout, "external\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown!\n");
+		break;
+	};
+
+	fprintf(stdout, "	Auto-negotiation: %s\n",
+		(ep->autoneg == AUTONEG_DISABLE) ?
+		"off" : "on");
+	return 0;
+}
+
+static int dump_drvinfo(struct ethtool_drvinfo *info)
+{
+	fprintf(stdout,
+		"driver: %s\n"
+		"version: %s\n"
+		"firmware-version: %s\n"
+		"bus-info: %s\n",
+		info->driver,
+		info->version,
+		info->fw_version,
+		info->bus_info);
+
+	return 0;
+}
+
+static int dump_wol(struct ethtool_wolinfo *wol)
+{
+	fprintf(stdout, "	Supports Wake-on: %s\n",
+		unparse_wolopts(wol->supported));
+	fprintf(stdout, "	Wake-on: %s\n",
+		unparse_wolopts(wol->wolopts));
+	if (wol->supported & WAKE_MAGICSECURE) {
+		int i;
+		int delim = 0;
+		fprintf(stdout, "        SecureOn password: ");
+		for (i = 0; i < SOPASS_MAX; i++) {
+			fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]);
+			delim=1;
+		}
+		fprintf(stdout, "\n");
+	}
+
+	return 0;
+}
+
+static int parse_wolopts(char *optstr, int *data)
+{
+	*data = 0;
+	while (*optstr) {
+		switch (*optstr) {
+			case 'p':
+				*data |= WAKE_PHY;
+				break;
+			case 'u':
+				*data |= WAKE_UCAST;
+				break;
+			case 'm':
+				*data |= WAKE_MCAST;
+				break;
+			case 'b':
+				*data |= WAKE_BCAST;
+				break;
+			case 'a':
+				*data |= WAKE_ARP;
+				break;
+			case 'g':
+				*data |= WAKE_MAGIC;
+				break;
+			case 's':
+				*data |= WAKE_MAGICSECURE;
+				break;
+			case 'd':
+				*data = 0;
+				break;
+			default:
+				return -1;
+		}
+		optstr++;
+	}
+	return 0;
+}
+
+static char *unparse_wolopts(int wolopts)
+{
+	static char buf[16];
+	char *p = buf;
+
+	memset(buf, 0, sizeof(buf));
+
+	if (wolopts) {
+		if (wolopts & WAKE_PHY)
+			*p++ = 'p';
+		if (wolopts & WAKE_UCAST)
+			*p++ = 'u';
+		if (wolopts & WAKE_MCAST)
+			*p++ = 'm';
+		if (wolopts & WAKE_BCAST)
+			*p++ = 'b';
+		if (wolopts & WAKE_ARP)
+			*p++ = 'a';
+		if (wolopts & WAKE_MAGIC)
+			*p++ = 'g';
+		if (wolopts & WAKE_MAGICSECURE)
+			*p++ = 's';
+	} else {
+		*p = 'd';
+	}
+
+	return buf;
+}
+
+static int parse_sopass(char *src, unsigned char *dest)
+{
+	int count;
+	int i;
+	int buf[SOPASS_MAX];
+
+	count = sscanf(src, "%2x:%2x:%2x:%2x:%2x:%2x",
+		&buf[0], &buf[1], &buf[2], &buf[3], &buf[4], &buf[5]);
+	if (count != SOPASS_MAX) {
+		return -1;
+	}
+
+	for (i = 0; i < count; i++) {
+		dest[i] = buf[i];
+	}
+	return 0;
+}
+
+static struct {
+	const char *name;
+	int (*func)(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
+
+} driver_list[] = {
+	{ "8139cp", realtek_dump_regs },
+	{ "8139too", realtek_dump_regs },
+	{ "r8169", realtek_dump_regs },
+	{ "de2104x", de2104x_dump_regs },
+	{ "e1000", e1000_dump_regs },
+	{ "natsemi", natsemi_dump_regs },
+	{ "e100", e100_dump_regs },
+	{ "amd8111e", amd8111e_dump_regs },
+	{ "pcnet32", pcnet32_dump_regs },
+	{ "fec_8xx", fec_8xx_dump_regs },
+};
+
+static int dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	int i;
+
+	if (gregs_dump_raw) {
+		fwrite(regs->data, regs->len, 1, stdout);
+		return 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(driver_list); i++)
+		if (!strncmp(driver_list[i].name, info->driver,
+			     ETHTOOL_BUSINFO_LEN))
+			return driver_list[i].func(info, regs);
+
+	fprintf(stdout, "Offset\tValue\n");
+	fprintf(stdout, "--------\t-----\n");
+	for (i = 0; i < regs->len; i++)
+		fprintf(stdout, "%02d\t0x%02x\n", i, regs->data[i]);
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee)
+{
+	int i;
+
+	if (geeprom_dump_raw) {
+		fwrite(ee->data, 1, ee->len, stdout);
+		return 0;
+	}
+
+	if (!strncmp("natsemi", info->driver, ETHTOOL_BUSINFO_LEN)) {
+		return natsemi_dump_eeprom(info, ee);
+	} else if (!strncmp("tg3", info->driver, ETHTOOL_BUSINFO_LEN)) {
+		return tg3_dump_eeprom(info, ee);
+	}
+
+	fprintf(stdout, "Offset\t\tValues\n");
+	fprintf(stdout, "------\t\t------");
+	for (i = 0; i < ee->len; i++) {
+		if(!(i%16)) fprintf(stdout, "\n0x%04x\t\t", i + ee->offset);
+		fprintf(stdout, "%02x ", ee->data[i]);
+	}
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_test(struct ethtool_drvinfo *info, struct ethtool_test *test,
+		      struct ethtool_gstrings *strings)
+{
+	int i, rc;
+
+	rc = test->flags & ETH_TEST_FL_FAILED;
+	fprintf(stdout, "The test result is %s\n", rc ? "FAIL" : "PASS");
+
+	if (info->testinfo_len)
+		fprintf(stdout, "The test extra info:\n");
+
+	for (i = 0; i < info->testinfo_len; i++) {
+		fprintf(stdout, "%s\t %d\n",
+			(char *)(strings->data + i * ETH_GSTRING_LEN),
+			(u32) test->data[i]);
+	}
+
+	fprintf(stdout, "\n");
+	return rc;
+}
+
+static int dump_pause(void)
+{
+	fprintf(stdout,
+		"Autonegotiate:	%s\n"
+		"RX:		%s\n"
+		"TX:		%s\n",
+		epause.autoneg ? "on" : "off",
+		epause.rx_pause ? "on" : "off",
+		epause.tx_pause ? "on" : "off");
+
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_ring(void)
+{
+	fprintf(stdout,
+		"Pre-set maximums:\n"
+		"RX:		%u\n"
+		"RX Mini:	%u\n"
+		"RX Jumbo:	%u\n"
+		"TX:		%u\n",
+		ering.rx_max_pending,
+		ering.rx_mini_max_pending,
+		ering.rx_jumbo_max_pending,
+		ering.tx_max_pending);
+
+	fprintf(stdout,
+		"Current hardware settings:\n"
+		"RX:		%u\n"
+		"RX Mini:	%u\n"
+		"RX Jumbo:	%u\n"
+		"TX:		%u\n",
+		ering.rx_pending,
+		ering.rx_mini_pending,
+		ering.rx_jumbo_pending,
+		ering.tx_pending);
+
+	fprintf(stdout, "\n");
+	return 0;
+}
+
+static int dump_coalesce(void)
+{
+	fprintf(stdout, "Adaptive RX: %s  TX: %s\n",
+		ecoal.use_adaptive_rx_coalesce ? "on" : "off",
+		ecoal.use_adaptive_tx_coalesce ? "on" : "off");
+
+	fprintf(stdout,
+		"stats-block-usecs: %u\n"
+		"sample-interval: %u\n"
+		"pkt-rate-low: %u\n"
+		"pkt-rate-high: %u\n"
+		"\n"
+		"rx-usecs: %u\n"
+		"rx-frames: %u\n"
+		"rx-usecs-irq: %u\n"
+		"rx-frames-irq: %u\n"
+		"\n"
+		"tx-usecs: %u\n"
+		"tx-frames: %u\n"
+		"tx-usecs-irq: %u\n"
+		"tx-frames-irq: %u\n"
+		"\n"
+		"rx-usecs-low: %u\n"
+		"rx-frame-low: %u\n"
+		"tx-usecs-low: %u\n"
+		"tx-frame-low: %u\n"
+		"\n"
+		"rx-usecs-high: %u\n"
+		"rx-frame-high: %u\n"
+		"tx-usecs-high: %u\n"
+		"tx-frame-high: %u\n"
+		"\n",
+		ecoal.stats_block_coalesce_usecs,
+		ecoal.rate_sample_interval,
+		ecoal.pkt_rate_low,
+		ecoal.pkt_rate_high,
+
+		ecoal.rx_coalesce_usecs,
+		ecoal.rx_max_coalesced_frames,
+		ecoal.rx_coalesce_usecs_irq,
+		ecoal.rx_max_coalesced_frames_irq,
+
+		ecoal.tx_coalesce_usecs,
+		ecoal.tx_max_coalesced_frames,
+		ecoal.tx_coalesce_usecs_irq,
+		ecoal.tx_max_coalesced_frames_irq,
+
+		ecoal.rx_coalesce_usecs_low,
+		ecoal.rx_max_coalesced_frames_low,
+		ecoal.tx_coalesce_usecs_low,
+		ecoal.tx_max_coalesced_frames_low,
+
+		ecoal.rx_coalesce_usecs_high,
+		ecoal.rx_max_coalesced_frames_high,
+		ecoal.tx_coalesce_usecs_high,
+		ecoal.tx_max_coalesced_frames_high);
+
+	return 0;
+}
+
+static int dump_offload (int rx, int tx, int sg, int tso)
+{
+	fprintf(stdout,
+		"rx-checksumming: %s\n"
+		"tx-checksumming: %s\n"
+		"scatter-gather: %s\n"
+		"tcp segmentation offload: %s\n",
+		rx ? "on" : "off",
+		tx ? "on" : "off",
+		sg ? "on" : "off",
+		tso ? "on" : "off");
+
+	return 0;
+}
+
+static int doit(void)
+{
+	struct ifreq ifr;
+	int fd;
+
+	/* Setup our control structures. */
+	memset(&ifr, 0, sizeof(ifr));
+	strcpy(ifr.ifr_name, devname);
+
+	/* Open control socket. */
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0) {
+		perror("Cannot get control socket");
+		return 70;
+	}
+
+	/* all of these are expected to populate ifr->ifr_data as needed */
+	if (mode == MODE_GDRV) {
+		return do_gdrv(fd, &ifr);
+	} else if (mode == MODE_GSET) {
+		return do_gset(fd, &ifr);
+	} else if (mode == MODE_SSET) {
+		return do_sset(fd, &ifr);
+	} else if (mode == MODE_GREGS) {
+		return do_gregs(fd, &ifr);
+	} else if (mode == MODE_NWAY_RST) {
+		return do_nway_rst(fd, &ifr);
+	} else if (mode == MODE_GEEPROM) {
+		return do_geeprom(fd, &ifr);
+	} else if (mode == MODE_SEEPROM) {
+		return do_seeprom(fd, &ifr);
+	} else if (mode == MODE_TEST) {
+		return do_test(fd, &ifr);
+	} else if (mode == MODE_PHYS_ID) {
+		return do_phys_id(fd, &ifr);
+	} else if (mode == MODE_GPAUSE) {
+		return do_gpause(fd, &ifr);
+	} else if (mode == MODE_SPAUSE) {
+		return do_spause(fd, &ifr);
+	} else if (mode == MODE_GCOALESCE) {
+		return do_gcoalesce(fd, &ifr);
+	} else if (mode == MODE_SCOALESCE) {
+		return do_scoalesce(fd, &ifr);
+	} else if (mode == MODE_GRING) {
+		return do_gring(fd, &ifr);
+	} else if (mode == MODE_SRING) {
+		return do_sring(fd, &ifr);
+	} else if (mode == MODE_GOFFLOAD) {
+		return do_goffload(fd, &ifr);
+	} else if (mode == MODE_SOFFLOAD) {
+		return do_soffload(fd, &ifr);
+	} else if (mode == MODE_GSTATS) {
+		return do_gstats(fd, &ifr);
+	}
+
+	return 69;
+}
+
+static int do_gdrv(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_drvinfo drvinfo;
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	ifr->ifr_data = (caddr_t)&drvinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 71;
+	}
+	return dump_drvinfo(&drvinfo);
+}
+
+static int do_gpause(int fd, struct ifreq *ifr)
+{
+	int err;
+
+	fprintf(stdout, "Pause parameters for %s:\n", devname);
+
+	epause.cmd = ETHTOOL_GPAUSEPARAM;
+	ifr->ifr_data = (caddr_t)&epause;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		err = dump_pause();
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device pause settings");
+		return 76;
+	}
+
+	return 0;
+}
+
+static void do_generic_set1(struct cmdline_info *info, int *changed_out)
+{
+	int wanted, *v1, *v2;
+
+	v1 = info->wanted_val;
+	wanted = *v1;
+
+	if (wanted < 0)
+		return;
+
+	v2 = info->ioctl_val;
+	if (wanted == *v2) {
+		fprintf(stderr, "%s unmodified, ignoring\n", info->name);
+	} else {
+		*v2 = wanted;
+		*changed_out = 1;
+	}
+}
+
+static void do_generic_set(struct cmdline_info *info,
+			   unsigned int n_info,
+			   int *changed_out)
+{
+	unsigned int i;
+
+	for (i = 0; i < n_info; i++)
+		do_generic_set1(&info[i], changed_out);
+}
+
+static int do_spause(int fd, struct ifreq *ifr)
+{
+	int err, changed = 0;
+
+	epause.cmd = ETHTOOL_GPAUSEPARAM;
+	ifr->ifr_data = (caddr_t)&epause;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot get device pause settings");
+		return 77;
+	}
+
+	do_generic_set(cmdline_pause, ARRAY_SIZE(cmdline_pause), &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no pause parameters changed, aborting\n");
+		return 78;
+	}
+
+	epause.cmd = ETHTOOL_SPAUSEPARAM;
+	ifr->ifr_data = (caddr_t)&epause;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot set device pause parameters");
+		return 79;
+	}
+
+	return 0;
+}
+
+static int do_sring(int fd, struct ifreq *ifr)
+{
+	int err, changed = 0;
+
+	ering.cmd = ETHTOOL_GRINGPARAM;
+	ifr->ifr_data = (caddr_t)&ering;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot get device ring settings");
+		return 76;
+	}
+
+	do_generic_set(cmdline_ring, ARRAY_SIZE(cmdline_ring), &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no ring parameters changed, aborting\n");
+		return 80;
+	}
+
+	ering.cmd = ETHTOOL_SRINGPARAM;
+	ifr->ifr_data = (caddr_t)&ering;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot set device ring parameters");
+		return 81;
+	}
+
+	return 0;
+}
+
+static int do_gring(int fd, struct ifreq *ifr)
+{
+	int err;
+
+	fprintf(stdout, "Ring parameters for %s:\n", devname);
+
+	ering.cmd = ETHTOOL_GRINGPARAM;
+	ifr->ifr_data = (caddr_t)&ering;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		err = dump_ring();
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device ring settings");
+		return 76;
+	}
+
+	return 0;
+}
+
+static int do_gcoalesce(int fd, struct ifreq *ifr)
+{
+	int err;
+
+	fprintf(stdout, "Coalesce parameters for %s:\n", devname);
+
+	ecoal.cmd = ETHTOOL_GCOALESCE;
+	ifr->ifr_data = (caddr_t)&ecoal;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		err = dump_coalesce();
+		if (err)
+			return err;
+	} else {
+		perror("Cannot get device coalesce settings");
+		return 82;
+	}
+
+	return 0;
+}
+
+static int do_scoalesce(int fd, struct ifreq *ifr)
+{
+	int err, changed = 0;
+
+	ecoal.cmd = ETHTOOL_GCOALESCE;
+	ifr->ifr_data = (caddr_t)&ecoal;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot get device coalesce settings");
+		return 76;
+	}
+
+	do_generic_set(cmdline_coalesce, ARRAY_SIZE(cmdline_coalesce),
+		       &changed);
+
+	if (!changed) {
+		fprintf(stderr, "no ring parameters changed, aborting\n");
+		return 80;
+	}
+
+	ecoal.cmd = ETHTOOL_SCOALESCE;
+	ifr->ifr_data = (caddr_t)&ecoal;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err) {
+		perror("Cannot set device ring parameters");
+		return 81;
+	}
+
+	return 0;
+}
+
+static int do_goffload(int fd, struct ifreq *ifr)
+{
+	struct ethtool_value eval;
+	int err, allfail = 1, rx = 0, tx = 0, sg = 0, tso = 0;
+
+	fprintf(stdout, "Offload parameters for %s:\n", devname);
+
+	eval.cmd = ETHTOOL_GRXCSUM;
+	ifr->ifr_data = (caddr_t)&eval;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err)
+		perror("Cannot get device rx csum settings");
+	else {
+		rx = eval.data;
+		allfail = 0;
+	}
+
+	eval.cmd = ETHTOOL_GTXCSUM;
+	ifr->ifr_data = (caddr_t)&eval;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err)
+		perror("Cannot get device tx csum settings");
+	else {
+		tx = eval.data;
+		allfail = 0;
+	}
+
+	eval.cmd = ETHTOOL_GSG;
+	ifr->ifr_data = (caddr_t)&eval;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err)
+		perror("Cannot get device scatter-gather settings");
+	else {
+		sg = eval.data;
+		allfail = 0;
+	}
+
+	eval.cmd = ETHTOOL_GTSO;
+	ifr->ifr_data = (caddr_t)&eval;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err)
+		perror("Cannot get device tcp segmentation offload settings");
+	else {
+		tso = eval.data;
+		allfail = 0;
+	}
+
+	if (allfail) {
+		fprintf(stdout, "no offload info available\n");
+		return 83;
+	}
+
+	return dump_offload(rx, tx, sg, tso);
+}
+
+static int do_soffload(int fd, struct ifreq *ifr)
+{
+	struct ethtool_value eval;
+	int err, changed = 0;
+
+	if (off_csum_rx_wanted >= 0) {
+		changed = 1;
+		eval.cmd = ETHTOOL_SRXCSUM;
+		eval.data = (off_csum_rx_wanted == 1);
+		ifr->ifr_data = (caddr_t)&eval;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err) {
+			perror("Cannot set device rx csum settings");
+			return 84;
+		}
+	}
+
+	if (off_csum_tx_wanted >= 0) {
+		changed = 1;
+		eval.cmd = ETHTOOL_STXCSUM;
+		eval.data = (off_csum_tx_wanted == 1);
+		ifr->ifr_data = (caddr_t)&eval;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err) {
+			perror("Cannot set device tx csum settings");
+			return 85;
+		}
+	}
+
+	if (off_sg_wanted >= 0) {
+		changed = 1;
+		eval.cmd = ETHTOOL_SSG;
+		eval.data = (off_sg_wanted == 1);
+		ifr->ifr_data = (caddr_t)&eval;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err) {
+			perror("Cannot set device scatter-gather settings");
+			return 86;
+		}
+	}
+
+	if (off_tso_wanted >= 0) {
+		changed = 1;
+		eval.cmd = ETHTOOL_STSO;
+		eval.data = (off_tso_wanted == 1);
+		ifr->ifr_data = (caddr_t)&eval;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err) {
+			perror("Cannot set device tcp segmentation offload settings");
+			return 88;
+		}
+	}
+	if (!changed) {
+		fprintf(stdout, "no offload settings changed\n");
+	}
+
+	return 0;
+}
+
+static int do_gset(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_cmd ecmd;
+	struct ethtool_wolinfo wolinfo;
+	struct ethtool_value edata;
+	int allfail = 1;
+
+	fprintf(stdout, "Settings for %s:\n", devname);
+
+	ecmd.cmd = ETHTOOL_GSET;
+	ifr->ifr_data = (caddr_t)&ecmd;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		err = dump_ecmd(&ecmd);
+		if (err)
+			return err;
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get device settings");
+	}
+
+	wolinfo.cmd = ETHTOOL_GWOL;
+	ifr->ifr_data = (caddr_t)&wolinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		err = dump_wol(&wolinfo);
+		if (err)
+			return err;
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get wake-on-lan settings");
+	}
+
+	edata.cmd = ETHTOOL_GMSGLVL;
+	ifr->ifr_data = (caddr_t)&edata;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		fprintf(stdout, "	Current message level: 0x%08x (%d)\n",
+			edata.data, edata.data);
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get message level");
+	}
+
+	edata.cmd = ETHTOOL_GLINK;
+	ifr->ifr_data = (caddr_t)&edata;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err == 0) {
+		fprintf(stdout, "	Link detected: %s\n",
+			edata.data ? "yes":"no");
+		allfail = 0;
+	} else if (errno != EOPNOTSUPP) {
+		perror("Cannot get link status");
+	}
+
+	if (allfail) {
+		fprintf(stdout, "No data available\n");
+		return 75;
+	}
+	return 0;
+}
+
+static int do_sset(int fd, struct ifreq *ifr)
+{
+	int err;
+
+	if (gset_changed) {
+		struct ethtool_cmd ecmd;
+
+		ecmd.cmd = ETHTOOL_GSET;
+		ifr->ifr_data = (caddr_t)&ecmd;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err < 0) {
+			perror("Cannot get current device settings");
+		} else {
+			/* Change everything the user specified. */
+			if (speed_wanted != -1)
+				ecmd.speed = speed_wanted;
+			if (duplex_wanted != -1)
+				ecmd.duplex = duplex_wanted;
+			if (port_wanted != -1)
+				ecmd.port = port_wanted;
+			if (autoneg_wanted != -1)
+				ecmd.autoneg = autoneg_wanted;
+			if (phyad_wanted != -1)
+				ecmd.phy_address = phyad_wanted;
+			if (xcvr_wanted != -1)
+				ecmd.transceiver = xcvr_wanted;
+			if (advertising_wanted != -1)
+				ecmd.advertising = advertising_wanted;
+
+			/* Try to perform the update. */
+			ecmd.cmd = ETHTOOL_SSET;
+			ifr->ifr_data = (caddr_t)&ecmd;
+			err = ioctl(fd, SIOCETHTOOL, ifr);
+			if (err < 0)
+				perror("Cannot set new settings");
+		}
+		if (err < 0) {
+			if (speed_wanted != -1)
+				fprintf(stderr, "  not setting speed\n");
+			if (duplex_wanted != -1)
+				fprintf(stderr, "  not setting duplex\n");
+			if (port_wanted != -1)
+				fprintf(stderr, "  not setting port\n");
+			if (autoneg_wanted != -1)
+				fprintf(stderr, "  not setting autoneg\n");
+			if (phyad_wanted != -1)
+				fprintf(stderr, "  not setting phy_address\n");
+			if (xcvr_wanted != -1)
+				fprintf(stderr, "  not setting transceiver\n");
+		}
+	}
+
+	if (gwol_changed) {
+		struct ethtool_wolinfo wol;
+
+		wol.cmd = ETHTOOL_GWOL;
+		ifr->ifr_data = (caddr_t)&wol;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err < 0) {
+			perror("Cannot get current wake-on-lan settings");
+		} else {
+			/* Change everything the user specified. */
+			if (wol_change) {
+				wol.wolopts = wol_wanted;
+			}
+			if (sopass_change) {
+				int i;
+				for (i = 0; i < SOPASS_MAX; i++) {
+					wol.sopass[i] = sopass_wanted[i];
+				}
+			}
+
+			/* Try to perform the update. */
+			wol.cmd = ETHTOOL_SWOL;
+			ifr->ifr_data = (caddr_t)&wol;
+			err = ioctl(fd, SIOCETHTOOL, ifr);
+			if (err < 0)
+				perror("Cannot set new wake-on-lan settings");
+		}
+		if (err < 0) {
+			if (wol_change)
+				fprintf(stderr, "  not setting wol\n");
+			if (sopass_change)
+				fprintf(stderr, "  not setting sopass\n");
+		}
+	}
+
+	if (msglvl_wanted != -1) {
+		struct ethtool_value edata;
+
+		edata.cmd = ETHTOOL_SMSGLVL;
+		edata.data = msglvl_wanted;
+		ifr->ifr_data = (caddr_t)&edata;;
+		err = ioctl(fd, SIOCETHTOOL, ifr);
+		if (err < 0)
+			perror("Cannot set new msglvl");
+	}
+
+	return 0;
+}
+
+static int do_gregs(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_regs *regs;
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	ifr->ifr_data = (caddr_t)&drvinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 72;
+	}
+
+	regs = calloc(1, sizeof(*regs)+drvinfo.regdump_len);
+	if (!regs) {
+		perror("Cannot allocate memory for register dump");
+		return 73;
+	}
+	regs->cmd = ETHTOOL_GREGS;
+	regs->len = drvinfo.regdump_len;
+	ifr->ifr_data = (caddr_t)regs;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get register dump");
+		free(regs);
+		return 74;
+	}
+	if(dump_regs(&drvinfo, regs) < 0) {
+		perror("Cannot dump registers");
+		free(regs);
+		return 75;
+	}
+	free(regs);
+
+	return 0;
+}
+
+static int do_nway_rst(int fd, struct ifreq *ifr)
+{
+	struct ethtool_value edata;
+	int err;
+
+	edata.cmd = ETHTOOL_NWAY_RST;
+	ifr->ifr_data = (caddr_t)&edata;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0)
+		perror("Cannot restart autonegotiation");
+
+	return err;
+}
+
+static int do_geeprom(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_eeprom *eeprom;
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	ifr->ifr_data = (caddr_t)&drvinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 74;
+	}
+
+	if (geeprom_length <= 0)
+		geeprom_length = drvinfo.eedump_len;
+
+	if (drvinfo.eedump_len < geeprom_offset + geeprom_length)
+		geeprom_length = drvinfo.eedump_len - geeprom_offset;
+
+	eeprom = calloc(1, sizeof(*eeprom)+geeprom_length);
+	if (!eeprom) {
+		perror("Cannot allocate memory for EEPROM data");
+		return 75;
+	}
+	eeprom->cmd = ETHTOOL_GEEPROM;
+	eeprom->len = geeprom_length;
+	eeprom->offset = geeprom_offset;
+	ifr->ifr_data = (caddr_t)eeprom;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get EEPROM data");
+		free(eeprom);
+		return 74;
+	}
+	err = dump_eeprom(&drvinfo, eeprom);
+	free(eeprom);
+
+	return err;
+}
+
+static int do_seeprom(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct {
+		struct ethtool_eeprom eeprom;
+		u8 data;
+	} edata;
+
+	edata.eeprom.cmd = ETHTOOL_SEEPROM;
+	edata.eeprom.len = 1;
+	edata.eeprom.offset = seeprom_offset;
+	edata.eeprom.magic = seeprom_magic;
+	edata.data = seeprom_value;
+	ifr->ifr_data = (caddr_t)&edata.eeprom;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot set EEPROM data");
+		return 87;
+	}
+
+	return err;
+}
+
+static int do_test(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_test *test;
+	struct ethtool_gstrings *strings;
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	ifr->ifr_data = (caddr_t)&drvinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 72;
+	}
+
+	test = calloc(1, sizeof(*test) + drvinfo.testinfo_len * sizeof(u64));
+	if (!test) {
+		perror("Cannot allocate memory for test info");
+		return 73;
+	}
+	memset (test->data, 0, drvinfo.testinfo_len * sizeof(u64));
+	test->cmd = ETHTOOL_TEST;
+	test->len = drvinfo.testinfo_len;
+	if (test_type == OFFLINE)
+		test->flags = ETH_TEST_FL_OFFLINE;
+	else
+		test->flags = 0;
+	ifr->ifr_data = (caddr_t)test;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot test");
+		free (test);
+		return 74;
+	}
+
+	strings = calloc(1, sizeof(*strings) +
+			    drvinfo.testinfo_len * ETH_GSTRING_LEN);
+	if (!strings) {
+		perror("Cannot allocate memory for strings");
+		free(test);
+		return 73;
+	}
+	memset (strings->data, 0, drvinfo.testinfo_len * ETH_GSTRING_LEN);
+	strings->cmd = ETHTOOL_GSTRINGS;
+	strings->string_set = ETH_SS_TEST;
+	strings->len = drvinfo.testinfo_len;
+	ifr->ifr_data = (caddr_t)strings;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get strings");
+		free (test);
+		free (strings);
+		return 74;
+	}
+	err = dump_test(&drvinfo, test, strings);
+	free(test);
+	free(strings);
+
+	return err;
+}
+
+static int do_phys_id(int fd, struct ifreq *ifr)
+{
+	int err;
+	struct ethtool_value edata;
+
+	edata.cmd = ETHTOOL_PHYS_ID;
+	edata.data = phys_id_time;
+	ifr->ifr_data = (caddr_t)&edata;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0)
+		perror("Cannot identify NIC");
+
+	return err;
+}
+
+static int do_gstats(int fd, struct ifreq *ifr)
+{
+	struct ethtool_drvinfo drvinfo;
+	struct ethtool_gstrings *strings;
+	struct ethtool_stats *stats;
+	unsigned int n_stats, sz_str, sz_stats, i;
+	int err;
+
+	drvinfo.cmd = ETHTOOL_GDRVINFO;
+	ifr->ifr_data = (caddr_t)&drvinfo;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get driver information");
+		return 71;
+	}
+
+	n_stats = drvinfo.n_stats;
+	if (n_stats < 1) {
+		fprintf(stderr, "no stats available\n");
+		return 94;
+	}
+
+	sz_str = n_stats * ETH_GSTRING_LEN;
+	sz_stats = n_stats * sizeof(u64);
+
+	strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
+	stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
+	if (!strings || !stats) {
+		fprintf(stderr, "no memory available\n");
+		return 95;
+	}
+
+	strings->cmd = ETHTOOL_GSTRINGS;
+	strings->string_set = ETH_SS_STATS;
+	strings->len = n_stats;
+	ifr->ifr_data = (caddr_t) strings;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get stats strings information");
+		free(strings);
+		free(stats);
+		return 96;
+	}
+
+	stats->cmd = ETHTOOL_GSTATS;
+	stats->n_stats = n_stats;
+	ifr->ifr_data = (caddr_t) stats;
+	err = ioctl(fd, SIOCETHTOOL, ifr);
+	if (err < 0) {
+		perror("Cannot get stats information");
+		free(strings);
+		free(stats);
+		return 97;
+	}
+
+	/* todo - pretty-print the strings per-driver */
+	fprintf(stdout, "NIC statistics:\n");
+	for (i = 0; i < n_stats; i++) {
+		char s[ETH_GSTRING_LEN];
+
+		strncpy(s, &strings->data[i * ETH_GSTRING_LEN],
+			ETH_GSTRING_LEN);
+		fprintf(stdout, "     %s: %llu\n",
+			s, stats->data[i]);
+	}
+	free(strings);
+	free(stats);
+
+	return 0;
+}
+
+int main(int argc, char **argp, char **envp)
+{
+	parse_cmdline(argc, argp);
+	return doit();
+}
diff --git a/ethtool.spec.in b/ethtool.spec.in
new file mode 100644
index 0000000..1705d7f
--- /dev/null
+++ b/ethtool.spec.in
@@ -0,0 +1,42 @@
+Name		: @PACKAGE@
+Version		: @VERSION@
+Release		: 1
+Group		: Utilities
+
+Summary		: A tool for setting ethernet parameters
+
+Copyright	: GPL
+URL		: http://sourceforge.net/projects/gkernel/
+
+Buildroot	: %{_tmppath}/%{name}-%{version}
+Source		: %{name}-%{version}.tar.gz
+
+
+%description
+Ethtool is a small utility to get and set values from your your ethernet 
+controllers.  Not all ethernet drivers support ethtool, but it is getting 
+better.  If your ethernet driver doesn't support it, ask the maintainer to 
+write support - it's not hard!
+
+
+%prep
+%setup -q
+
+
+%build
+CFLAGS="${RPM_OPT_FLAGS}" ./configure --prefix=/usr --mandir=%{_mandir}
+make
+
+
+%install
+make install DESTDIR=${RPM_BUILD_ROOT}
+
+
+%files
+%defattr(-,root,root)
+/usr/sbin/ethtool
+%{_mandir}/man8/ethtool.8*
+%doc AUTHORS COPYING INSTALL NEWS README ChangeLog
+
+
+%changelog
diff --git a/fec_8xx.c b/fec_8xx.c
new file mode 100644
index 0000000..969a14e
--- /dev/null
+++ b/fec_8xx.c
@@ -0,0 +1,81 @@
+/* 
+ * Copyright (C) 2004 Intracom S.A.
+ * Pantelis Antoniou <panto@intracom.gr>
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+
+#include "ethtool-util.h"
+
+struct fec {
+	uint32_t	addr_low;	/* lower 32 bits of station address	*/
+	uint32_t	addr_high;	/* upper 16 bits of station address||0  */
+	uint32_t	hash_table_high;/* upper 32-bits of hash table		*/
+	uint32_t	hash_table_low;	/* lower 32-bits of hash table		*/
+	uint32_t	r_des_start;	/* beginning of Rx descriptor ring	*/
+	uint32_t	x_des_start;	/* beginning of Tx descriptor ring	*/
+	uint32_t	r_buff_size;	/* Rx buffer size			*/
+	uint32_t	res2[9];	/* reserved				*/
+	uint32_t	ecntrl;		/* ethernet control register		*/
+	uint32_t	ievent;		/* interrupt event register		*/
+	uint32_t	imask;		/* interrupt mask register		*/
+	uint32_t	ivec;		/* interrupt level and vector status	*/
+	uint32_t	r_des_active;	/* Rx ring updated flag			*/
+	uint32_t	x_des_active;	/* Tx ring updated flag			*/
+	uint32_t	res3[10];	/* reserved				*/
+	uint32_t	mii_data;	/* MII data register			*/
+	uint32_t	mii_speed;	/* MII speed control register		*/
+	uint32_t	res4[17];	/* reserved				*/
+	uint32_t	r_bound;	/* end of RAM (read-only)		*/
+	uint32_t	r_fstart;	/* Rx FIFO start address		*/
+	uint32_t	res5[6];	/* reserved				*/
+	uint32_t	x_fstart;	/* Tx FIFO start address		*/
+	uint32_t	res6[17];	/* reserved				*/
+	uint32_t	fun_code;	/* fec SDMA function code		*/
+	uint32_t	res7[3];	/* reserved				*/
+	uint32_t	r_cntrl;	/* Rx control register			*/
+	uint32_t	r_hash;		/* Rx hash register			*/
+	uint32_t	res8[14];	/* reserved				*/
+	uint32_t	x_cntrl;	/* Tx control register			*/
+	uint32_t	res9[0x1e];	/* reserved				*/
+};
+
+#define DUMP_REG(f, x)	fprintf(stdout, \
+			"0x%04lx: %-16s 0x%08x\n", \
+				(unsigned long)(offsetof(struct fec, x)), \
+				#x, f->x)
+
+int fec_8xx_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	struct fec *f = (struct fec *)regs->data;
+
+	fprintf(stdout, "Descriptor Registers\n");
+	fprintf(stdout, "---------------------\n");
+
+	DUMP_REG(f, addr_low);
+	DUMP_REG(f, addr_high);
+	DUMP_REG(f, hash_table_high);
+	DUMP_REG(f, hash_table_low);
+	DUMP_REG(f, r_des_start);
+	DUMP_REG(f, x_des_start);
+	DUMP_REG(f, r_buff_size);
+	DUMP_REG(f, ecntrl);
+	DUMP_REG(f, ievent);
+	DUMP_REG(f, imask);
+	DUMP_REG(f, ivec);
+	DUMP_REG(f, r_des_active);
+	DUMP_REG(f, x_des_active);
+	DUMP_REG(f, mii_data);
+	DUMP_REG(f, mii_speed);
+	DUMP_REG(f, r_bound);
+	DUMP_REG(f, r_fstart);
+	DUMP_REG(f, x_fstart);
+	DUMP_REG(f, fun_code);
+	DUMP_REG(f, r_cntrl);
+	DUMP_REG(f, r_hash);
+	DUMP_REG(f, x_cntrl);
+
+	return 0;
+}
diff --git a/natsemi.c b/natsemi.c
new file mode 100644
index 0000000..24a7cb3
--- /dev/null
+++ b/natsemi.c
@@ -0,0 +1,985 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include "ethtool-util.h"
+
+#define PCI_VENDOR_NATSEMI		0x100b
+#define PCI_DEVICE_DP83815		0x0020
+#define NATSEMI_MAGIC			(PCI_VENDOR_NATSEMI | \
+					 (PCI_DEVICE_DP83815<<16))
+
+/* register indices in the ethtool_regs->data */
+#define REG_CR				0
+#define   BIT_CR_TXE			(1<<0)
+#define   BIT_CR_RXE			(1<<2)
+#define   BIT_CR_RST			(1<<8)
+#define REG_CFG				1
+#define   BIT_CFG_BEM			(1<<0)
+#define   BIT_CFG_BROM_DIS		(1<<2)
+#define   BIT_CFG_PHY_DIS		(1<<9)
+#define   BIT_CFG_PHY_RST		(1<<10)
+#define   BIT_CFG_EXT_PHY		(1<<12)
+#define   BIT_CFG_ANEG_EN		(1<<13)
+#define   BIT_CFG_ANEG_100		(1<<14)
+#define   BIT_CFG_ANEG_FDUP		(1<<15)
+#define   BIT_CFG_PINT_ACEN		(1<<17)
+#define   BIT_CFG_PHY_CFG		(0x3f<<18)
+#define   BIT_CFG_ANEG_DN		(1<<27)
+#define   BIT_CFG_POL			(1<<28)
+#define   BIT_CFG_FDUP			(1<<29)
+#define   BIT_CFG_SPEED100		(1<<30)
+#define   BIT_CFG_LNKSTS		(1<<31)
+
+#define REG_MEAR			2
+#define REG_PTSCR			3
+#define   BIT_PTSCR_EEBIST_FAIL		(1<<0)
+#define   BIT_PTSCR_EELOAD_EN		(1<<2)
+#define   BIT_PTSCR_RBIST_RXFFAIL	(1<<3)
+#define   BIT_PTSCR_RBIST_TXFAIL	(1<<4)
+#define   BIT_PTSCR_RBIST_RXFAIL	(1<<5)
+#define REG_ISR				4
+#define REG_IMR				5
+#define   BIT_INTR_RXOK			(1<<0)
+#define   NAME_INTR_RXOK		"Rx Complete"
+#define   BIT_INTR_RXDESC		(1<<1)
+#define   NAME_INTR_RXDESC		"Rx Descriptor"
+#define   BIT_INTR_RXERR		(1<<2)
+#define   NAME_INTR_RXERR		"Rx Packet Error"
+#define   BIT_INTR_RXEARLY		(1<<3)
+#define   NAME_INTR_RXEARLY		"Rx Early Threshold"
+#define   BIT_INTR_RXIDLE		(1<<4)
+#define   NAME_INTR_RXIDLE		"Rx Idle"
+#define   BIT_INTR_RXORN		(1<<5)
+#define   NAME_INTR_RXORN		"Rx Overrun"
+#define   BIT_INTR_TXOK			(1<<6)
+#define   NAME_INTR_TXOK		"Tx Packet OK"
+#define   BIT_INTR_TXDESC		(1<<7)
+#define   NAME_INTR_TXDESC		"Tx Descriptor"
+#define   BIT_INTR_TXERR		(1<<8)
+#define   NAME_INTR_TXERR		"Tx Packet Error"
+#define   BIT_INTR_TXIDLE		(1<<9)
+#define   NAME_INTR_TXIDLE		"Tx Idle"
+#define   BIT_INTR_TXURN		(1<<10)
+#define   NAME_INTR_TXURN		"Tx Underrun"
+#define   BIT_INTR_MIB			(1<<11)
+#define   NAME_INTR_MIB			"MIB Service"
+#define   BIT_INTR_SWI			(1<<12)
+#define   NAME_INTR_SWI			"Software"
+#define   BIT_INTR_PME			(1<<13)
+#define   NAME_INTR_PME			"Power Management Event"
+#define   BIT_INTR_PHY			(1<<14)
+#define   NAME_INTR_PHY			"Phy"
+#define   BIT_INTR_HIBERR		(1<<15)
+#define   NAME_INTR_HIBERR		"High Bits Error"
+#define   BIT_INTR_RXSOVR		(1<<16)
+#define   NAME_INTR_RXSOVR		"Rx Status FIFO Overrun"
+#define   BIT_INTR_RTABT		(1<<20)
+#define   NAME_INTR_RTABT		"Received Target Abort"
+#define   BIT_INTR_RMABT		(1<<20)
+#define   NAME_INTR_RMABT		"Received Master Abort"
+#define   BIT_INTR_SSERR		(1<<20)
+#define   NAME_INTR_SSERR		"Signaled System Error"
+#define   BIT_INTR_DPERR		(1<<20)
+#define   NAME_INTR_DPERR		"Detected Parity Error"
+#define   BIT_INTR_RXRCMP		(1<<20)
+#define   NAME_INTR_RXRCMP		"Rx Reset Complete"
+#define   BIT_INTR_TXRCMP		(1<<20)
+#define   NAME_INTR_TXRCMP		"Tx Reset Complete"
+#define REG_IER				6
+#define   BIT_IER_IE			(1<<0)
+#define REG_TXDP			8
+#define REG_TXCFG			9
+#define   BIT_TXCFG_DRTH		(0x3f<<0)
+#define   BIT_TXCFG_FLTH		(0x3f<<8)
+#define   BIT_TXCFG_MXDMA		(0x7<<20)
+#define   BIT_TXCFG_ATP			(1<<28)
+#define   BIT_TXCFG_MLB			(1<<29)
+#define   BIT_TXCFG_HBI			(1<<30)
+#define   BIT_TXCFG_CSI			(1<<31)
+#define REG_RXDP			12
+#define REG_RXCFG			13
+#define   BIT_RXCFG_DRTH		(0x1f<<1)
+#define   BIT_RXCFG_MXDMA		(0x7<<20)
+#define   BIT_RXCFG_ALP			(1<<27)
+#define   BIT_RXCFG_ATX			(1<<28)
+#define   BIT_RXCFG_ARP			(1<<30)
+#define   BIT_RXCFG_AEP			(1<<31)
+#define REG_CCSR			15
+#define   BIT_CCSR_CLKRUN_EN		(1<<0)
+#define   BIT_CCSR_PMEEN		(1<<8)
+#define   BIT_CCSR_PMESTS		(1<<15)
+#define REG_WCSR			16
+#define   BIT_WCSR_WKPHY		(1<<0)
+#define   BIT_WCSR_WKUCP		(1<<1)
+#define   BIT_WCSR_WKMCP		(1<<2)
+#define   BIT_WCSR_WKBCP		(1<<3)
+#define   BIT_WCSR_WKARP		(1<<4)
+#define   BIT_WCSR_WKPAT0		(1<<5)
+#define   BIT_WCSR_WKPAT1		(1<<6)
+#define   BIT_WCSR_WKPAT2		(1<<7)
+#define   BIT_WCSR_WKPAT3		(1<<8)
+#define   BIT_WCSR_WKMAG		(1<<9)
+#define   BIT_WCSR_MPSOE		(1<<10)
+#define   BIT_WCSR_SOHACK		(1<<20)
+#define   BIT_WCSR_PHYINT		(1<<22)
+#define   BIT_WCSR_UCASTR		(1<<23)
+#define   BIT_WCSR_MCASTR		(1<<24)
+#define   BIT_WCSR_BCASTR		(1<<25)
+#define   BIT_WCSR_ARPR			(1<<26)
+#define   BIT_WCSR_PATM0		(1<<27)
+#define   BIT_WCSR_PATM1		(1<<28)
+#define   BIT_WCSR_PATM2		(1<<29)
+#define   BIT_WCSR_PATM3		(1<<30)
+#define   BIT_WCSR_MPR			(1<<31)
+#define REG_PCR				17
+#define   BIT_PCR_PAUSE_CNT		(0xffff<<0)
+#define   BIT_PCR_PSNEG			(1<<21)
+#define   BIT_PCR_PS_RCVD		(1<<22)
+#define   BIT_PCR_PS_DA			(1<<29)
+#define   BIT_PCR_PSMCAST		(1<<30)
+#define   BIT_PCR_PSEN			(1<<31)
+#define REG_RFCR			18
+#define   BIT_RFCR_UHEN			(1<<20)
+#define   BIT_RFCR_MHEN			(1<<21)
+#define   BIT_RFCR_AARP			(1<<22)
+#define   BIT_RFCR_APAT0		(1<<23)
+#define   BIT_RFCR_APAT1		(1<<24)
+#define   BIT_RFCR_APAT2		(1<<25)
+#define   BIT_RFCR_APAT3		(1<<26)
+#define   BIT_RFCR_APM			(1<<27)
+#define   BIT_RFCR_AAU			(1<<28)
+#define   BIT_RFCR_AAM			(1<<29)
+#define   BIT_RFCR_AAB			(1<<30)
+#define   BIT_RFCR_RFEN			(1<<31)
+#define REG_RFDR			19
+#define REG_BRAR			20
+#define   BIT_BRAR_AUTOINC		(1<<31)
+#define REG_BRDR			21
+#define REG_SRR				22
+#define REG_MIBC			23
+#define   BIT_MIBC_WRN			(1<<0)
+#define   BIT_MIBC_FRZ			(1<<1)
+#define REG_MIB0			24
+#define REG_MIB1			25
+#define REG_MIB2			26
+#define REG_MIB3			27
+#define REG_MIB4			28
+#define REG_MIB5			29
+#define REG_MIB6			30
+#define REG_BMCR			32
+#define   BIT_BMCR_FDUP			(1<<8)
+#define   BIT_BMCR_ANRST		(1<<9)
+#define   BIT_BMCR_ISOL			(1<<10)
+#define   BIT_BMCR_PDOWN		(1<<11)
+#define   BIT_BMCR_ANEN			(1<<12)
+#define   BIT_BMCR_SPEED		(1<<13)
+#define   BIT_BMCR_LOOP			(1<<14)
+#define   BIT_BMCR_RST			(1<<15)
+#define REG_BMSR			33
+#define   BIT_BMSR_JABBER		(1<<1)
+#define   BIT_BMSR_LNK			(1<<2)
+#define   BIT_BMSR_ANCAP		(1<<3)
+#define   BIT_BMSR_RFAULT		(1<<4)
+#define   BIT_BMSR_ANDONE		(1<<5)
+#define   BIT_BMSR_PREAMBLE		(1<<6)
+#define   BIT_BMSR_10HCAP		(1<<11)
+#define   BIT_BMSR_10FCAP		(1<<12)
+#define   BIT_BMSR_100HCAP		(1<<13)
+#define   BIT_BMSR_100FCAP		(1<<14)
+#define   BIT_BMSR_100T4CAP		(1<<15)
+#define REG_PHYIDR1			34
+#define REG_PHYIDR2			35
+#define   BIT_PHYIDR2_OUILSB		(0x3f<<10)
+#define   BIT_PHYIDR2_MODEL		(0x3f<<4)
+#define   BIT_PHYIDR2_REV		(0xf)
+#define REG_ANAR			36
+#define   BIT_ANAR_PROTO		(0x1f<<0)
+#define   BIT_ANAR_10			(1<<5)
+#define   BIT_ANAR_10_FD		(1<<6)
+#define   BIT_ANAR_TX			(1<<7)
+#define   BIT_ANAR_TXFD			(1<<8)
+#define   BIT_ANAR_T4			(1<<9)
+#define   BIT_ANAR_PAUSE		(1<<10)
+#define   BIT_ANAR_RF			(1<<13)
+#define   BIT_ANAR_NP			(1<<15)
+#define REG_ANLPAR			37
+#define   BIT_ANLPAR_PROTO		(0x1f<<0)
+#define   BIT_ANLPAR_10			(1<<5)
+#define   BIT_ANLPAR_10_FD		(1<<6)
+#define   BIT_ANLPAR_TX			(1<<7)
+#define   BIT_ANLPAR_TXFD		(1<<8)
+#define   BIT_ANLPAR_T4			(1<<9)
+#define   BIT_ANLPAR_PAUSE		(1<<10)
+#define   BIT_ANLPAR_RF			(1<<13)
+#define   BIT_ANLPAR_ACK		(1<<14)
+#define   BIT_ANLPAR_NP			(1<<15)
+#define REG_ANER			38
+#define   BIT_ANER_LP_AN_ENABLE		(1<<0)
+#define   BIT_ANER_PAGE_RX		(1<<1)
+#define   BIT_ANER_NP_ABLE		(1<<2)
+#define   BIT_ANER_LP_NP_ABLE		(1<<3)
+#define   BIT_ANER_PDF			(1<<4)
+#define REG_ANNPTR			39
+#define REG_PHYSTS			48
+#define   BIT_PHYSTS_LNK		(1<<0)
+#define   BIT_PHYSTS_SPD10		(1<<1)
+#define   BIT_PHYSTS_FDUP		(1<<2)
+#define   BIT_PHYSTS_LOOP		(1<<3)
+#define   BIT_PHYSTS_ANDONE		(1<<4)
+#define   BIT_PHYSTS_JABBER		(1<<5)
+#define   BIT_PHYSTS_RF			(1<<6)
+#define   BIT_PHYSTS_MINT		(1<<7)
+#define   BIT_PHYSTS_FC			(1<<11)
+#define   BIT_PHYSTS_POL		(1<<12)
+#define   BIT_PHYSTS_RXERR		(1<<13)
+#define REG_MICR			49
+#define   BIT_MICR_INTEN		(1<<1)
+#define REG_MISR			50
+#define   BIT_MISR_MSK_RHF		(1<<9)
+#define   BIT_MISR_MSK_FHF		(1<<10)
+#define   BIT_MISR_MSK_ANC		(1<<11)
+#define   BIT_MISR_MSK_RF		(1<<12)
+#define   BIT_MISR_MSK_JAB		(1<<13)
+#define   BIT_MISR_MSK_LNK		(1<<14)
+#define   BIT_MISR_MINT			(1<<15)
+#define REG_PGSEL			51
+#define REG_FCSCR			52
+#define REG_RECR			53
+#define REG_PCSR			54
+#define   BIT_PCSR_NRZI			(1<<2)
+#define   BIT_PCSR_FORCE_100		(1<<5)
+#define   BIT_PCSR_SDOPT		(1<<8)
+#define   BIT_PCSR_SDFORCE		(1<<9)
+#define   BIT_PCSR_TQM			(1<<10)
+#define   BIT_PCSR_CLK			(1<<11)
+#define   BIT_PCSR_4B5B			(1<<12)
+#define REG_PHYCR			57
+#define   BIT_PHYCR_PHYADDR		(0x1f<<0)
+#define   BIT_PHYCR_PAUSE_STS		(1<<7)
+#define   BIT_PHYCR_STRETCH		(1<<8)
+#define   BIT_PHYCR_BIST		(1<<9)
+#define   BIT_PHYCR_BIST_STAT		(1<<10)
+#define   BIT_PHYCR_PSR15		(1<<11)
+#define REG_TBTSCR			58
+#define   BIT_TBTSCR_JAB		(1<<0)
+#define   BIT_TBTSCR_BEAT		(1<<1)
+#define   BIT_TBTSCR_AUTOPOL		(1<<3)
+#define   BIT_TBTSCR_POL		(1<<4)
+#define   BIT_TBTSCR_FPOL		(1<<5)
+#define   BIT_TBTSCR_FORCE_10		(1<<6)
+#define   BIT_TBTSCR_PULSE		(1<<7)
+#define   BIT_TBTSCR_LOOP		(1<<8)
+#define REG_PMDCSR			64
+#define REG_TSTDAT			65
+#define REG_DSPCFG			66
+#define REG_SDCFG			67
+#define REG_PMATCH0			68
+#define REG_PMATCH1			69
+#define REG_PMATCH2			70
+#define REG_PCOUNT0			71
+#define REG_PCOUNT1			72
+#define REG_SOPASS0			73
+#define REG_SOPASS1			74
+#define REG_SOPASS2			75
+
+static void __print_intr(int d, int intr, const char *name,
+			 const char *s1, const char *s2)
+{
+	if ((d) & intr)
+		fprintf(stdout, "      %s Interrupt: %s\n", name, s1);
+	else if (s2)
+		fprintf(stdout, "      %s Interrupt: %s\n", name, s2);
+}
+
+#define PRINT_INTR(d, i, s1, s2) do { \
+	int intr = BIT_INTR_ ## i; \
+	const char *name = NAME_INTR_ ## i; \
+	__print_intr(d, intr, name, s1, s2); \
+} while (0)
+
+#define PRINT_INTRS(d, s1, s2) do { \
+	PRINT_INTR((d), RXOK, s1, s2); \
+	PRINT_INTR((d), RXDESC, s1, s2); \
+	PRINT_INTR((d), RXERR, s1, s2); \
+	PRINT_INTR((d), RXEARLY, s1, s2); \
+	PRINT_INTR((d), RXIDLE, s1, s2); \
+	PRINT_INTR((d), RXORN, s1, s2); \
+	PRINT_INTR((d), TXOK, s1, s2); \
+	PRINT_INTR((d), TXDESC, s1, s2); \
+	PRINT_INTR((d), TXERR, s1, s2); \
+	PRINT_INTR((d), TXIDLE, s1, s2); \
+	PRINT_INTR((d), TXURN, s1, s2); \
+	PRINT_INTR((d), MIB, s1, s2); \
+	PRINT_INTR((d), SWI, s1, s2); \
+	PRINT_INTR((d), PME, s1, s2); \
+	PRINT_INTR((d), PHY, s1, s2); \
+	PRINT_INTR((d), HIBERR, s1, s2); \
+	PRINT_INTR((d), RXSOVR, s1, s2); \
+	PRINT_INTR((d), RTABT, s1, s2); \
+	PRINT_INTR((d), RMABT, s1, s2); \
+	PRINT_INTR((d), SSERR, s1, s2); \
+	PRINT_INTR((d), DPERR, s1, s2); \
+	PRINT_INTR((d), RXRCMP, s1, s2); \
+	PRINT_INTR((d), TXRCMP, s1, s2); \
+} while (0)
+
+int
+natsemi_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 *data = (u32 *)regs->data;
+	u32 tmp;
+
+	fprintf(stdout, "Mac/BIU Registers\n");
+	fprintf(stdout, "-----------------\n");
+
+	/* command register */
+	fprintf(stdout,
+		"0x00: CR (Command):                      0x%08x\n",
+		data[REG_CR]);
+	fprintf(stdout,
+		"      Transmit %s\n"
+		"      Receive %s\n",
+		data[REG_CR] & BIT_CR_TXE ? "Active" : "Idle",
+		data[REG_CR] & BIT_CR_RXE ? "Active" : "Idle");
+	if (data[REG_CR] & BIT_CR_RST) fprintf(stdout,
+		"      Reset In Progress\n");
+
+	/* configuration register */
+	fprintf(stdout,
+		"0x04: CFG (Configuration):               0x%08x\n",
+		data[REG_CFG]);
+	fprintf(stdout,
+		"      %s Endian\n"
+		"      Boot ROM %s\n"
+		"      Internal Phy %s\n"
+		"      Phy Reset %s\n"
+		"      External Phy %s\n"
+		"      Default Auto-Negotiation %s, %s %s Mb %s Duplex\n"
+		"      Phy Interrupt %sAuto-Cleared\n"
+		"      Phy Configuration = 0x%02x\n"
+		"      Auto-Negotiation %s\n"
+		"      %s Polarity\n"
+		"      %s Duplex\n"
+		"      %d Mb/s\n"
+		"      Link %s\n",
+		data[REG_CFG] & BIT_CFG_BEM ? "Big" : "Little",
+		data[REG_CFG] & BIT_CFG_BROM_DIS ? "Disabled" : "Enabled",
+		data[REG_CFG] & BIT_CFG_PHY_DIS ? "Disabled" : "Enabled",
+		data[REG_CFG] & BIT_CFG_PHY_RST ? "In Progress" : "Idle",
+		data[REG_CFG] & BIT_CFG_EXT_PHY ? "Enabled" : "Disabled",
+		data[REG_CFG] & BIT_CFG_ANEG_EN ? "Enabled" : "Disabled",
+		data[REG_CFG] & BIT_CFG_ANEG_EN ? "Advertise" : "Force",
+		data[REG_CFG] & BIT_CFG_ANEG_100 ?
+			(data[REG_CFG] & BIT_CFG_ANEG_EN ? "10/100" : "100")
+			: "10",
+		data[REG_CFG] & BIT_CFG_ANEG_FDUP ?
+			(data[REG_CFG] & BIT_CFG_ANEG_EN ? "Half/Full" : "Full")
+			: "Half",
+		data[REG_CFG] & BIT_CFG_PINT_ACEN ? "" : "Not ",
+		data[REG_CFG] & BIT_CFG_PHY_CFG >> 18,
+		data[REG_CFG] & BIT_CFG_ANEG_DN ? "Done" : "Not Done",
+		data[REG_CFG] & BIT_CFG_POL ? "Reversed" : "Normal",
+		data[REG_CFG] & BIT_CFG_FDUP ? "Full" : "Half",
+		data[REG_CFG] & BIT_CFG_SPEED100 ? 100 : 10,
+		data[REG_CFG] & BIT_CFG_LNKSTS ? "Up" : "Down");
+
+	/* EEPROM access register */
+	fprintf(stdout,
+		"0x08: MEAR (EEPROM Access):              0x%08x\n",
+		data[REG_MEAR]);
+
+	/* PCI test control register */
+	fprintf(stdout,
+		"0x0c: PTSCR (PCI Test Control):          0x%08x\n",
+		data[REG_PTSCR]);
+	fprintf(stdout,
+		"      EEPROM Self Test %s\n"
+		"      Rx Filter Self Test %s\n"
+		"      Tx FIFO Self Test %s\n"
+		"      Rx FIFO Self Test %s\n",
+		data[REG_PTSCR] & BIT_PTSCR_EEBIST_FAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_RXFFAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_TXFAIL ? "Failed" : "Passed",
+		data[REG_PTSCR] & BIT_PTSCR_RBIST_RXFAIL ? "Failed" : "Passed");
+	if (data[REG_PTSCR] & BIT_PTSCR_EELOAD_EN) fprintf(stdout,
+		"      EEPROM Reload In Progress\n");
+
+	/* Interrupt status register */
+	fprintf(stdout,
+		"0x10: ISR (Interrupt Status):            0x%08x\n",
+		data[REG_ISR]);
+	if (data[REG_ISR])
+		PRINT_INTRS(data[REG_ISR], "Active", (char *)NULL);
+	else
+		fprintf(stdout, "      No Interrupts Active\n");
+
+	/* Interrupt mask register */
+	fprintf(stdout,
+		"0x14: IMR (Interrupt Mask):              0x%08x\n",
+		data[REG_IMR]);
+	PRINT_INTRS(data[REG_IMR], "Enabled", "Masked");
+
+	/* Interrupt enable register */
+	fprintf(stdout,
+		"0x18: IER (Interrupt Enable):            0x%08x\n",
+		data[REG_IER]);
+	fprintf(stdout,
+		"      Interrupts %s\n",
+		data[REG_IER] & BIT_IER_IE ? "Enabled" : "Disabled");
+
+	/* Tx descriptor pointer register */
+	fprintf(stdout,
+		"0x20: TXDP (Tx Descriptor Pointer):      0x%08x\n",
+		data[REG_TXDP]);
+
+	/* Tx configuration register */
+	fprintf(stdout,
+		"0x24: TXCFG (Tx Config):                 0x%08x\n",
+		data[REG_TXCFG]);
+	tmp = (data[REG_TXCFG] & BIT_TXCFG_MXDMA)>>20;
+	fprintf(stdout,
+		"      Drain Threshhold = %d bytes (%d)\n"
+		"      Fill Threshhold = %d bytes (%d)\n"
+		"      Max DMA Burst per Tx = %d bytes\n"
+		"      Automatic Tx Padding %s\n"
+		"      Mac Loopback %s\n"
+		"      Heartbeat Ignore %s\n"
+		"      Carrier Sense Ignore %s\n",
+		(data[REG_TXCFG] & BIT_TXCFG_DRTH) * 32,
+		data[REG_TXCFG] & BIT_TXCFG_DRTH,
+		((data[REG_TXCFG] & BIT_TXCFG_FLTH)>>8) * 32,
+		data[REG_TXCFG] & BIT_TXCFG_FLTH,
+		tmp ? (1<<(tmp-1))*4 : 512,
+		data[REG_TXCFG] & BIT_TXCFG_ATP ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_MLB ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_HBI ? "Enabled" : "Disabled",
+		data[REG_TXCFG] & BIT_TXCFG_CSI ? "Enabled" : "Disabled");
+
+
+	/* Rx descriptor pointer register */
+	fprintf(stdout,
+		"0x30: RXDP (Rx Descriptor Pointer):      0x%08x\n",
+		data[REG_RXDP]);
+
+	/* Rx configuration register */
+	fprintf(stdout,
+		"0x34: RXCFG (Rx Config):                 0x%08x\n",
+		data[REG_RXCFG]);
+	tmp = (data[REG_RXCFG] & BIT_RXCFG_MXDMA)>>20;
+	fprintf(stdout,
+		"      Drain Threshhold = %d bytes (%d)\n"
+		"      Max DMA Burst per Rx = %d bytes\n"
+		"      Long Packets %s\n"
+		"      Tx Packets %s\n"
+		"      Runt Packets %s\n"
+		"      Error Packets %s\n",
+		((data[REG_RXCFG] & BIT_RXCFG_DRTH) >> 1) * 8,
+		(data[REG_RXCFG] & BIT_RXCFG_DRTH) >> 1,
+		tmp ? (1<<(tmp-1))*4 : 512,
+		data[REG_RXCFG] & BIT_RXCFG_ALP ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_ATX ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_ARP ? "Accepted" : "Rejected",
+		data[REG_RXCFG] & BIT_RXCFG_AEP ? "Accepted" : "Rejected");
+
+	/* CLKRUN control/status register */
+	fprintf(stdout,
+		"0x3c: CCSR (CLKRUN Control/Status):      0x%08x\n",
+		data[REG_CCSR]);
+	fprintf(stdout,
+		"      CLKRUNN %s\n"
+		"      Power Management %s\n",
+		data[REG_CCSR] & BIT_CCSR_CLKRUN_EN ? "Enabled" : "Disabled",
+		data[REG_CCSR] & BIT_CCSR_PMEEN ? "Enabled" : "Disabled");
+	if (data[REG_CCSR] & BIT_CCSR_PMESTS) fprintf(stdout,
+		"      Power Management Event Pending\n");
+
+	/* WoL control/status register */
+	fprintf(stdout,
+		"0x40: WCSR (Wake-on-LAN Control/Status): 0x%08x\n",
+		data[REG_WCSR]);
+	if (data[REG_WCSR] & BIT_WCSR_WKPHY) fprintf(stdout,
+		"      Wake on Phy Interrupt Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKUCP) fprintf(stdout,
+		"      Wake on Unicast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKMCP) fprintf(stdout,
+		"      Wake on Multicast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKBCP) fprintf(stdout,
+		"      Wake on Broadcast Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKARP) fprintf(stdout,
+		"      Wake on Arp Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT0) fprintf(stdout,
+		"      Wake on Pattern 0 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT1) fprintf(stdout,
+		"      Wake on Pattern 1 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT2) fprintf(stdout,
+		"      Wake on Pattern 2 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKPAT3) fprintf(stdout,
+		"      Wake on Pattern 3 Match Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_WKMAG) fprintf(stdout,
+		"      Wake on Magic Packet Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_MPSOE) fprintf(stdout,
+		"      Magic Packet SecureOn Enabled\n");
+	if (data[REG_WCSR] & BIT_WCSR_SOHACK) fprintf(stdout,
+		"      SecureOn Hack Detected\n");
+	if (data[REG_WCSR] & BIT_WCSR_PHYINT) fprintf(stdout,
+		"      Phy Interrupt Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_UCASTR) fprintf(stdout,
+		"      Unicast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_MCASTR) fprintf(stdout,
+		"      Multicast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_BCASTR) fprintf(stdout,
+		"      Broadcast Packet Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_ARPR) fprintf(stdout,
+		"      Arp Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM0) fprintf(stdout,
+		"      Pattern 0 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM1) fprintf(stdout,
+		"      Pattern 1 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM2) fprintf(stdout,
+		"      Pattern 2 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_PATM3) fprintf(stdout,
+		"      Pattern 3 Received\n");
+	if (data[REG_WCSR] & BIT_WCSR_MPR) fprintf(stdout,
+		"      Magic Packet Received\n");
+
+	/* Pause control/status register */
+	fprintf(stdout,
+		"0x44: PCR (Pause Control/Status):        0x%08x\n",
+		data[REG_PCR]);
+	fprintf(stdout,
+		"      Pause Counter = %d\n"
+		"      Pause %sNegotiated\n"
+		"      Pause on DA %s\n"
+		"      Pause on Mulitcast %s\n"
+		"      Pause %s\n",
+		data[REG_PCR] & BIT_PCR_PAUSE_CNT,
+		data[REG_PCR] & BIT_PCR_PSNEG ? "" : "Not ",
+		data[REG_PCR] & BIT_PCR_PS_DA ? "Enabled" : "Disabled",
+		data[REG_PCR] & BIT_PCR_PSMCAST ? "Enabled" : "Disabled",
+		data[REG_PCR] & BIT_PCR_PSEN ? "Enabled" : "Disabled");
+	if (data[REG_PCR] & BIT_PCR_PS_RCVD) fprintf(stdout,
+		"      PS_RCVD: Pause Frame Received\n");
+
+	/* Rx Filter Control */
+	fprintf(stdout,
+		"0x48: RFCR (Rx Filter Control):          0x%08x\n",
+		data[REG_RFCR]);
+	fprintf(stdout,
+		"      Unicast Hash %s\n"
+		"      Multicast Hash %s\n"
+		"      Arp %s\n"
+		"      Pattern 0 Match %s\n"
+		"      Pattern 1 Match %s\n"
+		"      Pattern 2 Match %s\n"
+		"      Pattern 3 Match %s\n"
+		"      Perfect Match %s\n"
+		"      All Unicast %s\n"
+		"      All Multicast %s\n"
+		"      All Broadcast %s\n"
+		"      Rx Filter %s\n",
+		data[REG_RFCR] & BIT_RFCR_UHEN ? "Enabled" : "Disabled",
+		data[REG_RFCR] & BIT_RFCR_MHEN ? "Enabled" : "Disabled",
+		data[REG_RFCR] & BIT_RFCR_AARP ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT0 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT1 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT2 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APAT3 ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_APM ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAU ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAM ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_AAB ? "Accepted" : "Rejected",
+		data[REG_RFCR] & BIT_RFCR_RFEN ? "Enabled" : "Disabled");
+
+	/* Rx filter data register */
+	fprintf(stdout,
+		"0x4c: RFDR (Rx Filter Data):             0x%08x\n",
+		data[REG_RFDR]);
+	if (regs->version >= 1) fprintf(stdout,
+		"      PMATCH 1-0 = 0x%08x\n"
+		"      PMATCH 3-2 = 0x%08x\n"
+		"      PMATCH 5-4 = 0x%08x\n"
+		"      PCOUNT 1-0 = 0x%08x\n"
+		"      PCOUNT 3-2 = 0x%08x\n"
+		"      SOPASS 1-0 = 0x%08x\n"
+		"      SOPASS 3-2 = 0x%08x\n"
+		"      SOPASS 5-4 = 0x%08x\n",
+		data[REG_PMATCH0], data[REG_PMATCH1], data[REG_PMATCH2],
+		data[REG_PCOUNT0], data[REG_PCOUNT1],
+		data[REG_SOPASS0], data[REG_SOPASS1], data[REG_SOPASS2]);
+
+
+	/* Boot ROM address register */
+	fprintf(stdout,
+		"0x50: BRAR (Boot ROM Address):           0x%08x\n",
+		data[REG_BRAR]);
+	if (data[REG_BRAR] & BIT_BRAR_AUTOINC) fprintf(stdout,
+		"      Automatically Increment Address\n");
+
+	/* Boot ROM data register */
+	fprintf(stdout,
+		"0x54: BRDR (Boot ROM Data):              0x%08x\n",
+		data[REG_BRDR]);
+
+	/* Silicon revison register */
+	fprintf(stdout,
+		"0x58: SRR (Silicon Revision):            0x%08x\n",
+		data[REG_SRR]);
+
+	/* Management information base control register */
+	fprintf(stdout,
+		"0x5c: MIBC (Mgmt Info Base Control):     0x%08x\n",
+		data[REG_MIBC]);
+	if (data[REG_MIBC] & BIT_MIBC_WRN) fprintf(stdout,
+		"      Counter Overflow Warning\n");
+	if (data[REG_MIBC] & BIT_MIBC_FRZ) fprintf(stdout,
+		"      Counters Frozen\n");
+
+	/* MIB registers */
+	fprintf(stdout,
+		"0x60: MIB[0] (Rx Errored Packets):       0x%04x\n",
+		data[REG_MIB0]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB0]);
+	fprintf(stdout,
+		"0x64: MIB[1] (Rx Frame Sequence Errors): 0x%02x\n",
+		data[REG_MIB1]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB1]);
+	fprintf(stdout,
+		"0x68: MIB[2] (Rx Missed Packets):        0x%02x\n",
+		data[REG_MIB2]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB2]);
+	fprintf(stdout,
+		"0x6c: MIB[3] (Rx Alignment Errors):      0x%02x\n",
+		data[REG_MIB3]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB3]);
+	fprintf(stdout,
+		"0x70: MIB[4] (Rx Symbol Errors):         0x%02x\n",
+		data[REG_MIB4]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB4]);
+	fprintf(stdout,
+		"0x74: MIB[5] (Rx Long Frame Errors):     0x%02x\n",
+		data[REG_MIB5]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB5]);
+	fprintf(stdout,
+		"0x78: MIB[6] (Tx Heartbeat Errors):      0x%02x\n",
+		data[REG_MIB6]);
+	fprintf(stdout, "      Value = %d\n", data[REG_MIB6]);
+
+	fprintf(stdout, "\n");
+	fprintf(stdout, "Internal Phy Registers\n");
+	fprintf(stdout, "----------------------\n");
+
+	/* Basic mode control register */
+	fprintf(stdout,
+		"0x80: BMCR (Basic Mode Control):         0x%04x\n",
+		data[REG_BMCR]);
+	fprintf(stdout,
+		"      %s Duplex\n"
+		"      Port is Powered %s\n"
+		"      Auto-Negotiation %s\n"
+		"      %d Mb/s\n",
+		data[REG_BMCR] & BIT_BMCR_FDUP ? "Full" : "Half",
+		data[REG_BMCR] & BIT_BMCR_PDOWN ? "Down" : "Up",
+		data[REG_BMCR] & BIT_BMCR_ANEN ? "Enabled" : "Disabled",
+		data[REG_BMCR] & BIT_BMCR_SPEED ? 100 : 10);
+	if (data[REG_BMCR] & BIT_BMCR_ANRST) fprintf(stdout,
+		"      Auto-Negotiation Restarting\n");
+	if (data[REG_BMCR] & BIT_BMCR_ISOL) fprintf(stdout,
+		"      Port Isolated\n");
+	if (data[REG_BMCR] & BIT_BMCR_LOOP) fprintf(stdout,
+		"      Loopback Enabled\n");
+	if (data[REG_BMCR] & BIT_BMCR_RST) fprintf(stdout,
+		"      Reset In Progress\n");
+
+	/* Basic mode status register */
+	fprintf(stdout,
+		"0x84: BMSR (Basic Mode Status):          0x%04x\n",
+		data[REG_BMSR]);
+	fprintf(stdout,
+		"      Link %s\n"
+		"      %sCapable of Auto-Negotiation\n"
+		"      Auto-Negotiation %sComplete\n"
+		"      %sCapable of Preamble Suppression\n"
+		"      %sCapable of 10Base-T Half Duplex\n"
+		"      %sCapable of 10Base-T Full Duplex\n"
+		"      %sCapable of 100Base-TX Half Duplex\n"
+		"      %sCapable of 100Base-TX Full Duplex\n"
+		"      %sCapable of 100Base-T4\n",
+		data[REG_BMSR] & BIT_BMSR_LNK ? "Up" : "Down",
+		data[REG_BMSR] & BIT_BMSR_ANCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_ANDONE ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_PREAMBLE ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_10HCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_10FCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100HCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100FCAP ? "" : "Not ",
+		data[REG_BMSR] & BIT_BMSR_100T4CAP ? "" : "Not ");
+	if (data[REG_BMSR] & BIT_BMSR_JABBER) fprintf(stdout,
+		"      Jabber Condition Detected\n");
+	if (data[REG_BMSR] & BIT_BMSR_RFAULT) fprintf(stdout,
+		"      Remote Fault Detected\n");
+
+	/* PHY identification registers */
+	fprintf(stdout,
+		"0x88: PHYIDR1 (PHY ID #1):               0x%04x\n",
+		data[REG_PHYIDR1]);
+	fprintf(stdout,
+		"0x8c: PHYIDR2 (PHY ID #2):               0x%04x\n",
+		data[REG_PHYIDR2]);
+	fprintf(stdout,
+		"      OUI = 0x%06x\n"
+		"      Model = 0x%02x (%d)\n"
+		"      Revision = 0x%01x (%d)\n",
+		(data[REG_PHYIDR1] << 6) | (data[REG_PHYIDR2] >> 10),
+		(data[REG_PHYIDR2] & BIT_PHYIDR2_MODEL) >> 4 & 0x3f,
+		(data[REG_PHYIDR2] & BIT_PHYIDR2_MODEL) >> 4 & 0x3f,
+		data[REG_PHYIDR2] & BIT_PHYIDR2_REV,
+		data[REG_PHYIDR2] & BIT_PHYIDR2_REV);
+
+	/* autonegotiation advertising register */
+	fprintf(stdout,
+		"0x90: ANAR (Autoneg Advertising):        0x%04x\n",
+		data[REG_ANAR]);
+	fprintf(stdout,
+		"      Protocol Selector = 0x%02x (%d)\n",
+		data[REG_ANAR] & BIT_ANAR_PROTO,
+		data[REG_ANAR] & BIT_ANAR_PROTO);
+	if (data[REG_ANAR] & BIT_ANAR_10) fprintf(stdout,
+		"      Advertising 10Base-T Half Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_10_FD) fprintf(stdout,
+		"      Advertising 10Base-T Full Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_TX) fprintf(stdout,
+		"      Advertising 100Base-TX Half Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_TXFD) fprintf(stdout,
+		"      Advertising 100Base-TX Full Duplex\n");
+	if (data[REG_ANAR] & BIT_ANAR_T4) fprintf(stdout,
+		"      Advertising 100Base-T4\n");
+	if (data[REG_ANAR] & BIT_ANAR_PAUSE) fprintf(stdout,
+		"      Advertising Pause\n");
+	if (data[REG_ANAR] & BIT_ANAR_RF) fprintf(stdout,
+		"      Indicating Remote Fault\n");
+	if (data[REG_ANAR] & BIT_ANAR_NP) fprintf(stdout,
+		"      Next Page Desired\n");
+
+	/* Autonegotiation link partner ability register */
+	fprintf(stdout,
+		"0x94: ANLPAR (Autoneg Partner):          0x%04x\n",
+		data[REG_ANLPAR]);
+	fprintf(stdout,
+		"      Protocol Selector = 0x%02x (%d)\n",
+		data[REG_ANLPAR] & BIT_ANLPAR_PROTO,
+		data[REG_ANLPAR] & BIT_ANLPAR_PROTO);
+	if (data[REG_ANLPAR] & BIT_ANLPAR_10) fprintf(stdout,
+		"      Supports 10Base-T Half Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_10_FD) fprintf(stdout,
+		"      Supports 10Base-T Full Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_TX) fprintf(stdout,
+		"      Supports 100Base-TX Half Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_TXFD) fprintf(stdout,
+		"      Supports 100Base-TX Full Duplex\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_T4) fprintf(stdout,
+		"      Supports 100Base-T4\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_PAUSE) fprintf(stdout,
+		"      Supports Pause\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_RF) fprintf(stdout,
+		"      Indicates Remote Fault\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_ACK) fprintf(stdout,
+		"      Indicates Acknowledgement\n");
+	if (data[REG_ANLPAR] & BIT_ANLPAR_NP) fprintf(stdout,
+		"      Next Page Desired\n");
+
+	/* Autonegotiation expansion register */
+	fprintf(stdout,
+		"0x98: ANER (Autoneg Expansion):          0x%04x\n",
+		data[REG_ANER]);
+	fprintf(stdout,
+		"      Link Partner Can %sAuto-Negotiate\n"
+		"      Link Code Word %sReceived\n"
+		"      Next Page %sSupported\n"
+		"      Link Partner Next Page %sSupported\n",
+		data[REG_ANER] & BIT_ANER_LP_AN_ENABLE ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_PAGE_RX ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_NP_ABLE ? "" : "Not ",
+		data[REG_ANER] & BIT_ANER_LP_NP_ABLE ? "" : "Not ");
+	if (data[REG_ANER] & BIT_ANER_PDF) fprintf(stdout,
+		"      Parallel Detection Fault\n");
+
+	/* Autonegotiation next-page tx register */
+	fprintf(stdout,
+		"0x9c: ANNPTR (Autoneg Next Page Tx):     0x%04x\n",
+		data[REG_ANNPTR]);
+
+	/* Phy status register */
+	fprintf(stdout,
+		"0xc0: PHYSTS (Phy Status):               0x%04x\n",
+		data[REG_PHYSTS]);
+	fprintf(stdout,
+		"      Link %s\n"
+		"      %d Mb/s\n"
+		"      %s Duplex\n"
+		"      Auto-Negotiation %sComplete\n"
+		"      %s Polarity\n",
+		data[REG_PHYSTS] & BIT_PHYSTS_LNK ? "Up" : "Down",
+		data[REG_PHYSTS] & BIT_PHYSTS_SPD10 ? 10 : 100,
+		data[REG_PHYSTS] & BIT_PHYSTS_FDUP ? "Full" : "Half",
+		data[REG_PHYSTS] & BIT_PHYSTS_ANDONE ? "" : "Not ",
+		data[REG_PHYSTS] & BIT_PHYSTS_POL ? "Reverse" : "Normal");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_LOOP) fprintf(stdout,
+		"      Loopback Enabled\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_JABBER) fprintf(stdout,
+		"      Jabber Condition Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_RF) fprintf(stdout,
+		"      Remote Fault Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_MINT) fprintf(stdout,
+		"      MII Interrupt Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_FC) fprintf(stdout,
+		"      False Carrier Detected\n");
+	if (data[REG_PHYSTS] & BIT_PHYSTS_RXERR) fprintf(stdout,
+		"      Rx Error Detected\n");
+
+	fprintf(stdout,
+		"0xc4: MICR (MII Interrupt Control):      0x%04x\n",
+		data[REG_MICR]);
+	fprintf(stdout,
+		"      MII Interrupts %s\n",
+		data[REG_MICR] & BIT_MICR_INTEN ? "Enabled" : "Disabled");
+
+	fprintf(stdout,
+		"0xc8: MISR (MII Interrupt Status):       0x%04x\n",
+		data[REG_MISR]);
+	fprintf(stdout,
+		"      Rx Error Counter Half-Full Interrupt %s\n"
+		"      False Carrier Counter Half-Full Interrupt %s\n"
+		"      Auto-Negotiation Complete Interrupt %s\n"
+		"      Remote Fault Interrupt %s\n"
+		"      Jabber Interrupt %s\n"
+		"      Link Change Interrupt %s\n",
+		data[REG_MISR] & BIT_MISR_MSK_RHF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_FHF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_ANC ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_RF ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_JAB ? "Masked" : "Enabled",
+		data[REG_MISR] & BIT_MISR_MSK_LNK ? "Masked" : "Enabled");
+	if (data[REG_MISR] & BIT_MISR_MINT) fprintf(stdout,
+		"      MII Interrupt Pending\n");
+
+	/* Page select register (from section of spec on 'suggested values') */
+	fprintf(stdout,
+		"0xcc: PGSEL (Phy Register Page Select):  0x%04x\n",
+		data[REG_PGSEL]);
+
+	/* counters */
+	fprintf(stdout,
+		"0xd0: FCSCR (False Carrier Counter):     0x%04x\n",
+		data[REG_FCSCR]);
+	fprintf(stdout,
+		"      Value = %d\n", data[REG_FCSCR] & 0xff);
+	fprintf(stdout,
+		"0xd4: RECR (Rx Error Counter):           0x%04x\n",
+		data[REG_RECR]);
+	fprintf(stdout,
+		"      Value = %d\n", data[REG_RECR] & 0xff);
+
+	/* 100 Mbit configuration register */
+	fprintf(stdout,
+		"0xd8: PCSR (100Mb/s PCS Config/Status):  0x%04x\n",
+		data[REG_PCSR]);
+	fprintf(stdout,
+		"      NRZI Bypass %s\n"
+		"      %s Signal Detect Algorithm\n"
+		"      %s Signal Detect Operation\n"
+		"      True Quiet Mode %s\n"
+		"      Rx Clock is %s\n"
+		"      4B/5B Operation %s\n",
+		data[REG_PCSR] & BIT_PCSR_NRZI ? "Enabled" : "Disabled",
+		data[REG_PCSR] & BIT_PCSR_SDOPT ? "Enhanced" : "Reduced",
+		data[REG_PCSR] & BIT_PCSR_SDFORCE ? "Forced" : "Normal",
+		data[REG_PCSR] & BIT_PCSR_TQM ? "Enabled" : "Disabled",
+		data[REG_PCSR] & BIT_PCSR_CLK ?
+			"Free-Running" : "Phase-Adjusted",
+		data[REG_PCSR] & BIT_PCSR_4B5B ? "Bypassed" : "Normal");
+	if (data[REG_PCSR] & BIT_PCSR_FORCE_100) fprintf(stdout,
+		"      Forced 100 Mb/s Good Link\n");
+
+	/* Phy control register */
+	fprintf(stdout,
+		"0xe4: PHYCR (Phy Control):               0x%04x\n",
+		data[REG_PHYCR]);
+	fprintf(stdout,
+		"      Phy Address = 0x%x (%d)\n"
+		"      %sPause Compatible with Link Partner\n"
+		"      LED Stretching %s\n"
+		"      Phy Self Test %s\n"
+		"      Self Test Sequence = PSR%d\n",
+		data[REG_PHYCR] & BIT_PHYCR_PHYADDR,
+		data[REG_PHYCR] & BIT_PHYCR_PHYADDR,
+		data[REG_PHYCR] & BIT_PHYCR_PAUSE_STS ? "" : "Not ",
+		data[REG_PHYCR] & BIT_PHYCR_STRETCH ? "Bypassed" : "Enabled",
+		data[REG_PHYCR] & BIT_PHYCR_BIST ? "In Progress" :
+		  data[REG_PHYCR] & BIT_PHYCR_BIST_STAT ?
+		    "Passed" : "Failed or Not Run",
+		data[REG_PHYCR] & BIT_PHYCR_PSR15 ? 15 : 9);
+
+
+	/* 10 Mbit control and status register */
+	fprintf(stdout,
+		"0xe8: TBTSCR (10Base-T Status/Control):  0x%04x\n",
+		data[REG_TBTSCR]);
+	fprintf(stdout,
+		"      Jabber %s\n"
+		"      Heartbeat %s\n"
+		"      Polarity Auto-Sense/Correct %s\n"
+		"      %s Polarity %s\n"
+		"      Normal Link Pulse %s\n"
+		"      10 Mb/s Loopback %s\n",
+		data[REG_TBTSCR] & BIT_TBTSCR_JAB ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_BEAT ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ?
+			data[REG_TBTSCR]&BIT_TBTSCR_FPOL ? "Reverse":"Normal" :
+			data[REG_TBTSCR]&BIT_TBTSCR_POL ? "Reverse":"Normal",
+		data[REG_TBTSCR] & BIT_TBTSCR_AUTOPOL ? "Forced" : "Detected",
+		data[REG_TBTSCR] & BIT_TBTSCR_PULSE ? "Disabled" : "Enabled",
+		data[REG_TBTSCR] & BIT_TBTSCR_LOOP ? "Enabled" : "Disabled");
+	if (data[REG_TBTSCR] & BIT_TBTSCR_FORCE_10) fprintf(stdout,
+		"      Forced 10 Mb/s Good Link\n");
+
+	/* the spec says to set these */
+	fprintf(stdout, "\n");
+	fprintf(stdout, "'Magic' Phy Registers\n");
+	fprintf(stdout, "---------------------\n");
+	fprintf(stdout,
+		"0xe4: PMDCSR:                            0x%04x\n",
+		data[REG_PMDCSR]);
+	fprintf(stdout,
+		"0xf4: DSPCFG:                            0x%04x\n",
+		data[REG_DSPCFG]);
+	fprintf(stdout,
+		"0xf8: SDCFG:                             0x%04x\n",
+		data[REG_SDCFG]);
+	fprintf(stdout,
+		"0xfc: TSTDAT:                            0x%04x\n",
+		data[REG_TSTDAT]);
+
+	return 0;
+}
+
+int
+natsemi_dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee)
+{
+	int i;
+	u16 *eebuf = (u16 *)ee->data;
+
+	if (ee->magic != NATSEMI_MAGIC) {
+		fprintf(stderr, "Magic number 0x%08x does not match 0x%08x\n",
+			ee->magic, NATSEMI_MAGIC);
+		return -1;
+	}
+
+	fprintf(stdout, "Address\tData\n");
+	fprintf(stdout, "-------\t------\n");
+	for (i = 0; i < ee->len/2; i++) {
+		fprintf(stdout, "0x%02x   \t0x%04x\n", i + ee->offset, eebuf[i]);
+	}
+
+	return 0;
+}
+
diff --git a/pcnet32.c b/pcnet32.c
new file mode 100644
index 0000000..a4641ca
--- /dev/null
+++ b/pcnet32.c
@@ -0,0 +1,222 @@
+/* Copyright 2004 IBM Corporation (jklewis@us.ibm.com) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "ethtool-util.h"
+
+#define BIT0  0x0001
+#define BIT1  0x0002
+#define BIT2  0x0004
+#define BIT3  0x0008
+#define BIT4  0x0010
+#define BIT5  0x0020
+#define BIT6  0x0040
+#define BIT7  0x0080
+#define BIT8  0x0100
+#define BIT9  0x0200
+#define BIT10 0x0400
+#define BIT11 0x0800
+#define BIT12 0x1000
+#define BIT13 0x2000
+#define BIT14 0x4000
+#define BIT15 0x8000
+
+int pcnet32_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	int i, csr;
+	u16 *data = (u16 *) regs->data;
+	int len = regs->len / 2;
+	u16 temp,*ptr;
+
+	printf("Driver:  %s\n",info->driver);
+	printf("Version: %s\n",info->version);
+
+	printf("APROM:  ");
+	for (i=0; i<8; i++)
+		printf(" %04x ", data[i]);
+	printf("\n");
+
+	csr = i;
+	for (; i<100; i++)
+	 {
+		if (((i-csr) & 7) == 0) printf("CSR%02d:  ", i-csr);
+		printf(" %04x ", data[i]);
+		if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+
+	csr = i;
+	for (; i<136; i++)
+	 {
+		if (((i-csr) & 7) == 0) printf("BCR%02d:  ", i-csr);
+		printf(" %04x ", data[i]);
+		if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+
+	csr = i;
+	for (; i<len; i++)
+	 {
+	  if (((i-csr) & 7) == 0) printf("MII%02d:  ", i-csr);
+		printf(" %04x ", data[i]);
+	  if (((i-csr) & 7) == 7) printf("\n");
+	 }
+	if (((i-csr) & 7) != 7) printf("\n");
+	printf("\n");
+
+	ptr=&data[8];            /* start of the CSRs */
+
+	printf("CSR0:   Status and Control         0x%04x\n  ",ptr[0]);
+	temp=ptr[0];
+
+	if(temp & BIT15) printf("ERR ");
+	if(temp & BIT14) printf("BABL ");
+	if(temp & BIT13) printf("CERR ");
+	if(temp & BIT12) printf("MISS ");
+	if(temp & BIT11) printf("MERR ");
+	if(temp & BIT10) printf("RINT ");
+	if(temp & BIT9)  printf("TINT ");
+	if(temp & BIT8)  printf("IDON ");
+	if(temp & BIT7)  printf("INTR ");
+	if(temp & BIT6)  printf("INT ");
+	if(temp & BIT5)  printf("RXON ");
+	if(temp & BIT4)  printf("TXON ");
+	if(temp & BIT3)  printf("TDMD ");
+	if(temp & BIT2)  printf("STOP ");
+	if(temp & BIT1)  printf("STRT ");
+	if(temp & BIT0)  printf("INIT ");
+
+	printf("\n");
+
+	printf("CSR3:   Interrupt Mask             0x%04x\n  ",ptr[3]);
+	temp=ptr[3];
+
+	if(temp & BIT14) printf("BABLM ");
+	if(temp & BIT12) printf("MISSM ");
+	if(temp & BIT11) printf("MERRM ");
+	if(temp & BIT10) printf("RINTM ");
+	if(temp & BIT9)  printf("TINTM ");
+	if(temp & BIT8)  printf("IDONM ");
+	if(temp & BIT6)  printf("DXSUFLO ");
+	if(temp & BIT5)  printf("LAPPEN ");
+	if(temp & BIT4)  printf("DXMT2PD ");
+	if(temp & BIT3)  printf("EMBA ");
+	if(temp & BIT2)  printf("BSWP ");
+
+	printf("\n");
+
+	printf("CSR4:   Test and Features          0x%04x\n  ",ptr[4]);
+	temp=ptr[4];
+
+	if(temp & BIT15) printf("EN124 ");
+	if(temp & BIT14) printf("DMAPLUS ");
+	if(temp & BIT12) printf("TXDPOLL ");
+	if(temp & BIT11) printf("APAD_XMT ");
+	if(temp & BIT10) printf("ASTRP_RCV ");
+	if(temp & BIT9)  printf("MFCO ");
+	if(temp & BIT8)  printf("MFCON ");
+	if(temp & BIT7)  printf("UINTCMD ");
+	if(temp & BIT6)  printf("UINT ");
+	if(temp & BIT5)  printf("RCVCCO ");
+	if(temp & BIT4)  printf("RCVCCOM ");
+	if(temp & BIT3)  printf("TXSTRT ");
+	if(temp & BIT2)  printf("TXSTRTM ");
+	if(temp & BIT1)  printf("JAB ");
+	if(temp & BIT0)  printf("JABM ");
+
+	printf("\n");
+
+	printf("CSR5:   Ext Control and Int 1      0x%04x\n  ",ptr[5]);
+	temp=ptr[5];
+
+	if(temp & BIT15) printf("TOKINTD ");
+	if(temp & BIT14) printf("LTINTEN ");
+	if(temp & BIT11) printf("SINT ");
+	if(temp & BIT10) printf("SINTE ");
+	if(temp & BIT9)  printf("SLPINT ");
+	if(temp & BIT8)  printf("SLPINTE ");
+	if(temp & BIT7)  printf("EXDINT ");
+	if(temp & BIT6)  printf("EXDINTE ");
+	if(temp & BIT5)  printf("MPPLBA ");
+	if(temp & BIT4)  printf("MPINT ");
+	if(temp & BIT3)  printf("MPINTE ");
+	if(temp & BIT2)  printf("MPEN ");
+	if(temp & BIT1)  printf("MPMODE ");
+	if(temp & BIT0)  printf("SPND ");
+
+	printf("\n");
+
+	printf("CSR7:   Ext Control and Int 2      0x%04x\n  ",ptr[7]);
+	temp=ptr[7];
+
+	if(temp & BIT15) printf("FASTSPNDE ");
+	if(temp & BIT14) printf("RXFRTG ");
+	if(temp & BIT13) printf("RDMD ");
+	if(temp & BIT12) printf("RXDPOLL ");
+	if(temp & BIT11) printf("STINT ");
+	if(temp & BIT10) printf("STINTE ");
+	if(temp & BIT9)  printf("MREINT ");
+	if(temp & BIT8)  printf("MREINTE ");
+	if(temp & BIT7)  printf("MAPINT ");
+	if(temp & BIT6)  printf("MAPINTE ");
+	if(temp & BIT5)  printf("MCCINT ");
+	if(temp & BIT4)  printf("MCCINTE ");
+	if(temp & BIT3)  printf("MCCIINT ");
+	if(temp & BIT2)  printf("MCCIINTE ");
+	if(temp & BIT1)  printf("MIIPDTINT ");
+	if(temp & BIT0)  printf("MIIPDTINTE ");
+
+	printf("\n");
+
+	printf("CSR15:  Mode                       0x%04x\n",ptr[15]);
+	printf("CSR40:  Current RX Byte Count      0x%04x\n",ptr[40]);
+	printf("CSR41:  Current RX Status          0x%04x\n",ptr[41]);
+	printf("CSR42:  Current TX Byte Count      0x%04x\n",ptr[42]);
+	printf("CSR43:  Current TX Status          0x%04x\n",ptr[43]);
+	printf("CSR88:  Chip ID Lower              0x%04x\n",ptr[88]);
+
+	printf("CSR89:  Chip ID Upper              0x%04x\n  ",ptr[89]);
+	temp=ptr[89];
+	printf("VER: %04x  PARTIDU: %04x\n",temp >> 12,temp & 0x00000fff);
+
+	printf("CSR112: Missed Frame Count         0x%04x\n",ptr[90]);    /* 90 is 112 */
+	printf("CSR114: RX Collision Count         0x%04x\n",ptr[91]);
+
+	printf("\n");
+
+	ptr=&data[100];        /* point to BCR 0 */
+
+	printf("BCR2:   Misc. Configuration        0x%04x\n  ",ptr[2]);
+	temp=ptr[2];
+
+	if(temp & BIT14) printf("TMAULOOP ");
+	if(temp & BIT12) printf("LEDPE ");
+
+	if(temp & BIT8)  printf("APROMWE ");
+	if(temp & BIT7)  printf("INTLEVEL ");
+
+	if(temp & BIT3)  printf("EADISEL ");
+	if(temp & BIT2)  printf("AWAKE ");
+	if(temp & BIT1)  printf("ASEL ");
+	if(temp & BIT0)  printf("XMAUSEL ");
+
+	printf("\n");
+
+	printf("BCR9:   Full-Duplex Control        0x%04x\n",ptr[9]);
+	printf("BCR18:  Burst and Bus Control      0x%04x\n",ptr[18]);
+
+	printf("BCR19:  EEPROM Control and Status  0x%04x\n  ",ptr[19]);
+	temp=ptr[19];
+	if(temp & BIT15) printf("PVALID ");
+	if(temp & BIT13) printf("EEDET ");
+	printf("\n");
+
+	printf("BCR23:  PCI Subsystem Vendor ID    0x%04x\n",ptr[23]);
+	printf("BCR24:  PCI Subsystem ID           0x%04x\n",ptr[24]);
+	printf("BCR31:  Software Timer             0x%04x\n",ptr[31]);
+	printf("BCR32:  MII Control and Status     0x%04x\n",ptr[32]);
+	printf("BCR35:  PCI Vendor ID              0x%04x\n",ptr[35]);
+
+	return(0);
+}
+
diff --git a/realtek.c b/realtek.c
new file mode 100644
index 0000000..64ab7f8
--- /dev/null
+++ b/realtek.c
@@ -0,0 +1,517 @@
+/* Copyright 2001 Sun Microsystems (thockin@sun.com) */
+#include <stdio.h>
+#include <stdlib.h>
+#include "ethtool-util.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
+	(b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
+
+enum chip_type {
+	RTLNONE,
+	RTL8139,
+	RTL8139_K,
+	RTL8139A,
+	RTL8139A_G,
+	RTL8139B,
+	RTL8130,
+	RTL8139C,
+	RTL8100,
+	RTL8100B_8139D,
+	RTL8139Cp,
+	RTL8101,
+	RTL8169,
+	RTL8169s,
+	RTL8110
+};
+
+enum {
+	chip_type_mask = HW_REVID(1, 1, 1, 1, 1, 1, 1)
+};
+
+static struct chip_info {
+	const char *name;
+	u32 id_mask;
+} rtl_info_tbl[] = {
+	{ "RTL-8139",		HW_REVID(1, 0, 0, 0, 0, 0, 0) },
+	{ "RTL-8139-K",		HW_REVID(1, 1, 0, 0, 0, 0, 0) },
+	{ "RTL-8139A",		HW_REVID(1, 1, 1, 0, 0, 0, 0) },
+	{ "RTL-8139A-G", 	HW_REVID(1, 1, 1, 0, 0, 1, 0) },
+	{ "RTL-8139B",		HW_REVID(1, 1, 1, 1, 0, 0, 0) },
+	{ "RTL-8130",		HW_REVID(1, 1, 1, 1, 1, 0, 0) },
+	{ "RTL-8139C",		HW_REVID(1, 1, 1, 0, 1, 0, 0) },
+	{ "RTL-8100",		HW_REVID(1, 1, 1, 1, 0, 1, 0) },
+	{ "RTL-8100B/8139D",	HW_REVID(1, 1, 1, 0, 1, 0, 1) },
+	{ "RTL-8139C+",		HW_REVID(1, 1, 1, 0, 1, 1, 0) },
+	{ "RTL-8101",		HW_REVID(1, 1, 1, 0, 1, 1, 1) },
+	{ "RTL-8169",		HW_REVID(0, 0, 0, 0, 0, 0, 0) },
+	{ "RTL-8169s",		HW_REVID(0, 0, 0, 0, 1, 0, 0) },
+	{ "RTL-8110",		HW_REVID(0, 0, 1, 0, 0, 0, 0) },
+	{ }
+};
+
+static void
+print_intr_bits(u16 mask)
+{
+	fprintf(stdout,
+		"      %s%s%s%s%s%s%s%s%s%s%s\n",
+		mask & (1 << 15)	? "SERR " : "",
+		mask & (1 << 14)	? "TimeOut " : "",
+		mask & (1 << 8)		? "SWInt " : "",
+		mask & (1 << 7)		? "TxNoBuf " : "",
+		mask & (1 << 6)		? "RxFIFO " : "",
+		mask & (1 << 5)		? "LinkChg " : "",
+		mask & (1 << 4)		? "RxNoBuf " : "",
+		mask & (1 << 3)		? "TxErr " : "",
+		mask & (1 << 2)		? "TxOK " : "",
+		mask & (1 << 1)		? "RxErr " : "",
+		mask & (1 << 0)		? "RxOK " : "");
+}
+
+int
+realtek_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs)
+{
+	u32 *data = (u32 *) regs->data;
+	u8 *data8 = (u8 *) regs->data;
+	u32 v;
+	struct chip_info *ci;
+	unsigned int board_type = RTLNONE, i;
+
+	v = data[0x40 >> 2] & chip_type_mask;
+
+	ci = &rtl_info_tbl[0];
+	while (ci->name) {
+		if (v == ci->id_mask)
+			break;
+		ci++;
+	}
+	if (v != ci->id_mask) {
+		fprintf(stderr, "unknown RealTek chip\n");
+		return 91;
+	}
+	for (i = 0; i < ARRAY_SIZE(rtl_info_tbl); i++) {
+		if (ci == &rtl_info_tbl[i])
+			board_type = i + 1;
+	}
+	if (board_type == RTLNONE)
+		abort();
+
+	fprintf(stdout,
+		"RealTek %s registers:\n"
+		"------------------------------\n",
+		ci->name);
+
+	fprintf(stdout,
+		"0x00: MAC Address                      %02x:%02x:%02x:%02x:%02x:%02x\n",
+		data8[0x00],
+		data8[0x01],
+		data8[0x02],
+		data8[0x03],
+		data8[0x04],
+		data8[0x05]);
+
+	fprintf(stdout,
+		"0x08: Multicast Address Filter     0x%08x 0x%08x\n",
+		data[0x08 >> 2],
+		data[0x0c >> 2]);
+
+	if (board_type == RTL8139Cp ||
+	    board_type == RTL8169 ||
+	    board_type == RTL8169s ||
+	    board_type == RTL8110) {
+	fprintf(stdout,
+		"0x10: Dump Tally Counter Command   0x%08x 0x%08x\n",
+		data[0x10 >> 2],
+		data[0x14 >> 2]);
+
+	fprintf(stdout,
+		"0x20: Tx Normal Priority Ring Addr 0x%08x 0x%08x\n",
+		data[0x20 >> 2],
+		data[0x24 >> 2]);
+
+	fprintf(stdout,
+		"0x28: Tx High Priority Ring Addr   0x%08x 0x%08x\n",
+		data[0x28 >> 2],
+		data[0x2C >> 2]);
+	} else {
+	fprintf(stdout,
+		"0x10: Transmit Status Desc 0                  0x%08x\n"
+		"0x14: Transmit Status Desc 1                  0x%08x\n"
+		"0x18: Transmit Status Desc 2                  0x%08x\n"
+		"0x1C: Transmit Status Desc 3                  0x%08x\n",
+		data[0x10 >> 2],
+		data[0x14 >> 2],
+		data[0x18 >> 2],
+		data[0x1C >> 2]);
+	fprintf(stdout,
+		"0x20: Transmit Start Addr  0                  0x%08x\n"
+		"0x24: Transmit Start Addr  1                  0x%08x\n"
+		"0x28: Transmit Start Addr  2                  0x%08x\n"
+		"0x2C: Transmit Start Addr  3                  0x%08x\n",
+		data[0x20 >> 2],
+		data[0x24 >> 2],
+		data[0x28 >> 2],
+		data[0x2C >> 2]);
+	}
+
+	if (board_type == RTL8169 ||
+	    board_type == RTL8169s ||
+	    board_type == RTL8110) {
+	fprintf(stdout,
+		"0x30: Flash memory read/write                 0x%08x\n",
+		data[0x30 >> 2]);
+	} else {
+	fprintf(stdout,
+		"0x30: Rx buffer addr (C mode)                 0x%08x\n",
+		data[0x30 >> 2]);
+	}
+
+	v = data8[0x36];
+	fprintf(stdout,
+		"0x34: Early Rx Byte Count                       %8u\n"
+		"0x36: Early Rx Status                               0x%02x\n",
+		data[0x34 >> 2] & 0xffff,
+		v);
+
+	if (v & 0xf) {
+	fprintf(stdout,
+		"      %s%s%s%s\n",
+		v & (1 << 3) ? "ERxGood " : "",
+		v & (1 << 2) ? "ERxBad " : "",
+		v & (1 << 1) ? "ERxOverWrite " : "",
+		v & (1 << 0) ? "ERxOK " : "");
+	}
+
+	v = data8[0x37];
+	fprintf(stdout,
+		"0x37: Command                                       0x%02x\n"
+		"      Rx %s, Tx %s%s\n",
+		data8[0x37],
+		v & (1 << 3) ? "on" : "off",
+		v & (1 << 2) ? "on" : "off",
+		v & (1 << 4) ? ", RESET" : "");
+
+	if (board_type != RTL8169 &&
+	    board_type != RTL8169s &&
+	    board_type != RTL8110) {
+	fprintf(stdout,
+		"0x38: Current Address of Packet Read (C mode)     0x%04x\n"
+		"0x3A: Current Rx buffer address (C mode)          0x%04x\n",
+		data[0x38 >> 2] & 0xffff,
+		data[0x38 >> 2] >> 16);
+	}
+
+	fprintf(stdout,
+		"0x3C: Interrupt Mask                              0x%04x\n",
+		data[0x3c >> 2] & 0xffff);
+	print_intr_bits(data[0x3c >> 2] & 0xffff);
+	fprintf(stdout,
+		"0x3E: Interrupt Status                            0x%04x\n",
+		data[0x3c >> 2] >> 16);
+	print_intr_bits(data[0x3c >> 2] >> 16);
+
+	fprintf(stdout,
+		"0x40: Tx Configuration                        0x%08x\n"
+		"0x44: Rx Configuration                        0x%08x\n"
+		"0x48: Timer count                             0x%08x\n"
+		"0x4C: Missed packet counter                     0x%06x\n",
+		data[0x40 >> 2],
+		data[0x44 >> 2],
+		data[0x48 >> 2],
+		data[0x4C >> 2] & 0xffffff);
+
+	fprintf(stdout,
+		"0x50: EEPROM Command                                0x%02x\n"
+		"0x51: Config 0                                      0x%02x\n"
+		"0x52: Config 1                                      0x%02x\n",
+		data8[0x50],
+		data8[0x51],
+		data8[0x52]);
+
+	if (board_type == RTL8169 ||
+	    board_type == RTL8169s ||
+	    board_type == RTL8110) {
+	fprintf(stdout,
+		"0x53: Config 2                                      0x%02x\n"
+		"0x54: Config 3                                      0x%02x\n"
+		"0x55: Config 4                                      0x%02x\n"
+		"0x56: Config 5                                      0x%02x\n",
+		data8[0x53],
+		data8[0x54],
+		data8[0x55],
+		data8[0x56]);
+	fprintf(stdout,
+		"0x58: Timer interrupt                         0x%08x\n",
+		data[0x58 >> 2]);
+	}
+	else {
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x54: Timer interrupt                         0x%08x\n",
+		data[0x54 >> 2]);
+	}
+	fprintf(stdout,
+		"0x58: Media status                                  0x%02x\n",
+		data8[0x58]);
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x59: Config 3                                      0x%02x\n",
+		data8[0x59]);
+	}
+	if (board_type >= RTL8139B) {
+	fprintf(stdout,
+		"0x5A: Config 4                                      0x%02x\n",
+		data8[0x5A]);
+	}
+	}
+
+	fprintf(stdout,
+		"0x5C: Multiple Interrupt Select                   0x%04x\n",
+		data[0x5c >> 2] & 0xffff);
+
+	if (board_type == RTL8169 ||
+	    board_type == RTL8169s ||
+	    board_type == RTL8110) {
+	fprintf(stdout,
+		"0x60: PHY access                              0x%08x\n"
+		"0x64: TBI control and status                  0x%08x\n",
+		data[0x60 >> 2],
+		data[0x64 >> 2]);
+
+	fprintf(stdout,
+		"0x68: TBI Autonegotiation advertisement (ANAR)    0x%04x\n"
+		"0x6A: TBI Link partner ability (LPAR)             0x%04x\n",
+		data[0x68 >> 2] & 0xffff,
+		data[0x68 >> 2] >> 16);
+
+	fprintf(stdout,
+		"0x6C: PHY status                                    0x%02x\n",
+		data8[0x6C]);
+
+	fprintf(stdout,
+		"0x84: PM wakeup frame 0            0x%08x 0x%08x\n"
+		"0x8C: PM wakeup frame 1            0x%08x 0x%08x\n",
+		data[0x84 >> 2],
+		data[0x88 >> 2],
+		data[0x8C >> 2],
+		data[0x90 >> 2]);
+
+	fprintf(stdout,
+		"0x94: PM wakeup frame 2 (low)      0x%08x 0x%08x\n"
+		"0x9C: PM wakeup frame 2 (high)     0x%08x 0x%08x\n",
+		data[0x94 >> 2],
+		data[0x98 >> 2],
+		data[0x9C >> 2],
+		data[0xA0 >> 2]);
+
+	fprintf(stdout,
+		"0xA4: PM wakeup frame 3 (low)      0x%08x 0x%08x\n"
+		"0xAC: PM wakeup frame 3 (high)     0x%08x 0x%08x\n",
+		data[0xA4 >> 2],
+		data[0xA8 >> 2],
+		data[0xAC >> 2],
+		data[0xB0 >> 2]);
+
+	fprintf(stdout,
+		"0xB4: PM wakeup frame 4 (low)      0x%08x 0x%08x\n"
+		"0xBC: PM wakeup frame 4 (high)     0x%08x 0x%08x\n",
+		data[0xB4 >> 2],
+		data[0xB8 >> 2],
+		data[0xBC >> 2],
+		data[0xC0 >> 2]);
+
+	fprintf(stdout,
+		"0xC4: Wakeup frame 0 CRC                          0x%04x\n"
+		"0xC6: Wakeup frame 1 CRC                          0x%04x\n"
+		"0xC8: Wakeup frame 2 CRC                          0x%04x\n"
+		"0xCA: Wakeup frame 3 CRC                          0x%04x\n"
+		"0xCC: Wakeup frame 4 CRC                          0x%04x\n",
+		data[0xC4 >> 2] & 0xffff,
+		data[0xC4 >> 2] >> 16,
+		data[0xC8 >> 2] & 0xffff,
+		data[0xC8 >> 2] >> 16,
+		data[0xCC >> 2] & 0xffff);
+	fprintf(stdout,
+		"0xDA: RX packet maximum size                      0x%04x\n",
+		data[0xD8 >> 2] >> 16);
+	}
+	else {
+	fprintf(stdout,
+		"0x5E: PCI revision id                               0x%02x\n",
+		data8[0x5e]);
+	fprintf(stdout,
+		"0x60: Transmit Status of All Desc (C mode)        0x%04x\n"
+		"0x62: MII Basic Mode Control Register             0x%04x\n",
+		data[0x60 >> 2] & 0xffff,
+		data[0x60 >> 2] >> 16);
+	fprintf(stdout,
+		"0x64: MII Basic Mode Status Register              0x%04x\n"
+		"0x66: MII Autonegotiation Advertising             0x%04x\n",
+		data[0x64 >> 2] & 0xffff,
+		data[0x64 >> 2] >> 16);
+	fprintf(stdout,
+		"0x68: MII Link Partner Ability                    0x%04x\n"
+		"0x6A: MII Expansion                               0x%04x\n",
+		data[0x68 >> 2] & 0xffff,
+		data[0x68 >> 2] >> 16);
+	fprintf(stdout,
+		"0x6C: MII Disconnect counter                      0x%04x\n"
+		"0x6E: MII False carrier sense counter             0x%04x\n",
+		data[0x6C >> 2] & 0xffff,
+		data[0x6C >> 2] >> 16);
+	fprintf(stdout,
+		"0x70: MII Nway test                               0x%04x\n"
+		"0x72: MII RX_ER counter                           0x%04x\n",
+		data[0x70 >> 2] & 0xffff,
+		data[0x70 >> 2] >> 16);
+	fprintf(stdout,
+		"0x74: MII CS configuration                        0x%04x\n",
+		data[0x74 >> 2] & 0xffff);
+	if (board_type >= RTL8139_K) {
+	fprintf(stdout,
+		"0x78: PHY parameter 1                         0x%08x\n"
+		"0x7C: Twister parameter                       0x%08x\n",
+		data[0x78 >> 2],
+		data[0x7C >> 2]);
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x80: PHY parameter 2                               0x%02x\n",
+		data8[0x80]);
+	}
+	}
+	if (board_type == RTL8139Cp) {
+	fprintf(stdout,
+		"0x82: Low addr of a Tx Desc w/ Tx DMA OK          0x%04x\n",
+		data[0x80 >> 2] >> 16);
+	} else if (board_type == RTL8130) {
+	fprintf(stdout,
+		"0x82: MII register                                  0x%02x\n",
+		data8[0x82]);
+	}
+	if (board_type >= RTL8139A) {
+	fprintf(stdout,
+		"0x84: PM CRC for wakeup frame 0                     0x%02x\n"
+		"0x85: PM CRC for wakeup frame 1                     0x%02x\n"
+		"0x86: PM CRC for wakeup frame 2                     0x%02x\n"
+		"0x87: PM CRC for wakeup frame 3                     0x%02x\n"
+		"0x88: PM CRC for wakeup frame 4                     0x%02x\n"
+		"0x89: PM CRC for wakeup frame 5                     0x%02x\n"
+		"0x8A: PM CRC for wakeup frame 6                     0x%02x\n"
+		"0x8B: PM CRC for wakeup frame 7                     0x%02x\n",
+		data8[0x84],
+		data8[0x85],
+		data8[0x86],
+		data8[0x87],
+		data8[0x88],
+		data8[0x89],
+		data8[0x8A],
+		data8[0x8B]);
+	fprintf(stdout,
+		"0x8C: PM wakeup frame 0            0x%08x 0x%08x\n"
+		"0x94: PM wakeup frame 1            0x%08x 0x%08x\n"
+		"0x9C: PM wakeup frame 2            0x%08x 0x%08x\n"
+		"0xA4: PM wakeup frame 3            0x%08x 0x%08x\n"
+		"0xAC: PM wakeup frame 4            0x%08x 0x%08x\n"
+		"0xB4: PM wakeup frame 5            0x%08x 0x%08x\n"
+		"0xBC: PM wakeup frame 6            0x%08x 0x%08x\n"
+		"0xC4: PM wakeup frame 7            0x%08x 0x%08x\n",
+		data[0x8C >> 2],
+		data[0x90 >> 2],
+		data[0x94 >> 2],
+		data[0x98 >> 2],
+		data[0x9C >> 2],
+		data[0xA0 >> 2],
+		data[0xA4 >> 2],
+		data[0xA8 >> 2],
+		data[0xAC >> 2],
+		data[0xB0 >> 2],
+		data[0xB4 >> 2],
+		data[0xB8 >> 2],
+		data[0xBC >> 2],
+		data[0xC0 >> 2],
+		data[0xC4 >> 2],
+		data[0xC8 >> 2]);
+	fprintf(stdout,
+		"0xCC: PM LSB CRC for wakeup frame 0                 0x%02x\n"
+		"0xCD: PM LSB CRC for wakeup frame 1                 0x%02x\n"
+		"0xCE: PM LSB CRC for wakeup frame 2                 0x%02x\n"
+		"0xCF: PM LSB CRC for wakeup frame 3                 0x%02x\n"
+		"0xD0: PM LSB CRC for wakeup frame 4                 0x%02x\n"
+		"0xD1: PM LSB CRC for wakeup frame 5                 0x%02x\n"
+		"0xD2: PM LSB CRC for wakeup frame 6                 0x%02x\n"
+		"0xD3: PM LSB CRC for wakeup frame 7                 0x%02x\n",
+		data8[0xCC],
+		data8[0xCD],
+		data8[0xCE],
+		data8[0xCF],
+		data8[0xD0],
+		data8[0xD1],
+		data8[0xD2],
+		data8[0xD3]);
+	}
+	if (board_type >= RTL8139B) {
+	if (board_type != RTL8100 && board_type != RTL8100B_8139D &&
+	    board_type != RTL8101)
+	fprintf(stdout,
+		"0xD4: Flash memory read/write                 0x%08x\n",
+		data[0xD4 >> 2]);
+	if (board_type != RTL8130)
+	fprintf(stdout,
+		"0xD8: Config 5                                      0x%02x\n",
+		data8[0xD8]);
+	}
+	}
+
+	if (board_type == RTL8139Cp ||
+	    board_type == RTL8169 ||
+	    board_type == RTL8169s ||
+	    board_type == RTL8110) {
+	v = data[0xE0 >> 2] & 0xffff;
+	fprintf(stdout,
+		"0xE0: C+ Command                                  0x%04x\n",
+		v);
+	if (v & (1 << 9))
+		fprintf(stdout, "      Big-endian mode\n");
+	if (v & (1 << 8))
+		fprintf(stdout, "      Home LAN enable\n");
+	if (v & (1 << 6))
+		fprintf(stdout, "      VLAN de-tagging\n");
+	if (v & (1 << 5))
+		fprintf(stdout, "      RX checksumming\n");
+	if (v & (1 << 4))
+		fprintf(stdout, "      PCI 64-bit DAC\n");
+	if (v & (1 << 3))
+		fprintf(stdout, "      PCI Multiple RW\n");
+
+	v = data[0xe0 >> 2] >> 16;
+	fprintf(stdout,
+		"0xE2: Interrupt Mitigation                        0x%04x\n"
+		"      TxTimer:       %u\n"
+		"      TxPackets:     %u\n"
+		"      RxTimer:       %u\n"
+		"      RxPackets:     %u\n",
+		v,
+		v >> 12,
+		(v >> 8) & 0xf,
+		(v >> 4) & 0xf,
+		v & 0xf);
+
+	fprintf(stdout,
+		"0xE4: Rx Ring Addr                 0x%08x 0x%08x\n",
+		data[0xE4 >> 2],
+		data[0xE8 >> 2]);
+
+	fprintf(stdout,
+		"0xEC: Early Tx threshold                            0x%02x\n",
+		data8[0xEC]);
+
+	if (board_type == RTL8139Cp) {
+	fprintf(stdout,
+		"0xFC: External MII register                   0x%08x\n",
+		data[0xFC >> 2]);
+	}
+	}
+
+	return 0;
+}
diff --git a/tg3.c b/tg3.c
new file mode 100644
index 0000000..97613e9
--- /dev/null
+++ b/tg3.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include "ethtool-util.h"
+
+#define TG3_MAGIC 0x669955aa
+
+int
+tg3_dump_eeprom(struct ethtool_drvinfo *info, struct ethtool_eeprom *ee)
+{
+	int i;
+
+	if (ee->magic != TG3_MAGIC) {
+		fprintf(stderr, "Magic number 0x%08x does not match 0x%08x\n",
+			ee->magic, TG3_MAGIC);
+		return -1;
+	}
+
+	fprintf(stdout, "Address   \tData\n");
+	fprintf(stdout, "----------\t----\n");
+	for (i = 0; i < ee->len; i++)
+		fprintf(stdout, "0x%08x\t0x%02x\n", i + ee->offset, ee->data[i]);
+
+	return 0;
+}