changeset 150:f0e3fb000de8

Merge from eCos master repository on 2001-01-26-06:43:02-GMT
author jlarmour
date Fri, 26 Jan 2001 08:15:27 +0000
parents 52c99470ec11
children 25e238959bae
files packages/ChangeLog packages/devs/eth/intel/i82559/current/ChangeLog packages/devs/eth/intel/i82559/current/cdl/intel_i82559_eth_drivers.cdl packages/devs/eth/intel/i82559/current/include/i82559_info.h packages/devs/eth/intel/i82559/current/src/if_i82559.c packages/devs/serial/generic/16x5x/current/ChangeLog packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c packages/ecos.db packages/hal/arm/arch/current/ChangeLog packages/hal/arm/arch/current/src/vectors.S packages/hal/mips/arch/current/ChangeLog packages/hal/mips/arch/current/include/arch.inc packages/hal/powerpc/arch/current/ChangeLog packages/hal/powerpc/arch/current/src/powerpc.ld packages/hal/powerpc/mbx/current/ChangeLog packages/hal/powerpc/mbx/current/include/hal_diag.h packages/hal/sh/cq7708/current/ChangeLog packages/hal/sh/cq7708/current/include/platform.inc packages/hal/sh/cq7750/current/ChangeLog packages/hal/sh/cq7750/current/include/platform.inc packages/hal/sh/edk7708/current/ChangeLog packages/hal/sh/edk7708/current/include/platform.inc packages/kernel/current/ChangeLog packages/kernel/current/src/sched/mlqueue.cxx packages/pkgconf/fixhtml.tcl packages/pkgconf/rules.doc packages/pkgconf/stylesheet.dsl packages/redboot/current/ChangeLog packages/redboot/current/cdl/redboot.cdl packages/redboot/current/include/net/net.h packages/redboot/current/src/main.c packages/redboot/current/src/net/icmp.c packages/redboot/current/src/net/inet_addr.c packages/redboot/current/src/net/ping.c
diffstat 34 files changed, 4681 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-25  Jesper Skov  <jskov@redhat.com>
+
+	* ecos.db: Added generic i82559 ethernet driver.
+
 
 2000-11-25  Jonathan Larmour  <jlarmour@redhat.com>
 
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/intel/i82559/current/ChangeLog
@@ -0,0 +1,463 @@
+2001-01-25  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c: Replace CYGNUM_HAL_INTERRUPT_PCI_IRQ with
+	CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT which platform .inl
+	must provide when appropriate. Changed _deliver functions to match
+	_isr functions.
+	* include/i82559_info.h: Remove debug hacks.
+	Fix declaration.
+
+	* src/if_i82559.c: Moved device descriptors into platform header.
+	Allow individual devices to hardwire ESA. Handle N devices instead
+	of just 1 or 2.
+	* include/i82559_info.h: ESA hardwired flag added.
+	* cdl/intel_i82559_eth_drivers.cdl: Device details moved to
+	platform CDL.
+
+	* src/if_i82559.c (i82559_start): Poll status after dump command.
+
+2001-01-24  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c: [changes from yesterday] Some more endian
+	fiddle, and the device coughs out the initial ARP packets.
+	(wait_for_cmd_done): semantics changed to wait for pending CU
+	cmds.
+	(i82559_reset): Cleaned up to spec. Init register bases after
+	reset.
+	Fix initialization of hardwired ESA.
+	Correct configuration command.
+	Fix rcv len masking.
+	(eth_set_mac_address): Set driver's ESA as well. Proper check for
+	completion.
+	Fix LE structure offsets.
+	(i82559_start): Call new eth_set_config to enable device. Last
+	hacks cleaned up.
+	Remove a few printfs.
+
+2001-01-23  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c: Debug hackery and some endian issues resolved.
+
+2001-01-22  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c: Major changes, getting rid of device structures
+	in favor of HAL IO accessor macros. Also added endian conversion
+	macros where required.
+	* include/i82559_info.h: Change type of device structures to char.
+
+2001-01-19  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/intel_i82559_eth_drivers.cdl: Hack for just one interface
+	now.
+	* src/if_i82559.c: Fix IO functions. Handle EEPROM not being
+	attached to device.
+
+	* src/if_i82559.c: Use uncached/physical address translation
+	macros.
+
+2001-01-15  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c: Handle endian differences between controller
+	and CPU. Leave usdelay to HAL. Hack around PCI-base-at-0
+	assumption.
+	Increase SK_DELAY (not that it changed anything, but now it's to
+	the spec), hardwire static ESA.
+	
+2001-01-12  Jesper Skov  <jskov@redhat.com>
+
+	* src/if_i82559.c (pci_init_find_82559s): Check that device has
+	been found before accessing it. 
+	(pci_init_find_82559s): Only delay if devices were
+	found. Recognize 82559ER code as well.
+
+2001-01-10  Jesper Skov  <jskov@redhat.com>
+	
+	* src/if_i82559.c: Minor hacks to get it to build.
+	* include/i82559_info.h: Same.
+	* cdl/intel_i82559_eth_drivers.cdl: Same.
+
+2000-12-07  Jesper Skov  <jskov@redhat.com>
+
+	* cdl/intel_i82559_eth_drivers.cdl: Cloned from the EBSA driver.
+	* include/i82559_info.h: Same.
+	* src/if_i82559.c: Same.
+
+2000-11-19  Gary Thomas  <gthomas@redhat.com>
+
+	* src/if_ebsa285.c (pci_init_find_82559s): Intel has at least
+	two devices equivalent to the 82559.  Support both (0x1229, 0x01030).
+
+2000-10-05  Hugo Tyson  <hmt@redhat.com>
+
+	* src/if_ebsa285.c: Deal with device interrupts in a nested
+	fashion - disable/restore is the semantics now, rather than
+	unconditionally unmasking.  Also go directly to the 21285 PIC's
+	interrupt control registers to gain atomicity for these.  Poll for
+	ready received packets when acknowledging an interrupt in the
+	tranmitting world; a race here could lose an Rx interrupt.  Which
+	doesn't matter on a busy system, but in quieter times...  there
+	will always be such a race because of the vague way the i82559's
+	status bits reflect how it's yanking the interrupt line; you have
+	to poll until the interrupt is gone before returning else spurious
+	interrupt failures occur.  The issue is to close the window as
+	tightly as possible, which this change achieves at a minor cost in
+	performance - because of the time spent polling when not required.
+
+2000-09-11  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_poll): Only diddle the interface we
+	were asked to.  This is more correct in terms of the intent of the
+	API, though it shouldn't really be necessary.
+
+2000-09-06  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (pci_init_find_82559s): Add asserts and an
+	unconditional check that the PCI window as configured matches the
+	address and size of the pci_window region from the MLT.  This is
+	here because at present the MLT and CT cannot intercommunicate
+	enough.  The separation of the PCI window is needed because
+	otherwise the malloc heap will eat all memory.  [This is related
+	to CR 902624-CR, "MLT needs to be configuration aware"]
+
+2000-09-01  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* OVERVIEW: This is part of the change to the network stack to
+	greatly reduce latencies both of (other) DSRs and of thread
+	scheduling.  All the work that the network stack *and* individual
+	ether drivers used to do in DSRs (including alarm callbacks and
+	data copies to/from the device memory) is moved into a "fast
+	network thread" instead.  It calls a device's "deliver" function
+	to do the work that was previously in the DSR.  This is a separate
+	thread so that it can be set higher priority than application
+	threads in order to minimize packet loss (depending on the
+	driver), if required (the application threads presumed to be
+	higher priority in turn than the network thread).  A crucial
+	consequence of this is that we are no longer locking against DSRs,
+	so a plain mutex can be used rather than the global scheduler
+	lock, thus simplifying all the splfoo/splx() style functions.
+
+	* src/if_ebsa285.c: Minor: fix the big assert in i82559_send()
+	which suffered a race condition when called from the fast thread
+	rather than from a DSR.  Major: Add a "deliver" entry to the
+	interface record for the "fast thread" implementation of the
+	network internal comms system.  Provide a pass-up DSR to the
+	logical ether driver's DSR and appropriate delivery routine(s).
+	i82559_poll() now calls i82559_deliver() rather than the DSR.  Add
+	valid data for mux'd DSR to pass on up.
+
+2000-09-01  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* tests/test_net_realtime.h: Tighten up the latency requirements
+	by a factor of 5; it all seems happy, so committed.
+
+2000-08-25  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_ioctl): A little further diddling; have
+	a bool to say whether the dot3 info is filled in.
+
+2000-08-24  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Do not export a symbol for the
+	device info file (include/ebsa285_info.h) since nobody needs
+	(portably) to include it now.
+
+	* src/if_ebsa285.c (i82559_ioctl): Handle new ioctl calls
+	ETH_DRV_GET_IF_STATS_UD and ETH_DRV_GET_IF_STATS to get loads of
+	statistical information out.  _UD means update.  The nonUD one can
+	be used instead mostly, if we find the performance hit too large.
+	This should allow SNMP (a) to not explode, (b) to get useful info
+	out of other device implementations than this one.
+
+	* include/ebsa285_info.h: Remove all the macro cruft for feature
+	detecting of lots of individual statistics; we now just have a
+	catch-all struct that SNMP uses, defined in the common ether
+	driver environment.
+
+2000-08-15  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (PacketRxReady): Put back the check for very
+	small packets into the driver; the layer above checks for that
+	(defensive programming) but only *after* asserting that the size
+	is large enough, to help detect that scenario from other drivers.
+	I believe we only have struct ether_header available if CYGPKG_NET
+	but I could be wrong.
+	[CASE 104353]
+
+2000-08-08  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (eth_set_promiscuous_mode):
+	- ccs->config_bytes[18]=0x70;
+	+ ccs->config_bytes[18]=0x72; // Keep the Padding Enable bit
+	...otherwise short frame sends don't work in promisc mode.
+	[CASE 104289]
+
+2000-08-07  Gary Thomas  <gthomas@redhat.com>
+
+	* src/if_ebsa285.c (pciwindow_mem_alloc): Take out very noisy debug.
+
+2000-08-03  Gary Thomas  <gthomas@redhat.com>
+
+	* src/if_ebsa285.c: Changes for stand-alone mode.
+
+	* cdl/ebsa285_eth_drivers.cdl: Ethernet driver package hierarchy changed.
+	Add option to control number of interfaces.
+
+2000-07-28  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (PacketRxReady): Do not attempt to forward
+	short packets; eth_drv.c assumes there is at least a header there.
+	(i82559_recv): Also be more careful and ASSERTive about -ve buffer
+	sizes; be more defensive about sglists.  [CASE 104206]
+
+2000-07-26  Gary Thomas  <gthomas@redhat.com>
+
+	* src/if_ebsa285.c: Update for new eth_drv interfaces.
+
+2000-07-18  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_poll): Fill in the flesh of this, it
+	just calls ISR and DSR repeatedly.
+	(i82559_start): Look in the device record for promiscuous mode
+	flag; it should be passed though the common layer, but it's not
+	[yet] - this change from Andrew Lunn/ASCOM.  Also a fix and delay
+	to the promisc mode code per se.
+
+2000-07-17  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_poll): New function, just to fill in
+	the interface record; not used.
+
+2000-06-27  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Add sesquipedalian option
+	CYGDBG_DEVS_ETH_ARM_EBSA285_KEEP_82559_STATISTICS in (now)
+	component CYGDBG_DEVS_ETH_ARM_EBSA285_KEEP_STATISTICS to control
+	keeping (well, harvesting really) the i82559's internal stats.
+	Reputedly, it doesn't service the net whilst this is happening, so
+	it could be viewed a bad thing.  Hence the option.
+
+	* include/ebsa285_info.h: Only describe the I82559_COUNTERS
+	i82559_counters[2]; structs if full stats are to be kept.
+
+	* src/if_ebsa285.c (update_statistics): Only include this if full
+	stats are to be kept.
+
+2000-06-27  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (ResetRxRing): Re-do the management of the
+	RxRing; have an end-of-list flag (EL) in the last entry, and as
+	you unload filled slots, drag it round after you.
+
+2000-06-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Add option to control statistics
+	keeping.
+
+	* include/ebsa285_info.h: Act on it.
+
+2000-06-13  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Properly include the new header
+	file and define symbols to allow client code to get at it without
+	knowing the particular device driver name.
+
+	* include/ebsa285_info.h: New file: export various statistics
+	information about the driver for use by monitoring and
+	network-management systems.  This requires exposing the
+	(otherwise) internal structures of the driver.
+
+	* src/if_ebsa285.c: remove a lot of structure definitions &c that
+	are now necessarily in the new header; add a couple of new
+	routines which provide status and update statistics from the
+	device into memory; tidy up control of whether stats-keeping is
+	enabled.
+
+2000-06-06  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl (define_proc): Add #define of
+	CYGDAT_DEVS_ETH_DESCRIPTION in the config file for information.
+
+2000-05-12  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* tests/test_net_realtime.h (tnr_print_activity): New routine to
+	check the system is working, tidied up the API.  It works!
+
+2000-05-11  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Added export of the test header
+	below, and config opts for controlling EEPROM writing and all the
+	status chatter as the device starts up.
+
+	* src/if_ebsa285.c: Reworked the code for reading and setting the
+	EEPROM that holds the MAC address.  This is very ugly, but now
+	more reliable.  Also tidied up printing cruft with neater
+	configury, and made it an option (for safety) whether it's
+	possible to write the EEPROM at all.
+
+	* tests/test_net_realtime.h: New file - it is intended to be used
+	by networking tests to verify that latency is not compromised by
+	the stack and driver.  It's very platform specific, hence the
+	location in here.  This is a preliminary version only.
+
+2000-04-27  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c: A serious re-write.  This cuts out a lot of
+	code from the old version and improves the performance greatly.
+
+	The cruft was mainly doing lots of explicit event communication
+	between the ISR and DSR, when in fact all the state needed is
+	present in the tx/rx rings.  So both ISRs and DSRs regard their
+	call as an opportunity to progress everything they can, rather
+	than only dealing with one interrupt cause at a time; the
+	connection between them is now rather looser.
+
+	Interrups can now be re-enabled after the ISR (in other words they
+	are not masked in the ISR), no need to wait for the DSR, but in
+	consequence some DSR code must mask/unmask intrs as it works.
+
+	The 82559 appears to be a little slow in reacting to commands and
+	state changes, so some interrupts were being lost - or persisting
+	beyond their desired life - so there's some kinda polling code to
+	deal with that also.  We also rely on the foreground to kind of
+	poll in the same way, in the send/can_send calls - we know the
+	stack will re-try if necessary, though this is rare.
+
+	The driver now works (albeit at much reduced performance) with as
+	few as 6 rx and tx buffers - in other words the "queue full/out of
+	rx buffers" states have been tested and all is well.  It works
+	generally fine with 8 buffers of each kind.
+
+	The mux ISR and DSR are now rather more polled than the old
+	versions; we just try to do things with both devices (if active)
+	by simply calling each unitary ISR/DSR respectively.
+
+	I also re-ordered some of the code, moving utilities to the end of
+	the file and grouping together Tx and Rx machines a bit better.
+
+2000-04-13  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c: Attribution to Ron Spence, Pacific Softworks
+	added as a contributor.
+
+2000-04-07  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* ecos.db: Re-organize device packages.  This is a massive change
+	involving deleting all the sources for serial and ethernet drivers
+	from where they used to live in
+	    packages/io/serial/current/src/ARCH/PLATFORM.[ch]
+	    packages/net/drivers/eth/PLATFORM/current/src/...
+	and reinstating them in
+	    packages/devs/serial/ARCH/PLATFORM/current/src/...
+	    packages/devs/eth/ARCH/PLATFORM/current/src/...
+
+	All these new packages are properly defined in ecos.db, and are
+	all of type "hardware" so that a "target" can grab them.
+	
+	This directory layout is descriptive of the devices we have right
+	now, arch and platform are separate levels just to make it easier
+	to navigate in the filesystem and similar to the HAL structure in
+	the filesystem.
+
+	It is *not* prescriptive of future work; for example, the mythical
+	common highly-portable 16550 serial driver which works on many
+	targets would be called "devs/serial/s16550/current", or a serial
+	device for a particular board (cogent springs to mind) that can
+	work with different CPUs fitted is "devs/serial/cogent/current".
+
+	Changelogs have been preserved and replicated over all the new
+	packages, so that no history is lost.
+
+	The contents of individual source files are unchanged; they build
+	in just the same emvironment except for a very few cases where the
+	config file name changed in this movement.
+
+	Targets in ecos.db have been redefined to bring in all relevant
+	hardware packages including net and serial drivers (but the newly
+	included packages are only active if their desired parent is
+	available.)
+	
+	The names of CDL options (and their #defines of course) stay the
+	same for the serial drivers, for backward compatibility.
+
+	* templates/*/current.ect: these have had CYGPKG_IO_SERIAL added
+	rather than it being in (almost) all target definitions.
+	
+2000-03-29  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_recv): Be happy with NULLs in the
+	SGlist; it means the caller is out of memory so drop the packet on
+	the floor.  Also remove a completely redundant test.
+
+2000-03-06  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (i82559_can_send): Update net driver to new
+	interface style.  This is incomplete wrt promiscuous mode, but
+	that's probably about all.
+
+2000-02-14  Gary Thomas  <gthomas@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl: Update CDL to indicate multiple 
+	interface support.
+
+2000-02-14  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (pci_init_find_82559s): Tidy comments somewhat
+	and set debug and stats collecting defines to most friendly
+	settings.
+
+2000-02-10  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c (PacketRxReady): Fix bug; current descriptor
+	was not being write back for the callback to use.  Hence asserts
+	on state of rfd were firing in busy times - that leading rfd had
+	already been drained.
+
+	Also rationalized meaning of DEBUG printy symbols a bit - it's now
+	chatty during startup/foreground manipulations but not in any
+	performance related activities ie. rx or tx.
+
+2000-02-09  John Dallaway  <jld@cygnus.co.uk>
+
+	* cdl/ebsa285_eth_drivers.cdl:
+
+	Reparent under CYGPKG_NET_ETH_DRIVERS and tidy display strings.
+
+2000-02-08  Hugo Tyson  <hmt@cygnus.co.uk>
+
+	* src/if_ebsa285.c: New File.
+	* cdl/ebsa285_eth_drivers.cdl: New File.
+
+	Initial Checkin of EBSA285 Ethernet driver.
+
+	It's one monolithic file at present, and should be split up into a
+	more generic Intel 82559 driver plus platform-specific parts (PCI
+	et al) plus eCos/Red-Hat-BSD-stack parts.
+	
+//===========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//===========================================================================
+	
+	
+
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/intel/i82559/current/cdl/intel_i82559_eth_drivers.cdl
@@ -0,0 +1,140 @@
+# ====================================================================
+#
+#	intel_i82559_eth_drivers.cdl
+#
+#	Intel 82559 ethernet driver
+#
+# ====================================================================
+#####COPYRIGHTBEGIN####
+#                                                                          
+# -------------------------------------------                              
+# The contents of this file are subject to the Red Hat eCos Public License 
+# Version 1.1 (the "License"); you may not use this file except in         
+# compliance with the License.  You may obtain a copy of the License at    
+# http://www.redhat.com/                                                   
+#                                                                          
+# Software distributed under the License is distributed on an "AS IS"      
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+# License for the specific language governing rights and limitations under 
+# the License.                                                             
+#                                                                          
+# The Original Code is eCos - Embedded Configurable Operating System,      
+# released September 30, 1998.                                             
+#                                                                          
+# The Initial Developer of the Original Code is Red Hat.                   
+# Portions created by Red Hat are                                          
+# Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
+# All Rights Reserved.                                                     
+# -------------------------------------------                              
+#                                                                          
+#####COPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      hmt
+# Original data:  hmt
+# Contributors:	  hmt, gthomas, jskov
+# Date:           2000-02-01
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_INTEL_I82559 {
+    display       "Intel 82559 ethernet driver"
+    description   "Ethernet driver for Intel 82559 controller."
+
+    parent        CYGPKG_IO_ETH_DRIVERS
+    active_if     CYGPKG_IO_ETH_DRIVERS
+
+    active_if     CYGINT_DEVS_ETH_INTEL_I82559_REQUIRED
+
+    include_dir   cyg/devs/eth
+
+    # SNMP demands to know stuff; this sadly makes us break the neat
+    # abstraction of the device having nothing exported.
+    include_files include/i82559_info.h
+    # and tell them that it is available
+    define_proc {
+	puts $::cdl_system_header \
+       "#define CYGBLD_DEVS_ETH_DEVICE_H <pkgconf/devs_eth_intel_i82559.h>"
+
+        puts $::cdl_header "#include CYGDAT_DEVS_ETH_INTEL_I82559_CFG";
+    }
+
+    compile       -library=libextras.a if_i82559.c
+
+    cdl_option CYGDBG_DEVS_ETH_INTEL_I82559_CHATTER {
+	display "Prints ethernet device status info during startup"
+	default_value 0
+	description   "
+	    The ethernet device initialization code can print lots of info
+	    to confirm that it has found the devices on the PCI bus, read
+	    the MAC address from EEPROM correctly, and so on, and also
+	    displays the mode (10/100MHz, half/full duplex) of the
+	    connection."
+    }
+
+    cdl_option CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT {
+	display "Number of supported interfaces."
+	calculated    { CYGINT_DEVS_ETH_INTEL_I82559_REQUIRED }
+        flavor        data
+	description   "
+	    This option selects the number of PCI ethernet interfaces to
+            be supported by the driver."
+    }
+
+    cdl_component CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_STATISTICS {
+	display "Keep Ethernet statistics"
+	default_value 1
+	description   "
+	    The ethernet device can maintain statistics about the network,
+	    specifically a great variety of error rates which are useful
+	    for network management.  SNMP for example uses this
+	    information.  There is some performance cost in maintaining
+	    this information; disable this option to recoup that."
+
+	cdl_option CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_82559_STATISTICS {
+	    display "Keep i82559 Internal statistics"
+	    default_value 1
+	    description   "
+	        The i82559 keeps internal counters, and it is possible to
+	        acquire these.  But the i82559 (reputedly) does not service
+	        the network whilst uploading the data to RAM from its
+	        internal registers.  If throughput is a problem, disable
+	        this option to acquire only those statistics gathered by
+	        software, so that the i82559 never sleeps."
+	}
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM {
+	display "SIOCSIFHWADDR records MAC address in EEPROM"
+	default_value 0
+	description   "
+	    The ioctl() socket call with operand SIOCSIFHWADDR sets the
+	    interface hardware address - the MAC address or ethernet
+	    address.  This option causes the new MAC address to be written
+	    into the EEPROM associated with the interface, so that the new
+	    MAC address is permanently recorded.  Doing this should be a
+	    carefully chosen decision, hence this option."
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_INTEL_I82559_OPTIONS {
+        display "Intel 82559 ethernet driver build options"
+        flavor  none
+	no_define
+
+        cdl_option CYGPKG_DEVS_ETH_INTEL_I82559_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "-D_KERNEL -D__ECOS" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the Intel 82559 ethernet driver
+                package. These flags are used in addition to the set of
+                global flags."
+        }
+    }
+}
+# EOF intel_i82559_eth_drivers.cdl
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/intel/i82559/current/include/i82559_info.h
@@ -0,0 +1,206 @@
+#ifndef CYGONCE_DEVS_ETH_INTEL_I82559_INFO_H
+#define CYGONCE_DEVS_ETH_INTEL_I82559_INFO_H
+/*==========================================================================
+//
+//        i82559_info.h
+//
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     hmt
+// Contributors:  hmt
+// Date:          2000-05-03
+// Description:
+//
+//####DESCRIPTIONEND####
+*/
+
+#include <pkgconf/devs_eth_intel_i82559.h>
+
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_STATISTICS
+# define KEEP_STATISTICS
+# define nDISPLAY_STATISTICS
+# define nDISPLAY_82559_STATISTICS
+#else
+# define nKEEP_STATISTICS
+# define nDISPLAY_STATISTICS
+# define nDISPLAY_82559_STATISTICS
+#endif
+
+
+// ------------------------------------------------------------------------
+//
+//                       STATISTICAL COUNTER STRUCTURE
+//
+// ------------------------------------------------------------------------
+#ifdef KEEP_STATISTICS
+typedef struct {
+/*  0 */    cyg_uint32 tx_good;
+/*  4 */    cyg_uint32 tx_max_collisions;
+/*  8 */    cyg_uint32 tx_late_collisions;
+/* 12 */    cyg_uint32 tx_underrun;
+/* 16 */    cyg_uint32 tx_carrier_loss;
+/* 20 */    cyg_uint32 tx_deferred;
+/* 24 */    cyg_uint32 tx_single_collisions;
+/* 28 */    cyg_uint32 tx_mult_collisions;
+/* 32 */    cyg_uint32 tx_total_collisions;
+/* 36 */    cyg_uint32 rx_good;
+/* 40 */    cyg_uint32 rx_crc_errors;
+/* 44 */    cyg_uint32 rx_align_errors;
+/* 48 */    cyg_uint32 rx_resource_errors;
+/* 52 */    cyg_uint32 rx_overrun_errors;
+/* 56 */    cyg_uint32 rx_collisions; // Always 0
+/* 60 */    cyg_uint32 rx_short_frames;
+// In this setup; can also be flow-control counts after.
+// If these are to be used, a config command (as in set promiscuous mode)
+// must be issued at start, to let those stats escape.  Params are in
+// comments around the config command setup...
+/* 64 */    cyg_uint32 done;
+} I82559_COUNTERS;
+
+
+typedef struct {
+    cyg_uint32 interrupts;
+    cyg_uint32 rx_count;
+    cyg_uint32 rx_deliver;
+    cyg_uint32 rx_resource;
+    cyg_uint32 rx_restart;
+    cyg_uint32 tx_count;
+    cyg_uint32 tx_complete;
+    cyg_uint32 tx_dropped;
+} STATISTICS;
+
+
+extern STATISTICS statistics[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_82559_STATISTICS
+extern I82559_COUNTERS i82559_counters[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
+#endif
+
+#endif // KEEP_STATISTICS
+
+// ------------------------------------------------------------------------
+//
+//                      DEVICES AND PACKET QUEUES
+//
+// ------------------------------------------------------------------------
+// The system seems to work OK with as few as 8 of RX and TX descriptors.
+// It limps very painfully with only 4.
+// Performance is better with more than 8.
+// But the size of non-cached (so useless for anything else)
+// memory window is 1Mb, so we might as well use it all.
+//
+// 128 for these uses the whole 1Mb, near enough.
+
+#ifndef MAX_RX_DESCRIPTORS
+#define MAX_RX_DESCRIPTORS	128     // number of Rx descriptors
+#endif
+#ifndef MAX_TX_DESCRIPTORS
+#define MAX_TX_DESCRIPTORS	128     // number of Tx descriptors
+#endif
+
+// Use packet type for selfdocumenting code
+typedef cyg_uint8 RFD;
+typedef cyg_uint8 TxCB;
+typedef cyg_uint8 CFG;
+
+typedef struct i82559 {
+    cyg_uint8                           // (split up for atomic byte access)
+        found:1,                        // was hardware discovered?
+        mac_addr_ok:1,                  // can we bring up?
+        active:1,                       // has this if been brung up?
+        hardwired_esa:1,                // set if ESA is hardwired via CDL
+        spare1:4; 
+    cyg_uint8
+        spare2:8; 
+    cyg_uint8
+        tx_in_progress:1,               // transmit in progress flag
+        tx_queue_full:1,                // all Tx descriptors used flag
+        spare3:6; 
+    cyg_uint8  index;                   // 0 or 1 or whatever
+    cyg_uint32 devid;                   // PCI device id
+    cyg_uint32 memory_address;          // PCI memory address
+    cyg_uint32 io_address;              // memory mapped I/O address
+    cyg_uint8  mac_address[6];          // mac (hardware) address
+    void *ndp;                          // Network Device Pointer
+
+    int next_rx_descriptor;             // descriptor index for RFDs
+    RFD* rx_ring[MAX_RX_DESCRIPTORS];   // location of Rx descriptors
+
+    int tx_descriptor_add;              // descriptor index for additions
+    int tx_descriptor_active;           // descriptor index for active tx
+    int tx_descriptor_remove;           // descriptor index for remove
+
+    TxCB* tx_ring[MAX_TX_DESCRIPTORS];  // location of Tx descriptors
+    unsigned long tx_keys[MAX_TX_DESCRIPTORS];
+                                        // keys for tx q management
+
+    // Interrupt handling stuff
+    cyg_vector_t    vector;             // interrupt vector
+    cyg_handle_t    interrupt_handle;   // handle for int.handler
+    cyg_interrupt   interrupt_object;
+
+#ifdef KEEP_STATISTICS
+    void *p_statistics;                 // pointer to statistical counters
+#endif
+
+} I82559;
+
+
+// ------------------------------------------------------------------------
+//
+//                   82559 GENERAL STATUS REGISTER
+//
+// ------------------------------------------------------------------------
+#define GEN_STATUS_FDX          0x04    // 1 = full duplex, 0 = half
+#define GEN_STATUS_100MBPS      0x02    // 1 = 100 Mbps, 0 = 10 Mbps
+#define GEN_STATUS_LINK         0x01    // 1 = link up, 0 = link down
+
+extern int i82559_status( struct eth_drv_sc *sc );
+
+// ------------------------------------------------------------------------
+
+#ifdef KEEP_STATISTICS
+void update_statistics(struct i82559* p_i82559);
+#endif
+
+
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_82559_STATISTICS
+#define ETH_STATS_INIT( p ) \
+        update_statistics( (struct i82559 *)((p)->driver_private) )
+#else
+#define ETH_STATS_INIT( p ) // otherwise do nothing
+#endif
+
+#define CYGDAT_DEVS_ETH_DESCRIPTION "Intel EtherPRO 10/100+ (i82559)"
+
+#define ETH_DEV_DOT3STATSETHERCHIPSET 1,3,6,1,2,1,10,7,8,2,5
+
+#endif /* ifndef CYGONCE_DEVS_ETH_INTEL_I82559_INFO_H */
+
+/* EOF i82559_info.h */
+
new file mode 100644
--- /dev/null
+++ b/packages/devs/eth/intel/i82559/current/src/if_i82559.c
@@ -0,0 +1,3188 @@
+//==========================================================================
+//
+//      if_i82559.c
+//
+//	Intel 82559 ethernet driver
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD or
+// other sources, and are covered by the appropriate copyright
+// disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    hmt, gthomas
+// Contributors: Ron Spence, Pacific Softworks, jskov
+// Date:         2000-02-01
+// Purpose:      
+// Description:  hardware driver for 82559 Intel PRO/100+ ethernet
+// Notes:        CU commands such as dump and config should, according
+//               to the docs, set the CU active state while executing.
+//               That does not seem to be the case though, and the
+//               driver polls the completion bit in the packet status
+//               word instead.
+//
+//               Platform code must provide this vector:
+//               CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT if it
+//               requires the interrupts to be handled via demuxers.
+//
+//               Platform code can also provide this macro:
+//               CYGPRI_DEVS_ETH_INTEL_I82559_INTERRUPT_ACK_LOOP(p_i82559)
+//               to handle delaying for acks to register on the interrupt
+//               controller as necessary on the EBSA.
+//
+//        FIXME: IN/OUT macros for accessing PCI IO space are probably
+//               broken on proper BE systems. Tested on a board with
+//               a Galileo which seems to do some weird stuff to 8/16
+//               bit word addressing.
+//        FIXME: replace -1/-2 return values with proper E-defines
+//        FIXME: eth_set_mac_address and eth_set_promiscuous_mode
+//               failures are not handled properly [try writing
+//               endian swapped cmd - CU starts, but wedges]
+//        FIXME: For 82557/8 compatibility the eth_set_config and
+//               eth_set_promiscuous_mode functions probably need
+//               some tweaking - config bits differ slightly but
+//               crucially.
+//        FIXME: EEPROM code not tested on a BE system.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/devs_eth_intel_i82559.h>
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/hal_intr.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/drv_api.h>
+#include <netdev.h>
+#include <eth_drv.h>
+
+#ifdef CYGPKG_NET
+#include <pkgconf/net.h>
+#include <net/if.h>  /* Needed for struct ifnet */
+#else
+#include <cyg/hal/hal_if.h>
+#define diag_printf printf
+#endif
+
+#ifdef CYGPKG_IO_PCI
+#include <cyg/io/pci.h>
+// So we can check the validity of the PCI window against the MLTs opinion,
+// and thereby what the malloc heap consumes willy-nilly:
+#include CYGHWR_MEMORY_LAYOUT_H
+#else
+#error "Need PCI package here"
+#endif
+
+// Exported statistics and the like
+#include <cyg/devs/eth/i82559_info.h>
+#include <eth_drv_stats.h>
+#include CYGDAT_DEVS_ETH_INTEL_I82559_INL
+
+// ------------------------------------------------------------------------
+// Platform specific
+
+#define CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE (CYGARC_UNCACHED_ADDRESS(0x0ff00000))
+#define CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE 0x00100000
+
+// ------------------------------------------------------------------------
+
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_CHATTER
+#define notDEBUG_82559 // This one prints stuff as packets come and go
+#define DEBUG          // Startup printing mainly
+#define DEBUG_EE       // Some EEPROM specific retries &c
+#endif
+
+#define os_printf diag_printf
+#define db_printf diag_printf
+
+// ------------------------------------------------------------------------
+// I/O access macros as inlines for type safety
+
+#if (CYG_BYTEORDER == CYG_MSBFIRST)
+
+#define HAL_CTOLE32(x)  ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff))
+#define HAL_LE32TOC(x)  ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) >> 24) & 0xff))
+
+#define HAL_CTOLE16(x)  ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
+#define HAL_LE16TOC(x)  ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
+
+static inline void OUTB(cyg_uint8 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint8 *)(io_address)) = value;    }
+
+static inline void OUTW(cyg_uint16 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint16 *)(io_address)) = (((value & 0xff) << 8) | ((value & 0xff00) >> 8));   }
+
+static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint32 *)io_address) = ((((value) & 0xff) << 24) | (((value) & 0xff00) << 8) | (((value) & 0xff0000) >> 8) | (((value) >> 24) & 0xff));   }
+
+static inline cyg_uint8 INB(cyg_uint32 io_address)
+{   return *((volatile cyg_uint8 *)(io_address));     }
+
+static inline cyg_uint16 INW(cyg_uint32 io_address)
+{   cyg_uint16 d;
+    d = *((volatile cyg_uint16 *)(io_address));
+    return (((d & 0xff) << 8) | ((d & 0xff00) >> 8));
+}
+
+static inline cyg_uint32 INL(cyg_uint32 io_address)
+{   cyg_uint32 d;
+    d = *((volatile cyg_uint32 *)io_address); 
+    return ((((d) & 0xff) << 24) | (((d) & 0xff00) << 8) | (((d) & 0xff0000) >> 8) | (((d) >> 24) & 0xff));
+}
+#else
+static inline void OUTB(cyg_uint8 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint8 *)io_address) = value;    }
+
+static inline void OUTW(cyg_uint16 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint16 *)io_address) = value;   }
+
+static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address)
+{   *((volatile cyg_uint32 *)io_address) = value;   }
+
+static inline cyg_uint8 INB(cyg_uint32 io_address)
+{   return *((volatile cyg_uint8 *)io_address);     }
+
+static inline cyg_uint16 INW(cyg_uint32 io_address)
+{   return *((volatile cyg_uint16 *)io_address);    }
+
+static inline cyg_uint32 INL(cyg_uint32 io_address)
+{   return *((volatile cyg_uint32 *)io_address);    }
+#endif // byteorder
+
+#define VIRT_TO_BUS( _x_ ) virt_to_bus((cyg_uint32)(_x_))
+static inline cyg_uint32 virt_to_bus(cyg_uint32 p_memory)
+{ return CYGARC_PHYSICAL_ADDRESS(p_memory);    }
+
+#define BUS_TO_VIRT( _x_ ) bus_to_virt((cyg_uint32)(_x_))
+static inline cyg_uint32 bus_to_virt(cyg_uint32 p_memory)
+{ return CYGARC_UNCACHED_ADDRESS(p_memory); }
+
+
+// ------------------------------------------------------------------------
+//                                                                      
+//                   82559 REGISTER OFFSETS (I/O SPACE)                 
+//                                                                      
+// ------------------------------------------------------------------------
+#define SCBStatus       0               // Rx/Command Unit command and status.
+#define SCBCmd          2               // Rx/Command Unit command and status.
+#define SCBPointer      4               // General purpose pointer.
+#define SCBPort         8               // Misc. commands and operands.
+#define SCBflash        12              // Flash memory control.
+#define SCBeeprom       14              // EEPROM memory control.
+#define SCBCtrlMDI      16              // MDI interface control.
+#define SCBEarlyRx      20              // Early receive byte count.
+#define SCBGenControl   28              // 82559 General Control Register
+#define SCBGenStatus    29              // 82559 General Status register
+
+
+// ------------------------------------------------------------------------
+//
+//               82559 SCB STATUS WORD DEFNITIONS
+//
+// ------------------------------------------------------------------------
+#define SCB_STATUS_CX   0x8000          // CU finished command (transmit)
+#define SCB_STATUS_FR   0x4000          // frame received
+#define SCB_STATUS_CNA  0x2000          // CU left active state
+#define SCB_STATUS_RNR  0x1000          // receiver left ready state
+#define SCB_STATUS_MDI  0x0800          // MDI read/write cycle done
+#define SCB_STATUS_SWI  0x0400          // software generated interrupt
+#define SCB_STATUS_FCP  0x0100          // flow control pause interrupt
+
+#define SCB_INTACK_MASK 0xFD00          // all the above
+
+#define SCB_INTACK_TX (SCB_STATUS_CX | SCB_STATUS_CNA)
+#define SCB_INTACK_RX (SCB_STATUS_FR | SCB_STATUS_RNR)
+
+// ------------------------------------------------------------------------
+//
+//               82559 PORT INTERFACE COMMANDS
+//
+// ------------------------------------------------------------------------
+#define I82559_RESET            0x00000000 // software reset
+#define I82559_SELFTEST         0x00000001 // 82559 selftest command
+#define I82559_SELECTIVE_RESET  0x00000002
+#define I82559_DUMP             0x00000003
+#define I82559_DUMP_WAKEUP      0x00000007
+
+
+// ------------------------------------------------------------------------
+//
+//                   82559 EEPROM INTERFACE
+//
+// ------------------------------------------------------------------------
+//  EEPROM_Ctrl bits.
+#define EE_SHIFT_CLK	0x01            // EEPROM shift clock.
+#define EE_CS		0x02            // EEPROM chip select.
+#define EE_DATA_WRITE	0x04            // EEPROM chip data in.
+#define EE_DATA_READ	0x08            // EEPROM chip data out.
+#define EE_ENB		(0x4800 | EE_CS)
+
+// Delay between EEPROM clock transitions.
+#define eeprom_delay(usec)		udelay(usec);
+
+// The EEPROM commands include the always-set leading bit.
+#define EE_WRITE_CMD(a)     (5 << (a))
+#define EE_READ_CMD(a)	    (6 << (a))
+#define EE_ERASE_CMD(a)	    (7 << (a))
+#define EE_WRITE_EN_CMD(a)  (19 << ((a)-2))
+#define EE_WRITE_DIS_CMD(a) (16 << ((a)-2))
+#define EE_ERASE_ALL_CMD(a) (18 << ((a)-2))
+
+#define EE_TOP_CMD_BIT(a)      ((a)+2) // Counts down to zero
+#define EE_TOP_DATA_BIT        (15)    // Counts down to zero
+
+#define EEPROM_ENABLE_DELAY (10) // Delay at chip select
+
+#define EEPROM_SK_DELAY  (4) // Delay between clock edges *and* data
+                             // read or transition; 3 of these per bit.
+#define EEPROM_DONE_DELAY (100) // Delay when all done
+
+
+// ------------------------------------------------------------------------
+//
+//               SYSTEM CONTROL BLOCK COMMANDS
+//
+// ------------------------------------------------------------------------
+// CU COMMANDS
+#define CU_NOP          0x0000
+#define	CU_START        0x0010
+#define	CU_RESUME       0x0020
+#define	CU_STATSADDR    0x0040          // Load Dump Statistics ctrs addr
+#define	CU_SHOWSTATS    0x0050          // Dump statistics counters.
+#define	CU_ADDR_LOAD    0x0060          // Base address to add to CU commands
+#define	CU_DUMPSTATS    0x0070          // Dump then reset stats counters.
+
+// RUC COMMANDS
+#define RUC_NOP         0x0000
+#define	RUC_START       0x0001
+#define	RUC_RESUME      0x0002
+#define RUC_ABORT       0x0004
+#define	RUC_ADDR_LOAD   0x0006          // (seems not to clear on acceptance)
+#define RUC_RESUMENR    0x0007
+
+#define CU_CMD_MASK     0x00f0
+#define RU_CMD_MASK     0x0007
+
+#define SCB_M	        0x0100          // 0 = enable interrupt, 1 = disable
+#define SCB_SI          0x0200          // 1 - cause device to interrupt
+
+#define CU_STATUS_MASK  0x00C0
+#define RU_STATUS_MASK  0x003C
+
+#define RU_STATUS_IDLE  (0<<2)
+#define RU_STATUS_SUS   (1<<2)
+#define RU_STATUS_NORES (2<<2)
+#define RU_STATUS_READY (4<<2)
+#define RU_STATUS_NO_RBDS_SUS   ((1<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_NORES ((2<<2)|(8<<2))
+#define RU_STATUS_NO_RBDS_READY ((4<<2)|(8<<2))
+
+#define MAX_MEM_RESERVED_IOCTL 1000
+
+// ------------------------------------------------------------------------
+//
+//               RECEIVE FRAME DESCRIPTORS
+//
+// ------------------------------------------------------------------------
+
+// The status is split into two shorts to get atomic access to the EL bit;
+// the upper word is not written by the device, so we can just hit it,
+// leaving the lower word (which the device updates) alone.  Otherwise
+// there's a race condition between software moving the end-of-list (EL)
+// bit round and the device writing into the previous slot.
+
+#if (CYG_BYTEORDER == CYG_MSBFIRST)
+
+#define RFD_STATUS       0
+#define RFD_STATUS_HI    2              // swapped
+#define RFD_STATUS_LO    0              // swapped
+#define RFD_LINK         4
+#define RFD_RDB_ADDR     8
+#define RFD_SIZE        14              // swapped
+#define RFD_COUNT       12              // swapped
+#define RFD_BUFFER      16
+#define RFD_SIZEOF      16
+
+// Note that status bits are endian converted - so we don't need to
+// fiddle the byteorder when accessing the status word!
+#define RFD_STATUS_EL   0x00000080      // 1=last RFD in RFA
+#define RFD_STATUS_S    0x00000040      // 1=suspend RU after receiving frame
+#define RFD_STATUS_H    0x00001000      // 1=RFD is a header RFD
+#define RFD_STATUS_SF   0x00000800      // 0=simplified, 1=flexible mode
+#define RFD_STATUS_C    0x00800000      // completion of received frame
+#define RFD_STATUS_OK   0x00200000      // frame received with no errors
+
+#define RFD_STATUS_HI_EL   0x0080       // 1=last RFD in RFA
+#define RFD_STATUS_HI_S    0x0040       // 1=suspend RU after receiving frame
+#define RFD_STATUS_HI_H    0x1000       // 1=RFD is a header RFD
+#define RFD_STATUS_HI_SF   0x0800       // 0=simplified, 1=flexible mode
+
+#define RFD_STATUS_LO_C    0x0080       // completion of received frame
+#define RFD_STATUS_LO_OK   0x0020       // frame received with no errors
+
+
+#define RFD_COUNT_MASK     0x3fff
+#define RFD_COUNT_F        0x4000
+#define RFD_COUNT_EOF      0x8000
+
+#define RFD_RX_CRC          0x00080000  // crc error
+#define RFD_RX_ALIGNMENT    0x00040000  // alignment error
+#define RFD_RX_RESOURCE     0x00020000  // out of space, no resources
+#define RFD_RX_DMA_OVER     0x00010000  // DMA overrun
+#define RFD_RX_SHORT        0x80000000  // short frame error
+#define RFD_RX_LENGTH       0x20000000  //
+#define RFD_RX_ERROR        0x10000000  // receive error
+#define RFD_RX_NO_ADR_MATCH 0x04000000  // no address match
+#define RFD_RX_IA_MATCH     0x02000000  // individual address does not match
+#define RFD_RX_TCO          0x01000000  // TCO indication
+
+#else // Little-endian
+
+#define RFD_STATUS       0
+#define RFD_STATUS_HI    0
+#define RFD_STATUS_LO    2
+#define RFD_LINK         4
+#define RFD_RDB_ADDR     8
+#define RFD_SIZE        12
+#define RFD_COUNT       14
+#define RFD_BUFFER      16
+
+#define RFD_STATUS_EL   0x80000000      // 1=last RFD in RFA
+#define RFD_STATUS_S    0x40000000      // 1=suspend RU after receiving frame
+#define RFD_STATUS_H    0x00100000      // 1=RFD is a header RFD
+#define RFD_STATUS_SF   0x00080000      // 0=simplified, 1=flexible mode
+#define RFD_STATUS_C    0x00008000      // completion of received frame
+#define RFD_STATUS_OK   0x00002000      // frame received with no errors
+
+#define RFD_STATUS_HI_EL   0x8000       // 1=last RFD in RFA
+#define RFD_STATUS_HI_S    0x4000       // 1=suspend RU after receiving frame
+#define RFD_STATUS_HI_H    0x0010       // 1=RFD is a header RFD
+#define RFD_STATUS_HI_SF   0x0008       // 0=simplified, 1=flexible mode
+
+#define RFD_STATUS_LO_C    0x8000       // completion of received frame
+#define RFD_STATUS_LO_OK   0x2000       // frame received with no errors
+
+#define RFD_COUNT_MASK     0x3fff
+#define RFD_COUNT_F        0x4000
+#define RFD_COUNT_EOF      0x8000
+
+#define RFD_RX_CRC          0x00000800  // crc error
+#define RFD_RX_ALIGNMENT    0x00000400  // alignment error
+#define RFD_RX_RESOURCE     0x00000200  // out of space, no resources
+#define RFD_RX_DMA_OVER     0x00000100  // DMA overrun
+#define RFD_RX_SHORT        0x00000080  // short frame error
+#define RFD_RX_LENGTH       0x00000020  //
+#define RFD_RX_ERROR        0x00000010  // receive error
+#define RFD_RX_NO_ADR_MATCH 0x00000004  // no address match
+#define RFD_RX_IA_MATCH     0x00000002  // individual address does not match
+#define RFD_RX_TCO          0x00000001  // TCO indication
+
+#endif // CYG_BYTEORDER
+
+// ------------------------------------------------------------------------
+//
+//               TRANSMIT FRAME DESCRIPTORS
+//
+// ------------------------------------------------------------------------
+
+#if (CYG_BYTEORDER == CYG_MSBFIRST)
+
+#define TxCB_CMD             2          // swapped
+#define TxCB_STATUS          0          // swapped
+#define TxCB_LINK            4
+#define TxCB_TBD_ADDR        8
+#define TxCB_TX_THRESHOLD   14          // swapped
+#define TxCB_TBD_NUMBER     15          // swapped
+#define TxCB_COUNT          12          // swapped
+#define TxCB_BUFFER         16
+#define TxCB_SIZEOF         16
+
+// Note that CMD/STATUS bits are endian converted - so we don't need
+// to fiddle the byteorder when accessing the CMD/STATUS word!
+
+#define TxCB_CMD_TRANSMIT   0x0400      // transmit command
+#define TxCB_CMD_SF         0x0800      // 0=simplified, 1=flexible mode
+#define TxCB_CMD_NC         0x0010      // 0=CRC insert by controller
+#define TxCB_CMD_I          0x0020      // generate interrupt on completion
+#define TxCB_CMD_S          0x0040      // suspend on completion
+#define TxCB_CMD_EL         0x0080      // last command block in CBL
+
+#define TxCB_COUNT_MASK     0x3fff
+#define TxCB_COUNT_EOF      0x8000
+
+#else // Little-endian layout
+
+#define TxCB_CMD             0
+#define TxCB_STATUS          2
+#define TxCB_LINK            4
+#define TxCB_TBD_ADDR        8
+#define TxCB_TBD_NUMBER     12
+#define TxCB_TX_THRESHOLD   13
+#define TxCB_COUNT          14
+#define TxCB_BUFFER         16
+
+#define TxCB_COUNT_MASK     0x3fff
+#define TxCB_COUNT_EOF      0x8000
+
+#define TxCB_CMD_TRANSMIT   0x0004      // transmit command
+#define TxCB_CMD_SF         0x0008      // 0=simplified, 1=flexible mode
+#define TxCB_CMD_NC         0x0010      // 0=CRC insert by controller
+#define TxCB_CMD_I          0x2000      // generate interrupt on completion
+#define TxCB_CMD_S          0x4000      // suspend on completion
+#define TxCB_CMD_EL         0x8000      // last command block in CBL
+
+#endif // CYG_BYTEORDER
+
+// ------------------------------------------------------------------------
+//
+//                   STRUCTURES ADDED FOR PROMISCUOUS MODE
+//
+// ------------------------------------------------------------------------
+
+#if (CYG_BYTEORDER == CYG_MSBFIRST)
+
+#define CFG_STATUS          0
+#define CFG_CMD             2
+#define CFG_CB_LINK_OFFSET  4
+#define CFG_BYTES           8
+#define CFG_SIZEOF          32
+
+// Note CFG CMD and STATUS swapped, so no need for endian conversion
+// in code.
+#define CFG_CMD_EL         0x0080
+#define CFG_CMD_SUSPEND    0x0040
+#define CFG_CMD_INT        0x0020
+#define CFG_CMD_IAS        0x0100       // individual address setup
+#define CFG_CMD_CONFIGURE  0x0200       // configure
+
+#define CFG_STATUS_C       0x0080
+#define CFG_STATUS_OK      0x0020
+
+#else // Little-endian 
+
+#define CFG_CMD             0
+#define CFG_STATUS          2
+#define CFG_CB_LINK_OFFSET  4
+#define CFG_BYTES           8
+#define CFG_SIZEOF          32
+
+#define CFG_CMD_EL         0x8000
+#define CFG_CMD_SUSPEND    0x4000
+#define CFG_CMD_INT        0x2000
+#define CFG_CMD_IAS        0x0001       // individual address setup
+#define CFG_CMD_CONFIGURE  0x0002       // configure
+
+#define CFG_STATUS_C       0x8000
+#define CFG_STATUS_OK      0x2000
+
+#endif  // CYG_BYTEORDER
+
+
+// ------------------------------------------------------------------------
+//
+//                       STATISTICAL COUNTER STRUCTURE
+//
+// ------------------------------------------------------------------------
+#ifdef KEEP_STATISTICS
+STATISTICS statistics[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
+I82559_COUNTERS i82559_counters[CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT];
+#endif // KEEP_STATISTICS
+
+// ------------------------------------------------------------------------
+//
+//                      DEVICES AND PACKET QUEUES
+//
+// ------------------------------------------------------------------------
+
+#define MAX_RX_PACKET_SIZE  1536        // maximum Rx packet size
+#define MAX_TX_PACKET_SIZE  1536        // maximum Tx packet size
+
+
+// ------------------------------------------------------------------------
+// Use arrays provided by platform header to verify pointers.
+#ifdef CYGDBG_USE_ASSERTS
+#define CHECK_NDP_SC_LINK()                                             \
+    CYG_MACRO_START                                                     \
+    int i, valid_netdev = 0, valid_sc = 0;                              \
+    for(i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT; i++) {       \
+        if (i82559_netdev_array[i] == ndp) valid_netdev = 1;            \
+        if (i82559_sc_array[i] == sc) valid_sc = 1;                     \
+        if (valid_sc || valid_netdev) break;                            \
+    }                                                                   \
+    CYG_ASSERT( valid_netdev, "Bad ndp" );                              \
+    CYG_ASSERT( valid_sc, "Bad sc" );                                   \
+    CYG_ASSERT( (void *)p_i82559 == i82559_sc_array[i]->driver_private, \
+                "sc pointer bad" );                                     \
+    CYG_MACRO_END
+#else
+#define CHECK_NDP_SC_LINK()
+#endif
+
+#define IF_BAD_82559( _p_ )                                             \
+if (({                                                                  \
+    int i, valid_p = 0;                                                 \
+    for(i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT; i++) {       \
+        if (i82559_priv_array[i] == (_p_)) {                            \
+            valid_p = 1;                                                \
+            break;                                                      \
+        }                                                               \
+    }                                                                   \
+    CYG_ASSERT(valid_p, "Bad pointer-to-i82559");                       \
+    (!valid_p);                                                         \
+}))
+
+// ------------------------------------------------------------------------
+//
+// Managing the memory that is windowed onto the PCI bus
+//
+// ------------------------------------------------------------------------
+
+static cyg_uint32 i82559_heap_size;
+static cyg_uint8 *i82559_heap_base;
+static cyg_uint8 *i82559_heap_free;
+
+static void *mem_reserved_ioctl = (void*)0;
+// uncacheable memory reserved for ioctl calls
+
+// ------------------------------------------------------------------------
+//
+//                       FUNCTION PROTOTYPES
+//
+// ------------------------------------------------------------------------
+
+static int pci_init_find_82559s(void);
+
+static void i82559_reset(struct i82559* p_i82559);
+static int eth_set_mac_address(struct i82559* p_i82559, char *addr);
+
+static void InitRxRing(struct i82559* p_i82559);
+static void ResetRxRing(struct i82559* p_i82559);
+static void InitTxRing(struct i82559* p_i82559);
+static void ResetTxRing(struct i82559* p_i82559);
+
+static int eth_set_config(struct i82559* p_i82559);
+
+#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+static void program_eeprom(cyg_uint32 , cyg_uint32 , cyg_uint8 * );
+#endif
+#ifdef CYGPKG_NET
+static int eth_set_promiscuous_mode(struct i82559* p_i82559);
+#endif
+
+// debugging/logging only:
+void dump_txcb(TxCB* p_txcb);
+void DisplayStatistics(void);
+void update_statistics(struct i82559* p_i82559);
+void dump_rfd(RFD* p_rfd, int anyway );
+void dump_all_rfds( int intf );
+void dump_packet(cyg_uint8 *p_buffer, int length);
+
+// ------------------------------------------------------------------------
+// utilities
+// ------------------------------------------------------------------------
+
+typedef enum {
+    WAIT_RU,                            // wait before RU cmd
+    WAIT_CU                             // wait before CU cmd
+} cmd_wait_t;
+
+static // inline
+void 
+wait_for_cmd_done(long scb_ioaddr, cmd_wait_t type)
+{
+    register int status;
+    register int wait;
+
+#ifdef nDEBUG_82559
+    os_printf(">%s %04x\n", __FUNCTION__, INW(scb_ioaddr + SCBCmd));
+#endif
+    wait = 0x100000;
+    do status = INW(scb_ioaddr + SCBCmd) ;
+    while( (0 != ((CU_CMD_MASK | RU_CMD_MASK) & status)) && --wait >= 0);
+#ifdef nDEBUG_82559
+    os_printf(">%s %04x\n", __FUNCTION__, INW(scb_ioaddr + SCBCmd));
+#endif
+    CYG_ASSERT( wait > 0, "wait_for_cmd_done: cmd busy" );
+
+    if (WAIT_CU == type) {
+        // Also check CU is idle
+#ifdef nDEBUG_82559
+      os_printf(">%s %04x\n", __FUNCTION__, INW(scb_ioaddr + SCBStatus));
+#endif
+        wait = 0x100000;
+        do status = INW(scb_ioaddr + SCBStatus) ;
+        while( (status & CU_STATUS_MASK) && --wait >= 0);
+#ifdef nDEBUG_82559
+        os_printf("<%s %04x\n", __FUNCTION__, INW(scb_ioaddr + SCBStatus));
+#endif
+        CYG_ASSERT( wait > 0, "wait_for_cmd_done: CU busy" );
+    } else if (WAIT_RU == type) {
+        // Can't see any active state in the doc to check for 
+    }
+}
+
+// Short circuit the drv_interrupt_XXX API once we are started:
+
+static inline int 
+Mask82559Interrupt(struct i82559* p_i82559)
+{
+    int old = 0;
+
+//    if (query_enabled)
+    old |= 1;
+    cyg_drv_interrupt_mask(p_i82559->vector);
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+//    if (query_enabled)
+    old |= 2;
+    cyg_drv_interrupt_mask(CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+#endif
+
+    /* it may prove necessary to do something like this
+    if ( mybits != (mybits & old) )
+        /# then at least one of them was disabled, so
+         # omit both from any restoration: #/
+        old = 0;
+    */
+
+    return old;
+}
+
+static inline void
+UnMask82559Interrupt(struct i82559* p_i82559, int old)
+{
+    // We must only unmask (enable) those which were unmasked before,
+    // according to the bits in old.
+    if (old & 1)
+        cyg_drv_interrupt_unmask(p_i82559->vector);
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+    if (old & 2)
+        cyg_drv_interrupt_mask(CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+#endif
+}
+
+static void
+Acknowledge82559Interrupt(struct i82559* p_i82559)
+{
+    cyg_drv_interrupt_acknowledge(p_i82559->vector);
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+    cyg_drv_interrupt_acknowledge(CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+#endif
+
+#ifdef CYGPRI_DEVS_ETH_INTEL_I82559_INTERRUPT_ACK_LOOP
+    CYGPRI_DEVS_ETH_INTEL_I82559_INTERRUPT_ACK_LOOP(p_i82559);
+#endif
+}
+
+
+externC void hal_delay_us(int);
+static void
+udelay(int delay)
+{
+    hal_delay_us(delay);
+}
+
+// ------------------------------------------------------------------------
+// Memory management
+//
+// Simply carve off from the front of the PCI mapped window into real memory
+
+static void*
+pciwindow_mem_alloc(int size)
+{
+    void *p_memory;
+    int _size = size;
+
+    CYG_ASSERT(
+        (CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE <= (int)i82559_heap_free)
+        &&
+        ((CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE + 
+          CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE) > (int)i82559_heap_free)
+        &&
+        (0 < i82559_heap_size)
+        &&
+        (CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE >= i82559_heap_size)
+        &&
+        (CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE == (int)i82559_heap_base),
+        "Heap variables corrupted" );
+
+    p_memory = (void *)0;
+    size = (size + 3) & ~3;
+    if ( (i82559_heap_free+size) < (i82559_heap_base+i82559_heap_size) ) {
+        cyg_uint32 *p;
+        p_memory = (void *)i82559_heap_free;
+        i82559_heap_free += size;
+        for ( p = (cyg_uint32 *)p_memory; _size > 0; _size -= 4 )
+            *p++ = 0;
+    }
+
+    return p_memory;
+}
+
+
+// ------------------------------------------------------------------------
+//
+//                       GET EEPROM SIZE
+//
+// ------------------------------------------------------------------------
+static int
+get_eeprom_size(long ioaddr)
+{
+    unsigned short retval = 0;
+    int ee_addr = ioaddr + SCBeeprom;
+    int i, addrbits;
+
+    // Should already be not-selected, but anyway:
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(EEPROM_ENABLE_DELAY);
+    OUTW(EE_ENB, ee_addr);
+    eeprom_delay(EEPROM_ENABLE_DELAY);
+    
+    // Shift the read command bits out.
+    for (i = 2; i >= 0; i--) {
+        short dataval = (6 & (1 << i)) ? EE_DATA_WRITE : 0;
+        OUTW(EE_ENB | dataval               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB | dataval               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+    }
+    // Now clock out address zero, looking for the dummy 0 data bit
+    for ( i = 1; i <= 12; i++ ) {
+        OUTW(EE_ENB               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        retval = INW(ee_addr) & EE_DATA_READ;
+        if ( 0 == retval )
+            break; // The dummy zero est arrive'
+    }
+
+#ifdef DEBUG_EE
+    os_printf( "eeprom data bits %d (ioaddr %x)\n", i, ee_addr );
+#endif
+    
+    if ( 6 != i && 8 != i && 1 != i) {
+#ifdef DEBUG_EE
+        os_printf( "*****EEPROM data bits not 6, 8 or 1*****\n" );
+#endif
+        i = 6;
+    }
+    addrbits = i;
+
+    // clear the dataval, leave the clock low to read in the data regardless
+    OUTW(EE_ENB, ee_addr);
+    eeprom_delay(1);
+    
+    retval = INW(ee_addr);
+    if ( (EE_DATA_READ & retval) != 0 ) {
+#ifdef DEBUG_EE
+        os_printf( "Size EEPROM: Dummy data bit not 0, reg %x\n" , retval );
+#endif
+    }
+    eeprom_delay(1);
+    
+    for (i = EE_TOP_DATA_BIT; i >= 0; i--) {
+        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        retval = INW(ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+    }
+    
+    // Terminate the EEPROM access.
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(EEPROM_DONE_DELAY);
+    
+    return addrbits;
+}
+
+
+// ------------------------------------------------------------------------
+//
+//                       READ EEPROM
+//
+// ------------------------------------------------------------------------
+static int
+read_eeprom(long ioaddr, int location, int addr_len)
+{
+    unsigned short retval = 0;
+    int ee_addr = ioaddr + SCBeeprom;
+    int read_cmd = location | EE_READ_CMD(addr_len);
+    int i, tries = 10;
+
+ try_again:
+    // Should already be not-selected, but anyway:
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(EEPROM_ENABLE_DELAY);
+    OUTW(EE_ENB, ee_addr);
+    eeprom_delay(EEPROM_ENABLE_DELAY);
+    
+    // Shift the read command bits out, changing only one bit per time.
+    for (i = EE_TOP_CMD_BIT(addr_len); i >= 0; i--) {
+        short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+        OUTW(EE_ENB | dataval               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB | dataval               , ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+    }
+
+    // clear the dataval, leave the clock low
+    OUTW(EE_ENB, ee_addr);
+    eeprom_delay(1);
+    
+    retval = INW(ee_addr);
+    // This should show a zero in the data read bit to confirm that the
+    // address transfer is compelete.  If not, go to the start and try
+    // again!
+    if ( (0 != (retval & EE_DATA_READ)) && (tries-- > 0) ) {
+    // Terminate the EEPROM access.
+        OUTW(EE_ENB & ~EE_CS, ee_addr);
+        eeprom_delay(EEPROM_DONE_DELAY);
+#ifdef DEBUG_EE
+        os_printf( "Warning: Retrying EEPROM read word %d, address %x, try %d\n",
+                   location,  ee_addr, tries+1 );
+#endif
+        goto try_again;
+    }
+
+    // This fires with one device on one of the customer boards!
+    // (but is OK on all other h/w.  Worrying huh.)
+    if ( (EE_DATA_READ & retval) != 0 ) {
+#ifdef DEBUG_EE
+        os_printf( "Read EEPROM: Dummy data bit not 0, reg %x\n" , retval );
+#endif
+    }
+    eeprom_delay(1);
+    retval = 0;
+
+    for (i = EE_TOP_DATA_BIT; i >= 0; i--) {
+        OUTW(EE_ENB | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+        retval = (retval << 1) | ((INW(ee_addr) & EE_DATA_READ) ? 1 : 0);
+        eeprom_delay(EEPROM_SK_DELAY);
+        OUTW(EE_ENB, ee_addr);
+        eeprom_delay(EEPROM_SK_DELAY);
+    }
+    
+    // Terminate the EEPROM access.
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(EEPROM_DONE_DELAY);
+    
+    return retval;
+}
+
+// ------------------------------------------------------------------------
+//
+//                NETWORK INTERFACE INITIALIZATION
+//
+//  Function : Init82559
+//
+//  Description :
+//       This routine resets, configures, and initializes the chip.
+//       It also clears the ethernet statistics structure, and selects
+//       which statistics are supported by this driver.
+//
+// ------------------------------------------------------------------------
+static bool
+i82559_init(struct cyg_netdevtab_entry * ndp)
+{
+    static int initialized = 0; // only probe PCI et al *once*
+
+    struct eth_drv_sc *sc;
+    cyg_uint32 selftest;
+    volatile cyg_uint32 *p_selftest;
+    cyg_uint32 ioaddr;
+    int count;
+    int ints;
+    struct i82559 *p_i82559;
+    cyg_uint8 mac_address[ETHER_ADDR_LEN];
+
+#ifdef DEBUG
+    db_printf("intel_i82559_init\n");
+#endif
+
+    sc = (struct eth_drv_sc *)(ndp->device_instance);
+    p_i82559 = (struct i82559 *)(sc->driver_private);
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "Bad device private pointer %x\n", sc->driver_private );
+#endif
+        return 0;
+    }
+
+    CHECK_NDP_SC_LINK();
+
+    if ( 0 == initialized++ ) {
+        // then this is the first time ever:
+        if ( ! pci_init_find_82559s() ) {
+#ifdef DEBUG
+            os_printf( "pci_init_find_82559s failed" );
+#endif
+            return 0;
+        }
+    }
+
+    // If this device is not present, exit
+    if (0 == p_i82559->found)
+        return 0;
+
+    ioaddr = p_i82559->io_address; // get I/O address for 82559
+
+#ifdef DEBUG
+    os_printf("Init82559 %d @ %x\n82559 Self Test\n",
+              p_i82559->index, (int)ndp);
+#endif
+
+    ints = Mask82559Interrupt(p_i82559);
+
+    // Reset device
+    i82559_reset(p_i82559);
+
+    // Perform a system self-test. (get enough mem to round address)
+    if ( (selftest = (cyg_uint32)pciwindow_mem_alloc(32) ) == 0)
+        return (0);
+    p_selftest = (cyg_uint32 *) ((selftest + 15) & ~0xf);
+    p_selftest[0] = p_selftest[1] = -1;
+
+    OUTL( (VIRT_TO_BUS(p_selftest)) | I82559_SELFTEST, ioaddr + SCBPort);
+    count = 0x7FFFF;                // Timeout for self-test.
+    do {
+        udelay(10);
+    } while ( (p_selftest[1] == -1)  &&  (--count >= 0) );
+
+    // Reset device again after selftest
+    i82559_reset(p_i82559);
+
+    Acknowledge82559Interrupt(p_i82559);
+    UnMask82559Interrupt(p_i82559, ints );
+    
+    if (count < 0) {
+        // Test timed out.
+#ifdef DEBUG
+        os_printf("Self test failed\n");
+#endif
+        return (0);
+    }
+#ifdef DEBUG
+    os_printf("  General self-test: %s.\n"
+              "  Serial sub-system self-test: %s.\n"
+              "  Internal registers self-test: %s.\n"
+              "  ROM checksum self-test: %s (%08X).\n",
+              HAL_LE32TOC(p_selftest[1]) & 0x1000 ? "failed" : "passed",
+              HAL_LE32TOC(p_selftest[1]) & 0x0020 ? "failed" : "passed",
+              HAL_LE32TOC(p_selftest[1]) & 0x0008 ? "failed" : "passed",
+              HAL_LE32TOC(p_selftest[1]) & 0x0004 ? "failed" : "passed",
+              HAL_LE32TOC(p_selftest[0]));
+#endif
+
+    // FIXME: free self-test memory?
+
+    if (p_i82559->hardwired_esa) {
+        // Hardwire the address without consulting the EEPROM.
+        // When this flag is set, the p_i82559 will already contain
+        // the ESA. Copy it to a mac_address for call to set_mac_addr
+        mac_address[0] = p_i82559->mac_address[0];
+        mac_address[1] = p_i82559->mac_address[1];
+        mac_address[2] = p_i82559->mac_address[2];
+        mac_address[3] = p_i82559->mac_address[3];
+        mac_address[4] = p_i82559->mac_address[4];
+        mac_address[5] = p_i82559->mac_address[5];
+
+        eth_set_mac_address(p_i82559, mac_address);
+    } else {
+        int addr_length, i;
+        cyg_uint16 checksum;
+
+        // read eeprom and get 82559's mac address
+        addr_length = get_eeprom_size(ioaddr);
+        // (this is the length of the *EEPROM*s address, not MAC address)
+
+        // If length is 1, it _probably_ means there's no EEPROM
+        // present.  Couldn't find an explicit mention of this in the
+        // docs, but length=1 appears to be the behaviour in that case.
+        if (1 == addr_length) {
+#ifdef DEBUG_EE
+            os_printf("Error: No EEPROM present for device %d\n", 
+                      p_i82559->index);
+#endif
+        } else {
+            for (checksum = 0, i = 0, count = 0; count < 64; count++) {
+                cyg_uint16 value;
+                // read word from eeprom
+                value = read_eeprom(ioaddr, count, addr_length);
+#ifdef DEBUG_EE
+                // os_printf( "%2d: %04x\n", count, value );
+#endif
+                checksum += value;
+                if (count < 3) {
+                    mac_address[i++] = value & 0xFF;
+                    mac_address[i++] = (value >> 8) & 0xFF;
+                }
+            }
+
+            // If the EEPROM checksum is wrong, the MAC address read
+            // from the EEPROM is probably wrong as well. In that
+            // case, we don't set mac_addr_ok, but continue the
+            // initialization. If then somebody calls i82559_start
+            // without calling eth_set_mac_address() first, we refuse
+            // to bring up the interface, because running with an
+            // invalid MAC address is not a very brilliant idea.
+        
+            if ((checksum & 0xFFFF) != 0xBABA)  {
+                // selftest verified checksum, verify again
+#ifdef DEBUG_EE
+                os_printf("Warning: Invalid EEPROM checksum %04X for device %d\n",
+                          checksum, p_i82559->index);
+#endif
+            } else {
+                p_i82559->mac_addr_ok = 1;
+#ifdef DEBUG_EE
+                os_printf("Valid EEPROM checksum\n");
+#endif
+            }
+        }
+
+        // record the MAC address in the device structure
+        p_i82559->mac_address[0] = mac_address[0];
+        p_i82559->mac_address[1] = mac_address[1];
+        p_i82559->mac_address[2] = mac_address[2];
+        p_i82559->mac_address[3] = mac_address[3];
+        p_i82559->mac_address[4] = mac_address[4];
+        p_i82559->mac_address[5] = mac_address[5];
+    }
+
+#ifdef DEBUG
+    os_printf("MAC Address = %02X %02X %02X %02X %02X %02X\n",
+              p_i82559->mac_address[0], p_i82559->mac_address[1],
+              p_i82559->mac_address[2], p_i82559->mac_address[3],
+              p_i82559->mac_address[4], p_i82559->mac_address[5]);
+#endif
+    
+    // and record the net dev pointer
+    p_i82559->ndp = (void *)ndp;
+    
+    InitRxRing(p_i82559);
+    InitTxRing(p_i82559);
+
+    // Initialize upper level driver
+    if ( p_i82559->mac_addr_ok )
+        (sc->funs->eth_drv->init)(sc, &(p_i82559->mac_address[0]) );
+    else
+        (sc->funs->eth_drv->init)(sc, NULL );
+
+    return (1);
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_start
+//
+// ------------------------------------------------------------------------
+static void 
+i82559_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
+{
+    struct i82559 *p_i82559;
+    cyg_uint32 ioaddr;
+    int count;
+    cyg_uint16 status;
+#ifdef KEEP_STATISTICS
+    void *p_statistics;
+#endif
+#ifdef CYGPKG_NET
+    struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+#endif
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+    ioaddr = p_i82559->io_address; // get 82559's I/O address
+    
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_start: Bad device pointer %x\n", p_i82559 );
+#endif
+        return;
+    }
+
+    if ( ! p_i82559->mac_addr_ok ) {
+#ifdef DEBUG
+        os_printf("i82559_start %d: invalid MAC address, "
+                  "can't bring up interface\n",
+                  p_i82559->index );
+#endif
+        return;
+    }
+
+    if ( p_i82559->active )
+        i82559_stop( sc );
+
+#ifdef KEEP_STATISTICS
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_STATISTICS
+    p_i82559->p_statistics =
+        p_statistics = pciwindow_mem_alloc(sizeof(I82559_COUNTERS));
+    memset(p_statistics, 0xFFFFFFFF, sizeof(I82559_COUNTERS));
+    // set statistics dump address
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTL(VIRT_TO_BUS(p_statistics), ioaddr + SCBPointer);
+    OUTW(SCB_M | CU_STATSADDR, ioaddr + SCBCmd);
+    // Start dump command
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTW(SCB_M | CU_DUMPSTATS, ioaddr + SCBCmd); // start register dump
+    // ...and wait for it to complete operation
+    count = 1000;
+    do {
+      HAL_READ_UINT16((cyg_uint8*)p_statistics + CFG_STATUS, status);
+      udelay(1);
+    } while (0 == (status & CFG_STATUS_C) && (count-- > 0));
+#ifdef CYGDBG_USE_ASSERTS
+    {
+      HAL_READ_UINT16((cyg_uint8*)p_statistics + CFG_STATUS, status);
+      CYG_ASSERT((CFG_STATUS_C | CFG_STATUS_OK)
+                 == (status & (CFG_STATUS_C | CFG_STATUS_OK)),
+                 "Dump stat command incomplete/failedd");
+    }
+#endif // CYGDBG_USE_ASSERTS
+#endif
+#endif
+
+    // Enable device
+    p_i82559->active = 1;
+    eth_set_config(p_i82559);
+
+#ifdef CYGPKG_NET
+    if (( 0
+#ifdef ETH_DRV_FLAGS_PROMISC_MODE
+          != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
+#endif
+        ) || (ifp->if_flags & IFF_PROMISC)
+        ) {
+        eth_set_promiscuous_mode(p_i82559);
+    }
+#endif
+#ifdef DEBUG
+    {
+        int status = i82559_status( sc );
+        os_printf("i82559_start %d flg %x Link = %s, %s Mbps, %s Duplex\n",
+                  p_i82559->index,
+                  *(int *)p_i82559,
+                  status & GEN_STATUS_LINK ? "Up" : "Down",
+                  status & GEN_STATUS_100MBPS ?  "100" : "10",
+                  status & GEN_STATUS_FDX ? "Full" : "Half");
+    }
+#endif
+
+    // Load pointer to Rx Ring and enable receiver
+    wait_for_cmd_done(ioaddr, WAIT_RU);
+    OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]), ioaddr + SCBPointer);
+    OUTW(RUC_START, ioaddr + SCBCmd);
+   
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_status
+//
+// ------------------------------------------------------------------------
+int
+i82559_status( struct eth_drv_sc *sc )
+{
+    int status;
+    struct i82559 *p_i82559;
+    cyg_uint32 ioaddr;
+    p_i82559 = (struct i82559 *)sc->driver_private;
+    
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_status: Bad device pointer %x\n", p_i82559 );
+#endif
+        return 0;
+    }
+
+    ioaddr = p_i82559->io_address; // get 82559's I/O address
+
+    status = INB(ioaddr + SCBGenStatus);
+
+    return status;
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : BringDown82559
+//
+// ------------------------------------------------------------------------
+
+static void
+i82559_stop( struct eth_drv_sc *sc )
+{
+    struct i82559 *p_i82559;
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_stop: Bad device pointer %x\n", p_i82559 );
+#endif
+        return;
+    }
+   
+#ifdef DEBUG
+    os_printf("i82559_stop %d flg %x\n", p_i82559->index, *(int *)p_i82559 );
+#endif
+
+    p_i82559->active = 0;               // stop people tormenting it
+    i82559_reset(p_i82559);             // that should stop it
+
+    ResetRxRing( p_i82559 );
+    ResetTxRing( p_i82559 );
+}
+
+
+// ------------------------------------------------------------------------
+//
+//  Function : InitRxRing
+//
+// ------------------------------------------------------------------------
+static void
+InitRxRing(struct i82559* p_i82559)
+{
+    int i;
+    RFD *rfd;
+    RFD *p_rfd = 0;
+#ifdef DEBUG_82559
+    os_printf("InitRxRing %d\n", p_i82559->index);
+#endif
+    for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) {
+        rfd = (RFD *)pciwindow_mem_alloc(RFD_SIZEOF + MAX_RX_PACKET_SIZE);
+        p_i82559->rx_ring[i] = rfd;
+        if ( i )
+            HAL_WRITE_UINT32(p_rfd+RFD_LINK, HAL_CTOLE32(VIRT_TO_BUS(rfd)));
+        p_rfd = (RFD *)rfd;
+    }
+    // link last RFD to first:
+    HAL_WRITE_UINT32(p_rfd+RFD_LINK,
+                     HAL_CTOLE32(VIRT_TO_BUS(p_i82559->rx_ring[0])));
+
+    ResetRxRing( p_i82559 );
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : ResetRxRing
+//
+// ------------------------------------------------------------------------
+static void
+ResetRxRing(struct i82559* p_i82559)
+{
+    RFD *p_rfd;
+    int i;
+#ifdef DEBUG_82559
+    os_printf("ResetRxRing %d\n", p_i82559->index);
+#endif
+    for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ ) {
+        p_rfd = p_i82559->rx_ring[i];
+        CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
+        CYG_ASSERT( (cyg_uint8 *)p_rfd <  i82559_heap_free, "rfd over" );
+#ifdef CYGDBG_USE_ASSERTS
+        {
+          RFD *p_rfd2;
+          cyg_uint32 link;
+          p_rfd2 = p_i82559->rx_ring[ ( i ? (i-1) : (MAX_RX_DESCRIPTORS-1) ) ];
+          HAL_READ_UINT32(p_rfd2 + RFD_LINK, link);
+          CYG_ASSERT( HAL_LE32TOC(link) == VIRT_TO_BUS(p_rfd), 
+                      "rfd linked list broken" );
+        }
+#endif
+        HAL_WRITE_UINT32(p_rfd + RFD_STATUS, /*0*/RFD_STATUS_S);
+        HAL_WRITE_UINT16(p_rfd + RFD_COUNT, 0);
+        HAL_WRITE_UINT32(p_rfd + RFD_RDB_ADDR, HAL_CTOLE32(0xFFFFFFFF));
+        HAL_WRITE_UINT16(p_rfd + RFD_SIZE, HAL_CTOLE16(MAX_RX_PACKET_SIZE));
+    }
+    p_i82559->next_rx_descriptor = 0;
+    // And set an end-of-list marker in the previous one.
+    HAL_WRITE_UINT32(p_rfd + RFD_STATUS, RFD_STATUS_EL);
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : PacketRxReady        (Called from delivery thread)
+//
+// ------------------------------------------------------------------------
+static void
+PacketRxReady(struct i82559* p_i82559)
+{
+    RFD *p_rfd;
+    int next_descriptor;
+    int length, ints;
+    struct cyg_netdevtab_entry *ndp;
+    struct eth_drv_sc *sc;
+    cyg_uint32 ioaddr;
+    cyg_uint16 status;
+
+    ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp);
+    sc = (struct eth_drv_sc *)(ndp->device_instance);
+
+    CHECK_NDP_SC_LINK();
+
+    ioaddr = p_i82559->io_address;
+
+    next_descriptor = p_i82559->next_rx_descriptor;
+    p_rfd = p_i82559->rx_ring[next_descriptor];
+
+    CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
+    CYG_ASSERT( (cyg_uint8 *)p_rfd <  i82559_heap_free, "rfd over" );
+
+    while ( 1 ) {
+        cyg_uint32 rxstatus;
+        cyg_uint16 rxstatus_hi;
+        HAL_READ_UINT32(p_rfd + RFD_STATUS, rxstatus);
+        if (0 == (rxstatus & RFD_STATUS_C))
+            break;
+
+        HAL_READ_UINT16(p_rfd + RFD_STATUS_HI, rxstatus_hi);
+        rxstatus_hi |= RFD_STATUS_HI_EL;
+        HAL_WRITE_UINT16(p_rfd + RFD_STATUS_HI, rxstatus_hi);
+
+        HAL_READ_UINT16(p_rfd + RFD_COUNT, length);
+        length = HAL_LE16TOC(length);
+        length &= RFD_COUNT_MASK;
+
+#ifdef DEBUG_82559
+        os_printf( "Device %d (eth%d), rx descriptor %d:\n", 
+                   p_i82559->index, p_i82559->index, next_descriptor );
+//        dump_rfd( p_rfd, 1 );
+#endif
+
+        p_i82559->next_rx_descriptor = next_descriptor;
+        // Check for bogusly short packets; can happen in promisc mode:
+        // Asserted against and checked by upper layer driver.
+#ifdef CYGPKG_NET
+        if ( length > sizeof( struct ether_header ) )
+            // then it is acceptable; offer the data to the network stack
+#endif
+        (sc->funs->eth_drv->recv)( sc, length );
+
+        HAL_WRITE_UINT16(p_rfd + RFD_COUNT, 0);
+        HAL_WRITE_UINT16(p_rfd + RFD_STATUS_LO, 0);
+
+        // The just-emptied slot is now ready for re-use and already marked EL;
+        // we can now remove the EL marker from the previous one.
+        if ( 0 == next_descriptor )
+            p_rfd = p_i82559->rx_ring[ MAX_RX_DESCRIPTORS-1 ];
+        else
+            p_rfd = p_i82559->rx_ring[ next_descriptor-1 ];
+        // The previous one: check it *was* marked before clearing.
+        HAL_READ_UINT16(p_rfd + RFD_STATUS_HI, rxstatus_hi);
+        CYG_ASSERT( rxstatus_hi & RFD_STATUS_HI_EL, "No prev EL" );
+        // that word is not written by the device.
+        HAL_WRITE_UINT16(p_rfd + RFD_STATUS_HI, 0);
+
+#ifdef KEEP_STATISTICS
+        statistics[p_i82559->index].rx_deliver++;
+#endif
+        if (++next_descriptor >= MAX_RX_DESCRIPTORS)
+            next_descriptor = 0;
+        p_rfd = p_i82559->rx_ring[next_descriptor];
+
+        CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
+        CYG_ASSERT( (cyg_uint8 *)p_rfd <  i82559_heap_free, "rfd over" );
+
+    }
+
+    // See if the RU has gone idle (usually because of out of resource
+    // condition) and restart it if needs be.
+    ints = Mask82559Interrupt(p_i82559);
+    status = INW(ioaddr + SCBStatus);
+    if ( RU_STATUS_READY != (status & RU_STATUS_MASK) ) {
+        // Acknowledge the RX INT sources
+        OUTW( SCB_INTACK_RX, ioaddr + SCBStatus);
+        // (see pages 6-10 & 6-90)
+
+#ifdef KEEP_STATISTICS
+        statistics[p_i82559->index].rx_restart++;
+#endif
+        // There's an end-of-list marker out there somewhere...
+        // So mop it up; it takes a little time but this is infrequent.
+        ResetRxRing( p_i82559 );  
+        next_descriptor = 0;        // re-initialize next desc.
+        // load pointer to Rx Ring
+        wait_for_cmd_done(ioaddr, WAIT_RU);
+        OUTL(VIRT_TO_BUS(p_i82559->rx_ring[0]),
+             ioaddr + SCBPointer);
+        OUTW(RUC_START, ioaddr + SCBCmd);
+        Acknowledge82559Interrupt(p_i82559);
+    }
+    UnMask82559Interrupt(p_i82559, ints);
+
+    p_i82559->next_rx_descriptor = next_descriptor;
+}
+
+// and the callback function
+
+static void 
+i82559_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
+{
+    struct i82559 *p_i82559;
+    RFD *p_rfd;
+    int next_descriptor;
+    int total_len;
+    struct eth_drv_sg *last_sg;
+    volatile cyg_uint8 *from_p;
+    cyg_uint32 rxstatus;
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+    
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_recv: Bad device pointer %x\n", p_i82559 );
+#endif
+        return;
+    }
+
+    next_descriptor = p_i82559->next_rx_descriptor;
+    p_rfd = p_i82559->rx_ring[next_descriptor];
+    
+    CYG_ASSERT( (cyg_uint8 *)p_rfd >= i82559_heap_base, "rfd under" );
+    CYG_ASSERT( (cyg_uint8 *)p_rfd <  i82559_heap_free, "rfd over" );
+
+    HAL_READ_UINT32(p_rfd + RFD_STATUS, rxstatus);
+    CYG_ASSERT( rxstatus & RFD_STATUS_C, "No complete frame" );
+    CYG_ASSERT( rxstatus & RFD_STATUS_EL, "No marked frame" );
+    CYG_ASSERT( rxstatus & RFD_STATUS_C, "No complete frame 2" );
+    CYG_ASSERT( rxstatus & RFD_STATUS_EL, "No marked frame 2" );
+    
+    if ( 0 == (rxstatus & RFD_STATUS_C) )
+        return;
+
+    HAL_READ_UINT16(p_rfd + RFD_COUNT, total_len);
+    total_len = HAL_LE16TOC(total_len);
+    total_len &= RFD_COUNT_MASK;
+    
+#ifdef DEBUG_82559
+    os_printf("Rx %d %x (status %x): %d sg's, %d bytes\n",
+              p_i82559->index, (int)p_i82559, 
+              HAL_LE32TOC(rxstatus), sg_len, total_len);
+#endif
+
+    // Copy the data to the network stack
+    from_p = p_rfd + RFD_BUFFER;
+
+    // check we have memory to copy into; we would be called even if
+    // caller was out of memory in order to maintain our state.
+    if ( 0 == sg_len || 0 == sg_list )
+        return; // caller was out of mbufs
+
+    CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
+    CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
+
+    for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
+        cyg_uint8 *to_p;
+        int l;
+            
+        to_p = (cyg_uint8 *)(sg_list->buf);
+        l = sg_list->len;
+
+        CYG_ASSERT( 0 <= l, "sg length -ve" );
+
+        if ( 0 >= l || 0 == to_p )
+            return; // caller was out of mbufs
+
+        if ( l > total_len )
+            l = total_len;
+
+        memcpy( to_p, (unsigned char *)from_p, l );
+        from_p += l;
+        total_len -= l;
+    }
+
+    CYG_ASSERT( 0 == total_len, "total_len mismatch in rx" );
+    CYG_ASSERT( last_sg == sg_list, "sg count mismatch in rx" );
+    CYG_ASSERT( p_rfd + RFD_BUFFER < from_p, "from_p wild in rx" );
+    CYG_ASSERT( p_rfd + RFD_BUFFER + MAX_RX_PACKET_SIZE >= from_p,
+                "from_p overflow in rx" );
+}
+
+
+// ------------------------------------------------------------------------
+//
+//  Function : InitTxRing
+//
+// ------------------------------------------------------------------------
+static void
+InitTxRing(struct i82559* p_i82559)
+{
+    int i;
+    cyg_uint32 ioaddr;
+
+#ifdef DEBUG_82559
+    os_printf("InitTxRing %d\n", p_i82559->index);
+#endif
+    ioaddr = p_i82559->io_address;
+    for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
+        p_i82559->tx_ring[i] = (TxCB *)pciwindow_mem_alloc(
+            TxCB_SIZEOF + MAX_TX_PACKET_SIZE);
+    }
+
+    ResetTxRing(p_i82559);
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : ResetTxRing
+//
+// ------------------------------------------------------------------------
+static void
+ResetTxRing(struct i82559* p_i82559)
+{
+    int i;
+    cyg_uint32 ioaddr;
+
+#ifdef DEBUG_82559
+    os_printf("ResetTxRing %d\n", p_i82559->index);
+#endif
+    ioaddr = p_i82559->io_address;
+    p_i82559->tx_descriptor_add =
+        p_i82559->tx_descriptor_active = 
+        p_i82559->tx_descriptor_remove = 0;
+    p_i82559->tx_in_progress =
+        p_i82559->tx_queue_full = 0;
+
+    for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
+        TxCB *p_txcb = p_i82559->tx_ring[i];
+        CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
+        CYG_ASSERT( (cyg_uint8 *)p_txcb <  i82559_heap_free, "txcb over" );
+
+        HAL_WRITE_UINT16(p_txcb + TxCB_STATUS, 0);
+        HAL_WRITE_UINT16(p_txcb + TxCB_CMD, 0);
+        HAL_WRITE_UINT32(p_txcb + TxCB_LINK,
+                         HAL_CTOLE32(VIRT_TO_BUS((cyg_uint32)p_txcb)));
+        HAL_WRITE_UINT32(p_txcb + TxCB_TBD_ADDR, HAL_CTOLE32(0xFFFFFFFF));
+        HAL_WRITE_UINT8(p_txcb + TxCB_TBD_NUMBER, 0);
+        HAL_WRITE_UINT8(p_txcb + TxCB_TX_THRESHOLD, 16);
+        HAL_WRITE_UINT16(p_txcb + TxCB_COUNT,
+                         HAL_CTOLE16(TxCB_COUNT_EOF | 0));
+        p_i82559->tx_keys[i] = 0;
+    }
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : TxMachine          (Called from FG & ISR)
+//
+// This steps the Tx Machine onto the next record if necessary - allowing
+// for missed interrupts, and so on.
+// ------------------------------------------------------------------------
+
+static void
+TxMachine(struct i82559* p_i82559)
+{
+    int tx_descriptor_active;
+    cyg_uint32 ioaddr;
+
+    tx_descriptor_active = p_i82559->tx_descriptor_active;
+    ioaddr = p_i82559->io_address;  
+    
+    // See if the CU is idle when we think it isn't; this is the only place
+    // tx_descriptor_active is advanced. (Also recovers from a dropped intr)
+    if ( p_i82559->tx_in_progress ) {
+        cyg_uint16 status;
+        status = INW(ioaddr + SCBStatus);
+        if ( 0 == (status & CU_STATUS_MASK) ) {
+            // It is idle.  So ack the TX interrupts
+            OUTW( SCB_INTACK_TX, ioaddr + SCBStatus);
+            // (see pages 6-10 & 6-90)
+
+            // and step on to the next queued tx.
+            p_i82559->tx_in_progress = 0;
+            if ( ++tx_descriptor_active >= MAX_TX_DESCRIPTORS )
+                tx_descriptor_active = 0;
+            p_i82559->tx_descriptor_active = tx_descriptor_active;
+        }
+    }
+
+    // is the CU idle, and there a next tx to set going?
+    if ( ( ! p_i82559->tx_in_progress )
+         && p_i82559->tx_descriptor_add != tx_descriptor_active ) {
+        TxCB *p_txcb = p_i82559->tx_ring[tx_descriptor_active];
+        cyg_uint16 status;
+        status = INW(ioaddr + SCBStatus);
+        CYG_ASSERT( ( 0 == (status & CU_STATUS_MASK)), "CU not idle");
+        CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
+        CYG_ASSERT( (cyg_uint8 *)p_txcb <  i82559_heap_free, "txcb over" );
+#ifdef DEBUG_82559
+        {
+            unsigned long key = p_i82559->tx_keys[ tx_descriptor_active ];
+            os_printf("Tx %d %x: Starting Engines: KEY %x TxCB %x\n",
+                      p_i82559->index, (int)p_i82559, key, p_txcb);
+        }
+#endif
+
+        // start Tx operation
+        wait_for_cmd_done(ioaddr, WAIT_CU);
+        OUTL(VIRT_TO_BUS(p_txcb), ioaddr + SCBPointer);
+        OUTW(CU_START, ioaddr + SCBCmd);
+        p_i82559->tx_in_progress = 1;
+    }
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : TxDone          (Called from delivery thread)
+//
+// This returns Tx's from the Tx Machine to the stack (ie. reports
+// completion) - allowing for missed interrupts, and so on.
+// ------------------------------------------------------------------------
+
+static void
+TxDone(struct i82559* p_i82559)
+{
+    struct cyg_netdevtab_entry *ndp;
+    struct eth_drv_sc *sc;
+    int tx_descriptor_remove = p_i82559->tx_descriptor_remove;
+
+    ndp = (struct cyg_netdevtab_entry *)(p_i82559->ndp);
+    sc = (struct eth_drv_sc *)(ndp->device_instance);
+
+    CHECK_NDP_SC_LINK();
+    
+    // "Done" txen are from here to active, OR 
+    // the remove one if the queue is full AND its status is nonzero:
+    while (  (tx_descriptor_remove != p_i82559->tx_descriptor_active) ||
+             ( p_i82559->tx_queue_full) ) {
+
+        cyg_uint16 txstatus;
+        TxCB *p_txcb = p_i82559->tx_ring[ tx_descriptor_remove ];
+        unsigned long key = p_i82559->tx_keys[ tx_descriptor_remove ];
+
+        HAL_READ_UINT16(p_txcb + TxCB_STATUS, txstatus);
+        if (0 == txstatus)
+            break;
+
+#ifdef DEBUG_82559
+        os_printf("TxDone %d %x: KEY %x TxCB %x\n",
+                  p_i82559->index, (int)p_i82559, key, p_txcb );
+#endif
+        (sc->funs->eth_drv->tx_done)( sc, key, 1 /* status */ );
+        
+        if ( ++tx_descriptor_remove >= MAX_TX_DESCRIPTORS )
+            tx_descriptor_remove = 0;
+        p_i82559->tx_descriptor_remove = tx_descriptor_remove;
+        p_i82559->tx_queue_full = 0;
+    }
+}
+
+
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_can_send
+//
+// ------------------------------------------------------------------------
+
+static int 
+i82559_can_send(struct eth_drv_sc *sc)
+{
+    struct i82559 *p_i82559;
+    int ints;
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );
+#endif
+        return 0;
+    }
+    
+    // Advance TxMachine atomically
+    ints = Mask82559Interrupt(p_i82559);
+    TxMachine(p_i82559);
+    Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so
+    PacketRxReady(p_i82559);
+    UnMask82559Interrupt(p_i82559,ints);
+
+    return ! p_i82559->tx_queue_full;
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_send
+//
+// ------------------------------------------------------------------------
+
+static void 
+i82559_send(struct eth_drv_sc *sc,
+            struct eth_drv_sg *sg_list, int sg_len, int total_len,
+            unsigned long key)
+{
+    struct i82559 *p_i82559;
+    int tx_descriptor_add, ints;
+    TxCB *p_txcb;
+    cyg_uint32 ioaddr;
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_send: Bad device pointer %x\n", p_i82559 );
+#endif
+        return;
+    }
+
+#ifdef DEBUG_82559
+    os_printf("Tx %d %x: %d sg's, %d bytes, KEY %x\n",
+              p_i82559->index, (int)p_i82559, sg_len, total_len, key );
+#endif
+
+    if ( ! p_i82559->active )
+        return;                         // device inactive, no return
+#ifdef KEEP_STATISTICS
+    statistics[p_i82559->index].tx_count++;
+#endif
+    ioaddr = p_i82559->io_address;      // get device I/O address
+
+    if ( p_i82559->tx_queue_full ) {
+#ifdef KEEP_STATISTICS
+        statistics[p_i82559->index].tx_dropped++;
+#endif
+#ifdef DEBUG_82559
+        os_printf( "i82559_send: Queue full, device %x, key %x\n",
+                   p_i82559, key );
+#endif
+    }
+    else {
+        struct eth_drv_sg *last_sg;
+        volatile cyg_uint8 *to_p;
+
+        tx_descriptor_add = p_i82559->tx_descriptor_add;
+
+        p_i82559->tx_keys[tx_descriptor_add] = key;
+
+        p_txcb = p_i82559->tx_ring[tx_descriptor_add];
+
+        CYG_ASSERT( (cyg_uint8 *)p_txcb >= i82559_heap_base, "txcb under" );
+        CYG_ASSERT( (cyg_uint8 *)p_txcb <  i82559_heap_free, "txcb over" );
+
+        HAL_WRITE_UINT16(p_txcb + TxCB_STATUS, 0);
+        HAL_WRITE_UINT16(p_txcb + TxCB_CMD,
+                         (TxCB_CMD_TRANSMIT | TxCB_CMD_S
+                          | TxCB_CMD_I | TxCB_CMD_EL));
+        HAL_WRITE_UINT32(p_txcb + TxCB_LINK, 
+                         HAL_CTOLE32(VIRT_TO_BUS((cyg_uint32)p_txcb)));
+        HAL_WRITE_UINT32(p_txcb + TxCB_TBD_ADDR,
+                         HAL_CTOLE32(0xFFFFFFFF));
+        HAL_WRITE_UINT8(p_txcb + TxCB_TBD_NUMBER, 0);
+        HAL_WRITE_UINT8(p_txcb + TxCB_TX_THRESHOLD, 16);
+        HAL_WRITE_UINT16(p_txcb + TxCB_COUNT,
+                         HAL_CTOLE16(TxCB_COUNT_EOF | total_len));
+
+        // Copy from the sglist into the txcb
+        to_p = p_txcb + TxCB_BUFFER;
+
+        CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
+        CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );
+
+        for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
+            cyg_uint8 *from_p;
+            int l;
+            
+            from_p = (cyg_uint8 *)(sg_list->buf);
+            l = sg_list->len;
+
+            if ( l > total_len )
+                l = total_len;
+
+            memcpy( (unsigned char *)to_p, from_p, l );
+            to_p += l;
+            total_len -= l;
+
+            if ( 0 > total_len ) 
+                break; // Should exit via sg_last normally
+        }
+
+        CYG_ASSERT( 0 == total_len, "length mismatch in tx" );
+        CYG_ASSERT( last_sg == sg_list, "sg count mismatch in tx" );
+        CYG_ASSERT( p_txcb + TxCB_BUFFER < to_p, "to_p wild in tx" );
+        CYG_ASSERT( p_txcb + TxCB_BUFFER + MAX_TX_PACKET_SIZE >= to_p,
+                    "to_p overflow in tx" );
+  
+        // Next descriptor
+        if ( ++tx_descriptor_add >= MAX_TX_DESCRIPTORS)
+            tx_descriptor_add = 0;
+        p_i82559->tx_descriptor_add = tx_descriptor_add;
+
+        // From this instant, interrupts can advance the world and start,
+        // even complete, this tx request...
+
+        if ( p_i82559->tx_descriptor_remove == tx_descriptor_add )
+            p_i82559->tx_queue_full = 1;
+    }
+
+    // Try advancing the Tx Machine regardless
+
+    // no more interrupts until started
+    ints = Mask82559Interrupt(p_i82559);
+
+    // Check that either:
+    //     tx is already active, there is other stuff queued,
+    // OR  this tx just added is the current active one
+    // OR  this tx just added is already complete
+    CYG_ASSERT(
+        // The machine is busy:
+        (p_i82559->tx_in_progress == 1) ||
+        // or: The machine is idle and this just added is the next one
+        (((p_i82559->tx_descriptor_add-1) == p_i82559->tx_descriptor_active)
+         || ((0 == p_i82559->tx_descriptor_add) &&
+             ((MAX_TX_DESCRIPTORS-1) == p_i82559->tx_descriptor_active))) ||
+        // or: This tx is already complete
+        (p_i82559->tx_descriptor_add == p_i82559->tx_descriptor_active),
+                "Active/add mismatch" );
+
+    // Advance TxMachine atomically
+    TxMachine(p_i82559);
+    Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so
+    PacketRxReady(p_i82559);
+    UnMask82559Interrupt(p_i82559, ints);
+}
+
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_reset
+//
+// ------------------------------------------------------------------------
+static void
+i82559_reset(struct i82559* p_i82559)
+{
+    cyg_uint32 ioaddr = p_i82559->io_address;
+
+    // First do soft reset. This must be done before the hard reset,
+    // otherwise we may create havoc on the PCI bus.
+    // Wait 20 uSecs afterwards for chip to settle.
+    OUTL(I82559_SELECTIVE_RESET, ioaddr + SCBPort);
+    udelay(20);
+  
+    // Do hard reset now that the controller is off the PCI bus.
+    // Wait 20 uSecs afterwards for chip to settle.
+    OUTL(I82559_RESET, ioaddr + SCBPort);
+    udelay(20);
+
+    // Set the base addresses
+    wait_for_cmd_done(ioaddr, WAIT_RU);
+    OUTL(0, ioaddr + SCBPointer);
+    OUTW(SCB_M | RUC_ADDR_LOAD, ioaddr + SCBCmd);
+
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTL(0, ioaddr + SCBPointer);
+    OUTW(SCB_M | CU_ADDR_LOAD, ioaddr + SCBCmd);
+}
+
+// ------------------------------------------------------------------------
+//
+//                       INTERRUPT HANDLERS
+//
+// ------------------------------------------------------------------------
+
+static cyg_uint32
+eth_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+    struct i82559* p_i82559 = (struct i82559 *)data;
+    cyg_uint16 status;
+    cyg_uint32 ioaddr;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_isr: Bad device pointer %x\n", p_i82559 );
+#endif
+        return 0;
+    }
+
+    ioaddr = p_i82559->io_address;
+    status = INW(ioaddr + SCBStatus);
+
+    // Acknowledge all INT sources that were active
+    OUTW( status & SCB_INTACK_MASK, ioaddr + SCBStatus);
+    // (see pages 6-10 & 6-90)
+
+#ifdef KEEP_STATISTICS
+    statistics[p_i82559->index].interrupts++;
+
+    // receiver left ready state ?
+    if ( status & SCB_STATUS_RNR )
+        statistics[p_i82559->index].rx_resource++;
+
+    // frame receive interrupt ?
+    if ( status & SCB_STATUS_FR )
+        statistics[p_i82559->index].rx_count++;
+
+    // transmit interrupt ?
+    if ( status & SCB_STATUS_CX )
+        statistics[p_i82559->index].tx_complete++;
+#endif
+
+    // Advance the Tx Machine regardless
+    TxMachine(p_i82559);
+
+    // it should have settled down now...
+    Acknowledge82559Interrupt(p_i82559);
+
+    return CYG_ISR_CALL_DSR;        // schedule DSR
+}
+
+
+// ------------------------------------------------------------------------
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+static cyg_uint32
+eth_mux_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+    int i;
+    struct i82559* p_i82559;
+
+    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT; i++) {
+        p_i82559 = i82559_priv_array[i];
+        if ( p_i82559->active )
+            (void)eth_isr( vector, (cyg_addrword_t)p_i82559 );
+    }
+
+    return CYG_ISR_CALL_DSR;
+}
+#endif
+
+// ------------------------------------------------------------------------
+
+static void
+eth_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+    struct i82559* p_i82559 = (struct i82559 *)data;
+    struct cyg_netdevtab_entry *ndp =
+        (struct cyg_netdevtab_entry *)(p_i82559->ndp);
+    struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance);
+
+    // but here, it must be a *sc:
+    eth_drv_dsr( vector, count, (cyg_addrword_t)sc );
+}
+
+// ------------------------------------------------------------------------
+// This is called from the function below (used to be uni-DSR)
+void
+i82559_deliver(struct eth_drv_sc *sc)
+{
+    struct i82559* p_i82559 = (struct i82559 *)(sc->driver_private);
+
+    // First pass any rx data up the stack
+    PacketRxReady(p_i82559);
+
+    // Then scan for completed Txen and inform the stack
+    TxDone(p_i82559);
+}
+
+
+// ------------------------------------------------------------------------
+
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+static void
+mux_deliver(struct eth_drv_sc *sc)
+{
+    int i;
+
+    // Since this must mux all devices, the incoming arg is ignored.
+    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT; i++) {
+        sc = i82559_sc_array[i];
+        if ( p_i82559->active )
+            i82559_deliver( sc );
+    }
+}
+#endif
+
+// ------------------------------------------------------------------------
+// Device table entry to operate the chip in a polled mode.
+// Only diddle the interface we were asked to!
+
+void
+i82559_poll(struct eth_drv_sc *sc)
+{
+    struct i82559 *p_i82559;
+    int ints;
+    p_i82559 = (struct i82559 *)sc->driver_private;
+    
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_poll: Bad device pointer %x\n", p_i82559 );
+#endif
+        return;
+    }
+
+    // Do these atomically
+    ints = Mask82559Interrupt(p_i82559);
+
+    // As it happens, this driver always requests the DSR to be called:
+    (void)eth_isr( p_i82559->vector, (cyg_addrword_t)p_i82559 );
+
+    // (no harm in calling this ints-off also, when polled)
+    i82559_deliver( sc );
+
+    Acknowledge82559Interrupt(p_i82559);
+    UnMask82559Interrupt(p_i82559, ints);
+}
+
+// ------------------------------------------------------------------------
+// Determine interrupt vector used by a device - for attaching GDB stubs
+// packet handler.
+int
+i82559_int_vector(struct eth_drv_sc *sc)
+{
+    struct i82559 *p_i82559;
+    p_i82559 = (struct i82559 *)sc->driver_private;
+    return (p_i82559->vector);
+}
+
+#if 0
+int
+i82559_int_op( struct eth_drv_sc *sc, int mask)
+{
+    struct i82559 *p_i82559;
+    p_i82559 = (struct i82559 *)sc->driver_private;
+
+    if ( 1 == mask )
+        return Mask82559Interrupt( p_i82559 );
+
+    if ( 0 == mask )
+        UnMask82559Interrupt( p_i82559, 0x0fffffff ); // enable all
+
+    return 0;
+}
+#endif
+    
+
+// ------------------------------------------------------------------------
+//
+//  Function : pci_init_find_82559s
+//
+// This is called exactly once at the start of time to:
+//  o scan the PCI bus for objects
+//  o record them in the device table
+//  o acquire all the info needed for the driver to access them
+//  o instantiate interrupts for them
+//  o attach those interrupts appropriately
+// ------------------------------------------------------------------------
+static int
+pci_init_find_82559s( void )
+{
+    cyg_pci_device_id devid;
+    cyg_pci_device dev_info;
+    cyg_uint16 cmd;
+    int device_index;
+    int found_devices = 0;
+
+#ifdef DEBUG
+    db_printf("pci_init_find_82559s()\n");
+#endif
+
+    // allocate memory to be used in ioctls later
+    if (mem_reserved_ioctl != (void*)0) {
+#ifdef DEBUG
+        db_printf("pci_init_find_82559s() called > once\n");
+#endif
+        return 0;
+    }
+
+    CYG_ASSERT( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) ==
+                CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE,
+      "PCI window configured does not match PCI memory section base" );
+    CYG_ASSERT( CYGMEM_SECTION_pci_window_SIZE ==
+                CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE,
+        "PCI window configured does not match PCI memory section size" );
+
+    if ( CYGARC_UNCACHED_ADDRESS((CYG_ADDRWORD)CYGMEM_SECTION_pci_window) !=
+         CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE
+         ||
+         CYGMEM_SECTION_pci_window_SIZE !=
+         CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE ) {
+#ifdef DEBUG
+        db_printf("pci_init_find_82559s(): PCI window misconfigured\n");
+#endif
+        return 0;
+    }
+
+    // First initialize the heap in PCI window'd memory
+    i82559_heap_size = CYGHWR_INTEL_I82559_PCI_MEM_MAP_SIZE;
+    i82559_heap_base = (cyg_uint8 *)CYGHWR_INTEL_I82559_PCI_MEM_MAP_BASE;
+    i82559_heap_free = i82559_heap_base;
+
+    mem_reserved_ioctl = pciwindow_mem_alloc(MAX_MEM_RESERVED_IOCTL);     
+
+    cyg_pci_init();
+#ifdef DEBUG
+    db_printf("Finished cyg_pci_init();\n");
+#endif
+
+    devid = CYG_PCI_NULL_DEVID;
+
+    for (device_index = 0; 
+         device_index < CYGNUM_DEVS_ETH_INTEL_I82559_DEV_COUNT;
+         device_index++) {
+        struct i82559 *p_i82559 = i82559_priv_array[device_index];
+
+        p_i82559->index = device_index;
+
+        // Intel 82559 and 82557 are virtually identical,
+        // with different dev codes
+        if (cyg_pci_find_device(0x8086, 0x1030, &devid) ||
+            cyg_pci_find_device(0x8086, 0x1209, &devid) ||
+            cyg_pci_find_device(0x8086, 0x1229, &devid) ) {
+#ifdef DEBUG
+            db_printf("eth%d = 82559\n", device_index);
+#endif
+            cyg_pci_get_device_info(devid, &dev_info);
+
+            if (cyg_pci_translate_interrupt(&dev_info, &p_i82559->vector)) {
+#ifdef DEBUG
+                db_printf(" Wired to HAL vector %d\n", p_i82559->vector);
+#endif
+                cyg_drv_interrupt_create(
+                    p_i82559->vector,
+                    0,                  // Priority - unused
+                    (CYG_ADDRWORD)p_i82559, // Data item passed to ISR & DSR
+                    eth_isr,            // ISR
+                    eth_dsr,            // DSR
+                    &p_i82559->interrupt_handle, // handle to intr obj
+                    &p_i82559->interrupt_object ); // space for int obj
+
+                cyg_drv_interrupt_attach(p_i82559->interrupt_handle);
+
+                // Don't unmask the interrupt yet, that could get us into a
+                // race.
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+                // ALSO attach it to MUX interrupt for multiplexed
+                // interrupts.  This is for certain boards where the
+                // PCI backplane is wired "straight through" instead of
+                // with a rotation of interrupt lines in the different
+                // slots.
+                {
+                    static cyg_handle_t mux_interrupt_handle = 0;
+                    static cyg_interrupt mux_interrupt_object;
+
+                    if ( ! mux_interrupt_handle ) {
+#ifdef DEBUG
+                        db_printf(" Also attaching to HAL vector %d\n", 
+                                  CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+#endif
+                        cyg_drv_interrupt_create(
+                            CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT,
+                            0,              // Priority - unused
+                            (CYG_ADDRWORD)p_i82559,// Data item passed to ISR and DSR
+                            eth_mux_isr,    // ISR
+                            eth_dsr,        // DSR
+                            &mux_interrupt_handle,
+                            &mux_interrupt_object );
+                        
+                        cyg_drv_interrupt_attach(mux_interrupt_handle);
+                    }
+                }
+#endif // CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+            }
+            else {
+                p_i82559->vector=0;
+#ifdef DEBUG
+                db_printf(" Does not generate interrupts.\n");
+#endif
+            }
+
+            if (cyg_pci_configure_device(&dev_info)) {
+#ifdef DEBUG
+                int i;
+                db_printf("Found device on bus %d, devfn 0x%02x:\n",
+                          CYG_PCI_DEV_GET_BUS(devid),
+                          CYG_PCI_DEV_GET_DEVFN(devid));
+
+                if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {
+                    db_printf(" Note that board is active. Probed"
+                              " sizes and CPU addresses invalid!\n");
+                }
+                db_printf(" Vendor    0x%04x", dev_info.vendor);
+                db_printf("\n Device    0x%04x", dev_info.device);
+                db_printf("\n Command   0x%04x, Status 0x%04x\n",
+                          dev_info.command, dev_info.status);
+                
+                db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
+                db_printf("\n Header 0x%02x\n", dev_info.header_type);
+
+                db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
+                          dev_info.header.normal.sub_vendor, 
+                          dev_info.header.normal.sub_id);
+
+                for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
+                    db_printf(" BAR[%d]    0x%08x /", i, dev_info.base_address[i]);
+                    db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
+                              dev_info.base_size[i], dev_info.base_map[i]);
+                }
+                db_printf(" eth%d configured\n", device_index);
+#endif
+                found_devices++;
+                p_i82559->found = 1;
+                p_i82559->active = 0;
+                p_i82559->devid = devid;
+                p_i82559->memory_address = dev_info.base_map[0];
+                p_i82559->io_address = dev_info.base_map[1];
+#ifdef DEBUG
+                db_printf(" memory address = 0x%08x\n", dev_info.base_map[0]);
+                db_printf(" I/O address = 0x%08x\n", dev_info.base_map[1]);
+#endif
+
+                // Don't use cyg_pci_set_device_info since it clears
+                // some of the fields we want to print out below.
+                cyg_pci_read_config_uint16(dev_info.devid,
+                                           CYG_PCI_CFG_COMMAND, &cmd);
+                cmd |= (CYG_PCI_CFG_COMMAND_IO         // enable I/O space
+                        | CYG_PCI_CFG_COMMAND_MEMORY   // enable memory space
+                        | CYG_PCI_CFG_COMMAND_MASTER); // enable bus master
+                cyg_pci_write_config_uint16(dev_info.devid,
+                                            CYG_PCI_CFG_COMMAND, cmd);
+
+                // Now the PCI part of the device is configured, reset
+                // it. This should make it safe to enable the
+                // interrupt
+                i82559_reset(p_i82559);
+
+                if (p_i82559->vector != 0) {
+                    cyg_drv_interrupt_acknowledge(p_i82559->vector);
+                    cyg_drv_interrupt_unmask(p_i82559->vector);
+                }
+#ifdef DEBUG
+                db_printf(" **** Device enabled for I/O and Memory "
+                          "and Bus Master\n");
+#endif
+            }
+            else {
+                p_i82559->found = 0;
+                p_i82559->active = 0;
+#ifdef DEBUG
+                db_printf("Failed to configure device %d\n",device_index);
+#endif
+            }
+        }
+        else {
+            p_i82559->found = 0;
+            p_i82559->active = 0;
+#ifdef DEBUG
+            db_printf("eth%d not found\n", device_index);
+#endif
+        }
+    }
+
+    if (0 == found_devices)
+        return 0;
+
+#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT
+    // Now enable the mux shared interrupt if it is in use
+    if (mux_interrupt_handle) {
+        cyg_drv_interrupt_acknowledge(CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+        cyg_drv_interrupt_unmask(CYGNUM_DEVS_ETH_INTEL_I82559_MUX_INTERRUPT);
+    }
+#endif
+
+    // Now a delay to ensure the hardware has "come up" before you try to
+    // use it.  Yes, really, the full 2 seconds.  It's only really
+    // necessary if DEBUG is off - otherwise all that printout wastes
+    // enough time.  No kidding.
+    udelay( 2000000 );
+    return 1;
+}
+
+// This function is called to enable the device by setting the necessary
+// minimum of the configuration.
+static int
+eth_set_config(struct i82559* p_i82559)
+{
+    cyg_uint32  ioaddr;
+    volatile CFG *ccs;
+    volatile cyg_uint8* config_bytes;
+    cyg_uint16 status;
+    int count;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "eth_set_config: Bad device pointer %x\n", p_i82559 );
+#endif
+        return -1;
+    }
+
+    ioaddr = p_i82559->io_address;
+
+    // Check the malloc we did earlier worked
+    ccs = (CFG *)mem_reserved_ioctl;
+    if (ccs == (void*)0) 
+        return 2; // Failed
+
+    // Prepare header
+    HAL_WRITE_UINT16(ccs + CFG_CMD, 
+                     (CFG_CMD_EL | CFG_CMD_SUSPEND | CFG_CMD_CONFIGURE));
+    HAL_WRITE_UINT16(ccs + CFG_STATUS, 0);
+    HAL_WRITE_UINT32(ccs + CFG_CB_LINK_OFFSET, 
+                     HAL_CTOLE32(VIRT_TO_BUS((cyg_uint32)ccs)));
+
+    // Default values from the Intel Manual
+    config_bytes = ccs + CFG_BYTES;
+    config_bytes[0]=0x9;
+    config_bytes[1]=0xc;
+    config_bytes[2]=0x0;
+    config_bytes[3]=0x0;
+    config_bytes[4]=0x0;
+    config_bytes[5]=0x0;
+    config_bytes[6]=0x32;
+    config_bytes[7]=0x1;
+    // This is the bit we go through all the trouble for. Must be set
+    // before the device activates.
+    config_bytes[8]=0x1;
+
+    // Let chip read configuration
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTL(VIRT_TO_BUS(ccs), ioaddr + SCBPointer);
+    OUTW(SCB_M | CU_START, ioaddr + SCBCmd);
+
+    // ...and wait for it to complete operation
+    count = 1000;
+    do {
+      HAL_READ_UINT16(ccs + CFG_STATUS, status);
+      udelay(1);
+    } while (0 == (status & CFG_STATUS_C) && (count-- > 0));
+
+    // Check status
+    if ((status & (CFG_STATUS_C | CFG_STATUS_OK)) 
+        != (CFG_STATUS_C | CFG_STATUS_OK)) {
+        // Failed!
+#ifdef DEBUG_82559
+        os_printf("%s:%d Config update failed\n", __FUNCTION__, __LINE__);
+#endif
+        return 1;
+    }
+
+    return 0;
+}
+
+#ifdef CYGPKG_NET
+// ------------------------------------------------------------------------
+//
+//  Function : eth_set_promiscuous_mode
+//
+//  Return : 0 = It worked.
+//           non0 = It failed.
+// ------------------------------------------------------------------------
+
+static int
+eth_set_promiscuous_mode(struct i82559* p_i82559)
+{
+    cyg_uint32  ioaddr;
+    volatile CFG *ccs;
+    volatile cyg_uint8* config_bytes;
+    cyg_uint16 status;
+    int count;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "eth_set_promiscuos_mode: Bad device pointer %x\n",
+                   p_i82559 );
+#endif
+        return -1;
+    }
+
+    ioaddr = p_i82559->io_address;  
+  
+    // Check the malloc we did earlier worked
+    ccs = (CFG *)mem_reserved_ioctl;
+    if (ccs == (void*)0) 
+        return 2; // Failed
+
+    // Prepare header
+    HAL_WRITE_UINT16(ccs + CFG_CMD, 
+                     (CFG_CMD_EL | CFG_CMD_SUSPEND | CFG_CMD_CONFIGURE));
+    HAL_WRITE_UINT16(ccs + CFG_STATUS, 0);
+    HAL_WRITE_UINT32(ccs + CFG_CB_LINK_OFFSET, 
+                     HAL_CTOLE32(VIRT_TO_BUS((cyg_uint32)ccs)));
+
+    // Default values from the Intel Manual
+    config_bytes = ccs + CFG_BYTES;
+    config_bytes[0]=0x13;
+    config_bytes[1]=0x8;
+    config_bytes[2]=0x0;
+    config_bytes[3]=0x0;
+    config_bytes[4]=0x0;
+    config_bytes[5]=0x0;
+    config_bytes[6]=0xb2; // (promisc ? 0x80 : 0) | 0x32 for small stats,
+    config_bytes[7]=0x1;  // \      ditto         | 0x12 for stats with PAUSE stats
+    config_bytes[8]=0x0;  //  \     ditto         | 0x16 for PAUSE + TCO stats
+    config_bytes[9]=0x0;
+    config_bytes[10]=0x28;
+    config_bytes[11]=0x0;
+    config_bytes[12]=0x60;
+    config_bytes[13]=0x0;          // arp
+    config_bytes[14]=0x0;          // arp
+                   
+    config_bytes[15]=0x81;         // promiscuous mode set
+                                   // \ or 0x80 for normal mode.
+    config_bytes[16]=0x0;
+    config_bytes[17]=0x40;
+    config_bytes[18]=0x72;         // Keep the Padding Enable bit
+
+    // Let chip read configuration
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTL(VIRT_TO_BUS(ccs), ioaddr + SCBPointer);
+    OUTW(SCB_M | CU_START, ioaddr + SCBCmd);
+
+    // ...and wait for it to complete operation
+    count = 1000;
+    do {
+      HAL_READ_UINT16(ccs + CFG_STATUS, status);
+      udelay(1);
+    } while (0 == (status & CFG_STATUS_C) && (count-- > 0));
+
+    // Check status
+    if ((status & (CFG_STATUS_C | CFG_STATUS_OK)) 
+        != (CFG_STATUS_C | CFG_STATUS_OK)) {
+        // Failed!
+#ifdef DEBUG_82559
+        os_printf("%s:%d Config update failed\n", __FUNCTION__, __LINE__);
+#endif
+        return 1;
+    }
+    return 0;
+}
+#endif
+
+// ------------------------------------------------------------------------
+// We use this as a templete when writing a new MAC address into the
+// eeproms. The MAC address in the first few bytes is over written
+// with the correct MAC address and then the whole lot is programmed
+// into the serial EEPROM. The checksum is calculated on the fly and
+// sent instead of the last two bytes.
+// The values are copied from the Intel EtherPro10/100+ &c devices
+// in the EBSA boards.
+
+#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+
+#define ee00 0x00, 0x00 // shorthand
+
+static char eeprom_burn[126] = { 
+/* halfword addresses! */
+/*  0: */  0x00, 0x90,   0x27, 0x8c,       0x57, 0x82,   0x03, 0x02,
+/*  4: */     ee00   ,   0x01, 0x02,       0x01, 0x47,      ee00   ,
+/*  8: */  0x13, 0x72,   0x06, 0x83,       0xa2, 0x40,   0x0c, 0x00,
+/*  C: */  0x86, 0x80,      ee00   ,          ee00   ,      ee00   ,
+/* 10: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 14: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 18: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 1C: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 20: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 24: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 28: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 2C: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 30: */  0x28, 0x01,      ee00   ,          ee00   ,      ee00   ,
+/* 34: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 38: */     ee00   ,      ee00   ,          ee00   ,      ee00   ,
+/* 3C: */     ee00   ,      ee00   ,          ee00   
+};
+#undef ee00
+
+#endif
+
+// ------------------------------------------------------------------------
+//
+//  Function : eth_set_mac_address
+//
+//  Return : 0 = It worked.
+//           non0 = It failed.
+// ------------------------------------------------------------------------
+static int
+eth_set_mac_address(struct i82559* p_i82559, char *addr)
+{
+    cyg_uint32  ioaddr;
+    cyg_uint16 status;
+    volatile CFG *ccs;
+    volatile cyg_uint8* config_bytes;
+    int count;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "eth_set_mac_address : Bad device pointer %x\n",
+                   p_i82559 );
+#endif
+        return -1;
+    }
+
+    ioaddr = p_i82559->io_address;      
+    
+    ccs = (CFG *)mem_reserved_ioctl;
+    if (ccs == (void*)0)
+        return 2;
+
+    HAL_WRITE_UINT16(ccs + CFG_CMD, 
+                     (CFG_CMD_EL | CFG_CMD_SUSPEND | CFG_CMD_IAS));
+    HAL_WRITE_UINT16(ccs + CFG_STATUS, 0);
+    HAL_WRITE_UINT32(ccs + CFG_CB_LINK_OFFSET, 
+                     HAL_CTOLE32(VIRT_TO_BUS((cyg_uint32)ccs)));
+
+    config_bytes = ccs + CFG_BYTES;
+    memcpy((char *)(config_bytes),addr,6);
+    config_bytes[6]=0x0;
+    config_bytes[7]=0x0;
+
+    // Let chip read new ESA
+    wait_for_cmd_done(ioaddr, WAIT_CU);
+    OUTL(VIRT_TO_BUS(ccs), ioaddr + SCBPointer); 
+    OUTW(SCB_M | CU_START, ioaddr + SCBCmd);    
+
+    // ...and wait for it to complete operation
+    count = 1000;
+    do {
+      HAL_READ_UINT16(ccs + CFG_STATUS, status);
+      udelay(1);
+    } while (0 == (status & CFG_STATUS_C) && (count-- > 0));
+
+    // Check status
+    HAL_READ_UINT16(ccs + CFG_STATUS, status);
+    if ((status & (CFG_STATUS_C | CFG_STATUS_OK)) 
+        != (CFG_STATUS_C | CFG_STATUS_OK)) {
+#ifdef DEBUG_82559
+        os_printf("%s:%d ESA update failed\n", __FUNCTION__, __LINE__);
+#endif
+        return 3;
+    }
+
+#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+    {
+        int checksum, i, count;
+        // (this is the length of the *EEPROM*s address, not MAC address)
+        int addr_length;
+
+        addr_length = get_eeprom_size( ioaddr );
+
+        // now set this address in the device eeprom ....
+        (void)memcpy(eeprom_burn,addr,6);
+
+        // No idea what these were for...
+        // eeprom_burn[20] &= 0xfe;   
+        // eeprom_burn[20] |= p_i82559->index;   
+        
+        program_eeprom( ioaddr, addr_length, eeprom_burn );
+   
+        // update 82559 driver data structure ...
+        udelay( 100000 );
+
+        // by reading EEPROM to get the mac address back
+        for (checksum = 0, i = 0, count = 0; count < 64; count++) {
+            cyg_uint16 value;
+            // read word from eeprom
+            value = read_eeprom(ioaddr, count, addr_length);
+            checksum += value;
+            if (count < 3) {
+                p_i82559->mac_address[i++] = value & 0xFF;
+                p_i82559->mac_address[i++] = (value >> 8) & 0xFF;
+            }
+        }
+    
+#ifdef DEBUG
+        os_printf("MAC Address = %02X %02X %02X %02X %02X %02X\n",
+                  p_i82559->mac_address[0], p_i82559->mac_address[1],
+                  p_i82559->mac_address[2], p_i82559->mac_address[3],
+                  p_i82559->mac_address[4], p_i82559->mac_address[5]);
+#endif
+
+        p_i82559->mac_addr_ok = 1;
+
+        for ( i = 0, count = 0; i < 6; i++ )
+            if ( p_i82559->mac_address[i] != addr[i] )
+                count++;
+
+        if ( count ) {
+#ifdef DEBUG
+            os_printf( "Warning: MAC Address read back wrong!  %d bytes differ.\n",
+                       count );
+#endif
+            p_i82559->mac_addr_ok = 0;
+        }
+
+        // If the EEPROM checksum is wrong, the MAC address read from
+        // the EEPROM is probably wrong as well. In that case, we
+        // don't set mac_addr_ok.
+        if ((checksum & 0xFFFF) != 0xBABA)  {
+#ifdef DEBUG
+            os_printf( "Warning: Invalid EEPROM checksum %04X for device %d\n",
+                       checksum, p_i82559->index);
+#endif
+            p_i82559->mac_addr_ok = 0;
+        }
+
+#else // CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+
+    // record the MAC address in the device structure
+    p_i82559->mac_address[0] = addr[0];
+    p_i82559->mac_address[1] = addr[1];
+    p_i82559->mac_address[2] = addr[2];
+    p_i82559->mac_address[3] = addr[3];
+    p_i82559->mac_address[4] = addr[4];
+    p_i82559->mac_address[5] = addr[5];
+    p_i82559->mac_addr_ok = 1;
+
+#endif // ! CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+
+    return p_i82559->mac_addr_ok ? 0 : 1;
+}
+
+#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+// ------------------------------------------------------------------------
+static void
+write_eeprom(long ioaddr, int location, int addr_len, unsigned short value)
+{
+    int ee_addr = ioaddr + SCBeeprom;
+    int write_cmd = location | EE_WRITE_CMD(addr_len); 
+    int i;
+    
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay( 100 );
+    OUTW(EE_ENB, ee_addr);
+    eeprom_delay( 100 );
+
+//    os_printf("\n write_eeprom : write_cmd : %x",write_cmd);  
+//    os_printf("\n addr_len : %x  value : %x ",addr_len,value);  
+
+    /* Shift the write command bits out. */
+    for (i = (addr_len+2); i >= 0; i--) {
+        short dataval = (write_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+        OUTW(EE_ENB | dataval, ee_addr);
+        eeprom_delay(100);
+        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(150);
+    }
+    OUTW(EE_ENB, ee_addr);
+        
+    for (i = 15; i >= 0; i--) {
+        short dataval = (value & (1 << i)) ? EE_DATA_WRITE : 0;
+        OUTW(EE_ENB | dataval, ee_addr);
+        eeprom_delay(100);
+        OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+        eeprom_delay(150);
+    }
+
+    /* Terminate the EEPROM access. */
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(150000); // let the write take effect
+}
+
+// ------------------------------------------------------------------------
+static int
+write_enable_eeprom(long ioaddr,  int addr_len)
+{
+    int ee_addr = ioaddr + SCBeeprom;
+    int write_en_cmd = EE_WRITE_EN_CMD(addr_len); 
+    int i;
+
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    OUTW(EE_ENB, ee_addr);
+
+#ifdef DEBUG_82559
+    os_printf("write_en_cmd : %x",write_en_cmd);
+#endif
+
+    // Shift the wr/er enable command bits out.
+    for (i = (addr_len+2); i >= 0; i--) {
+	short dataval = (write_en_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+	OUTW(EE_ENB | dataval, ee_addr);
+	eeprom_delay(100);
+	OUTW(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+	eeprom_delay(150);
+    }
+
+    // Terminate the EEPROM access.
+    OUTW(EE_ENB & ~EE_CS, ee_addr);
+    eeprom_delay(EEPROM_DONE_DELAY);
+}
+
+
+// ------------------------------------------------------------------------
+static void
+program_eeprom(cyg_uint32 ioaddr, cyg_uint32 eeprom_size, cyg_uint8 *data)
+{
+  cyg_uint32 i;
+  cyg_uint16 checksum = 0;
+  cyg_uint16 value;
+
+  // First enable erase/write operations on the eeprom.
+  // This is done through the EWEN instruction.
+  write_enable_eeprom( ioaddr, eeprom_size );
+
+  for (i=0 ; i< 63 ; i++) {
+    value = ((unsigned short *)data)[i];
+    checksum += value;
+#ifdef DEBUG_82559
+    os_printf("\n i : %x ... value to be written : %x",i,value);
+#endif
+    write_eeprom( ioaddr, i, eeprom_size, value);
+#ifdef DEBUG_82559
+    os_printf("\n val read : %x ",read_eeprom(ioaddr,i,eeprom_size));
+#endif
+  }
+  value = 0xBABA - checksum;
+#ifdef DEBUG_82559
+  os_printf("\n i : %x ... checksum adjustment val to be written : %x",i,value);
+#endif
+  write_eeprom( ioaddr, i, eeprom_size, value );
+}
+
+// ------------------------------------------------------------------------
+#endif // ! CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
+
+
+// ------------------------------------------------------------------------
+//
+//  Function : eth_get_mac_address
+//
+// ------------------------------------------------------------------------
+#ifdef ETH_DRV_GET_MAC_ADDRESS
+static int
+eth_get_mac_address(struct i82559* p_i82559, char *addr)
+{
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "eth_get_mac_address : Bad device pointer %x\n",
+                   p_i82559 );
+#endif
+        return -1;
+    }
+
+    memcpy( addr, (char *)(&p_i82559->mac_address[0]), 6 );
+    return 0;
+}
+#endif
+// ------------------------------------------------------------------------
+//
+//  Function : i82559_ioctl
+//
+// ------------------------------------------------------------------------
+static int
+i82559_ioctl(struct eth_drv_sc *sc, unsigned long key,
+             void *data, int data_length)
+{
+    struct i82559 *p_i82559;
+
+    p_i82559 = (struct i82559 *)sc->driver_private;
+
+    IF_BAD_82559( p_i82559 ) {
+#ifdef DEBUG
+        os_printf( "i82559_ioctl/control: Bad device pointer %x\n", p_i82559 );
+#endif
+        return -1;
+    }
+
+#ifdef DEBUG
+    db_printf( "i82559_ioctl: device eth%d at %x; key is 0x%x, data at %x[%d]\n",
+               p_i82559->index, p_i82559, key, data, data_length );
+#endif
+
+    switch ( key ) {
+
+#ifdef ETH_DRV_SET_MAC_ADDRESS
+    case ETH_DRV_SET_MAC_ADDRESS:
+        if ( 6 != data_length )
+            return -2;
+        return eth_set_mac_address( p_i82559, data );
+#endif
+
+#ifdef ETH_DRV_GET_MAC_ADDRESS
+    case ETH_DRV_GET_MAC_ADDRESS:
+        return eth_get_mac_address( p_i82559, data );
+#endif
+
+#ifdef ETH_DRV_GET_IF_STATS_UD
+    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
+        ETH_STATS_INIT( sc );    // so UPDATE the statistics structure
+#endif
+        // drop through
+#ifdef ETH_DRV_GET_IF_STATS
+    case ETH_DRV_GET_IF_STATS:
+#endif
+#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
+    {
+        struct ether_drv_stats *p = (struct ether_drv_stats *)data;
+        int i;
+        static unsigned char my_chipset[]
+            = { ETH_DEV_DOT3STATSETHERCHIPSET };
+
+        strcpy( p->description, CYGDAT_DEVS_ETH_DESCRIPTION );
+        CYG_ASSERT( 48 > strlen(p->description), "Description too long" );
+
+        for ( i = 0; i < SNMP_CHIPSET_LEN; i++ )
+            if ( 0 == (p->snmp_chipset[i] = my_chipset[i]) )
+                break;
+
+        i = i82559_status( sc );
+
+        if ( !( i & GEN_STATUS_LINK) ) {
+            p->operational = 2;         // LINK DOWN
+            p->duplex = 1;              // UNKNOWN
+            p->speed = 0;
+        }
+        else {
+            p->operational = 3;            // LINK UP
+            p->duplex = (i & GEN_STATUS_FDX) ? 3 : 2; // 2 = SIMPLEX, 3 = DUPLEX
+            p->speed = ((i & GEN_STATUS_100MBPS) ? 100 : 10) * 1000000;
+        }
+
+#ifdef KEEP_STATISTICS
+        {
+            I82559_COUNTERS *pc = &i82559_counters[ p_i82559->index ];
+            STATISTICS      *ps = &statistics[      p_i82559->index ];
+
+            // Admit to it...
+            p->supports_dot3        = true;
+
+            // Those commented out are not available on this chip.
+
+            p->tx_good              = pc->tx_good             ;
+            p->tx_max_collisions    = pc->tx_max_collisions   ;
+            p->tx_late_collisions   = pc->tx_late_collisions  ;
+            p->tx_underrun          = pc->tx_underrun         ;
+            p->tx_carrier_loss      = pc->tx_carrier_loss     ;
+            p->tx_deferred          = pc->tx_deferred         ;
+            //p->tx_sqetesterrors   = pc->tx_sqetesterrors    ;
+            p->tx_single_collisions = pc->tx_single_collisions;
+            p->tx_mult_collisions   = pc->tx_mult_collisions  ;
+            p->tx_total_collisions  = pc->tx_total_collisions ;
+            p->rx_good              = pc->rx_good             ;
+            p->rx_crc_errors        = pc->rx_crc_errors       ;
+            p->rx_align_errors      = pc->rx_align_errors     ;
+            p->rx_resource_errors   = pc->rx_resource_errors  ;
+            p->rx_overrun_errors    = pc->rx_overrun_errors   ;
+            p->rx_collisions        = pc->rx_collisions       ;
+            p->rx_short_frames      = pc->rx_short_frames     ;
+            //p->rx_too_long_frames = pc->rx_too_long_frames  ;
+            //p->rx_symbol_errors   = pc->rx_symbol_errors    ;
+        
+            p->interrupts           = ps->interrupts          ;
+            p->rx_count             = ps->rx_count            ;
+            p->rx_deliver           = ps->rx_deliver          ;
+            p->rx_resource          = ps->rx_resource         ;
+            p->rx_restart           = ps->rx_restart          ;
+            p->tx_count             = ps->tx_count            ;
+            p->tx_complete          = ps->tx_complete         ;
+            p->tx_dropped           = ps->tx_dropped          ;
+        }
+#endif // KEEP_STATISTICS
+
+        p->tx_queue_len = MAX_TX_DESCRIPTORS;
+
+        return 0; // OK
+    }
+#endif
+
+    default:
+        break;
+    }
+    return -1;
+}
+
+// ------------------------------------------------------------------------
+//
+// Statistics update...
+//
+// ------------------------------------------------------------------------
+
+#ifdef KEEP_STATISTICS
+#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_KEEP_82559_STATISTICS
+void
+update_statistics(struct i82559* p_i82559)
+{
+    I82559_COUNTERS *p_statistics;
+    cyg_uint32 *p_counter;
+    cyg_uint32 *p_register;
+    int reg_count, ints;
+    
+    ints = Mask82559Interrupt(p_i82559);
+
+    // This points to the sthared memory stats area/command block
+    p_statistics = (I82559_COUNTERS *)(p_i82559->p_statistics);
+
+    if ( (p_statistics->done & 0xFFFF) == 0xA007 ) {
+        p_counter = (cyg_uint32 *)&i82559_counters[ p_i82559->index ];
+        p_register = (cyg_uint32 *)p_statistics;
+        for ( reg_count = 0;
+              reg_count < sizeof( I82559_COUNTERS ) / sizeof( cyg_uint32 ) - 1;
+              reg_count++ ) {
+            *p_counter += *p_register;
+            p_counter++;
+            p_register++;
+        }
+        p_statistics->done = 0;
+        // start register dump
+        wait_for_cmd_done(p_i82559->io_address, WAIT_CU);
+        OUTW(CU_DUMPSTATS, p_i82559->io_address + SCBCmd);
+    }
+    Acknowledge82559Interrupt(p_i82559); // This can eat an Rx interrupt, so
+    PacketRxReady(p_i82559);
+
+    UnMask82559Interrupt(p_i82559, ints);
+}
+#endif
+#endif // KEEP_STATISTICS
+
+// ------------------------------------------------------------------------
+//
+//
+//           CODE FOR DEBUGGING PURPOSES ONLY
+//
+//
+// ------------------------------------------------------------------------
+void
+dump_txcb(TxCB *p_txcb)
+{
+    cyg_uint16 tmp8;
+    cyg_uint16 tmp16;
+    cyg_uint32 tmp32;
+
+    os_printf("TxCB @ %x\n", (int)p_txcb);
+    HAL_READ_UINT16(p_txcb + TxCB_STATUS, tmp16);
+    os_printf("status = %04X ", HAL_LE16TOC(tmp16));
+    HAL_READ_UINT16(p_txcb + TxCB_CMD, tmp16);
+    os_printf("command = %04X ", HAL_LE16TOC(tmp16));
+    HAL_READ_UINT32(p_txcb + TxCB_LINK, tmp32);
+    os_printf("link = %08X ", HAL_LE32TOC(tmp32));
+    HAL_READ_UINT32(p_txcb + TxCB_TBD_ADDR, tmp32);
+    os_printf("tbd = %08X ", HAL_LE32TOC(tmp32));
+    HAL_READ_UINT16(p_txcb + TxCB_COUNT, tmp16);
+    tmp16 = HAL_LE16TOC(tmp16);
+    os_printf("count = %d ", (tmp16 & TxCB_COUNT_MASK));
+    os_printf("eof = %x ", (tmp16 & TxCB_COUNT_EOF) ? 1 : 0);
+    HAL_READ_UINT8(p_txcb + TxCB_TX_THRESHOLD, tmp8);
+    os_printf("threshold = %d ", tmp8);
+    HAL_READ_UINT8(p_txcb + TxCB_TBD_NUMBER, tmp8);
+    os_printf("tbd number = %d\n", tmp8);
+}
+
+// This is intended to be the body of a THREAD that prints stuff every 10
+// seconds or so:
+#ifdef KEEP_STATISTICS
+#ifdef DISPLAY_STATISTICS
+void
+DisplayStatistics(void)
+{
+    int i;
+    I82559_COUNTERS *p_statistics;
+    cyg_uint32 *p_counter;
+    cyg_uint32 *p_register;
+    int reg_count;
+    int status;
+    
+    while ( 1 ) {
+#ifdef DISPLAY_82559_STATISTICS
+        for ( i = 0; i < 2; i ++ ) {
+            p_statistics = (I82559_COUNTERS *)i82559[i].p_statistics;
+            if ( (p_statistics->done & 0xFFFF) == 0xA007 ) {
+                p_counter = (cyg_uint32 *)&i82559_counters[i];
+                p_register = (cyg_uint32 *)&p_statistics->tx_good;
+                for ( reg_count = 20; reg_count != 0; reg_count--) {
+                    *p_counter += *p_register;
+                    p_counter++;
+                    p_register++;
+                }
+                p_statistics->done = 0;
+                // start register dump
+            	wait_for_cmd_done(i82559[i].io_address, WAIT_CU);
+                OUTW(CU_DUMPSTATS, i82559[i].io_address + SCBCmd);
+            }
+        }
+#endif
+        os_printf("\nRx\nPackets = %d  %d\n",
+        statistics[0].rx_count, statistics[1].rx_count);
+        os_printf("Deliver   %d  %d\n",
+        statistics[0].rx_deliver, statistics[1].rx_deliver);
+        os_printf("Resource  %d  %d\n",
+        statistics[0].rx_resource, statistics[1].rx_resource);
+        os_printf("Restart   %d  %d\n",
+        statistics[0].rx_restart, statistics[1].rx_restart);
+
+#ifdef DISPLAY_82559_STATISTICS
+        os_printf("Count     %d  %d\n",
+        i82559_counters[0].rx_good, i82559_counters[1].rx_good);
+        os_printf("CRC       %d  %d\n",
+        i82559_counters[0].rx_crc_errors, i82559_counters[1].rx_crc_errors);
+        os_printf("Align     %d  %d\n",
+        i82559_counters[0].rx_align_errors, i82559_counters[1].rx_align_errors);
+        os_printf("Resource  %d  %d\n",
+        i82559_counters[0].rx_resource_errors, i82559_counters[1].rx_resource_errors);
+        os_printf("Overrun   %d  %d\n",
+        i82559_counters[0].rx_overrun_errors, i82559_counters[1].rx_overrun_errors);
+        os_printf("Collision %d  %d\n",
+        i82559_counters[0].rx_collisions, i82559_counters[1].rx_collisions);
+        os_printf("Short     %d  %d\n",
+        i82559_counters[0].rx_short_frames, i82559_counters[1].rx_short_frames);
+#endif
+        os_printf("\nTx\nPackets = %d  %d\n",
+        statistics[0].tx_count, statistics[1].tx_count);
+        os_printf("Complete  %d  %d\n",
+        statistics[0].tx_complete, statistics[1].tx_complete);
+        os_printf("Dropped   %d  %d\n",
+        statistics[0].tx_dropped, statistics[1].tx_dropped);
+        os_printf("Count     %d  %d\n",
+        i82559_counters[0].tx_good, i82559_counters[1].tx_good);
+#ifdef DISPLAY_82559_STATISTICS
+        os_printf("Collision %d  %d\n",
+        i82559_counters[0].tx_max_collisions,i82559_counters[1].tx_max_collisions);
+        os_printf("Late Col. %d  %d\n",
+        i82559_counters[0].tx_late_collisions,i82559_counters[1].tx_late_collisions);
+        os_printf("Underrun  %d  %d\n",
+        i82559_counters[0].tx_underrun,i82559_counters[1].tx_underrun);
+        os_printf("Carrier   %d  %d\n",
+        i82559_counters[0].tx_carrier_loss,i82559_counters[1].tx_carrier_loss);
+        os_printf("Deferred  %d  %d\n",
+        i82559_counters[0].tx_deferred, i82559_counters[1].tx_deferred);
+        os_printf("1 Col     %d  %d\n",
+        i82559_counters[0].tx_single_collisions, i82559_counters[0].tx_single_collisions);
+        os_printf("Mult. Col %d  %d\n",
+        i82559_counters[0].tx_mult_collisions, i82559_counters[0].tx_mult_collisions);
+        os_printf("Total Col %d  %d\n",
+        i82559_counters[0].tx_total_collisions, i82559_counters[0].tx_total_collisions);
+#endif
+        status = INB(i82559[0].io_address + SCBGenStatus);
+        os_printf("Interface 0 Link = %s, %s Mbps, %s Duplex\n",
+            status & GEN_STATUS_LINK ? "Up" : "Down",
+            status & GEN_STATUS_100MBPS ?  "100" : "10",
+            status & GEN_STATUS_FDX ? "Full" : "Half");
+
+        status = INB(i82559[1].io_address + SCBGenStatus);
+        os_printf("Interface 1 Link = %s, %s Mbps, %s Duplex\n",
+            status & GEN_STATUS_LINK ? "Up" : "Down",
+            status & GEN_STATUS_100MBPS ?  "100" : "10",
+            status & GEN_STATUS_FDX ? "Full" : "Half");
+
+        cyg_thread_delay(1000);
+    }
+}
+#endif // DISPLAY_STATISTICS
+#endif // KEEP_STATISTICS
+
+void
+dump_rfd(RFD *p_rfd, int anyway )
+{
+    cyg_uint32 rxstatus, tmp32;
+    cyg_uint16 tmp16;
+
+    HAL_READ_UINT32(p_rfd + RFD_STATUS, rxstatus);
+    if ( (0 != rxstatus) || anyway ) {
+        os_printf("RFD @ %x = ", (int)p_rfd);
+        os_printf("status = %x ", HAL_LE32TOC(rxstatus));
+        HAL_READ_UINT32(p_rfd + RFD_LINK, tmp32);
+        os_printf("link = %x ", HAL_LE32TOC(tmp32));
+//      HAL_READ_UINT32(p_rfd + RFD_RDB_ADDR, tmp32);
+//      os_printf("rdb_address = %x ", HAL_LE32TOC(rdb_address));
+        HAL_READ_UINT16(p_rfd + RFD_COUNT, tmp16);
+        tmp16 = HAL_LE16TOC(tmp16);
+        os_printf("count = %x ", (tmp16 & RFD_COUNT_MASK));
+        os_printf("f = %x ", (tmp16 & RFD_COUNT_F) ? 1 : 0);
+        os_printf("eof = %x ", (tmp16 & RFD_COUNT_EOF) ? 1 : 0);
+        HAL_READ_UINT16(p_rfd + RFD_SIZE, tmp16);
+        os_printf("size = %x\n", HAL_LE16TOC(tmp16));
+        // FIXME: HAL_BE16TOC surely? This is the network package
+        // header, right?
+        os_printf("[%04x %04x %04x] ",
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 0)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 2)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 4)));
+        os_printf("[%04x %04x %04x] %04x : ",          
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 6)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 8)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 10)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 12)));
+        os_printf("(%04x %04x %04x %04x) ",            
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 14)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 16)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 18)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 20)) );
+        os_printf("[%04x %04x %04x] ",                 
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 22)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 24)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 26)) );
+        os_printf("%d.%d.%d.%d ",
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 28)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 29)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 30)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 31)) );
+        os_printf("[%04x %04x %04x] ",                 
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 32)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 34)),
+                  *((cyg_uint16 *)(p_rfd + RFD_BUFFER + 36)) );
+        os_printf("%d.%d.%d.%d ...\n",
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 38)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 39)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 40)),
+                  *((cyg_uint8  *)(p_rfd + RFD_BUFFER + 41)) );
+    }
+}
+
+void
+dump_all_rfds( int intf )
+{
+    struct i82559* p_i82559 = i82559_priv_array[intf];
+    int i, j;
+    j = p_i82559->next_rx_descriptor;
+    os_printf("rx descriptors for interface %d (eth%d):\n", intf, intf );
+    for ( i = 0; i < MAX_RX_DESCRIPTORS; i++ )
+        dump_rfd( p_i82559->rx_ring[i], (i > (j-3) && (i <= j)) );
+    os_printf("next rx descriptor = %x\n\n", j);
+}
+
+
+void
+dump_packet(cyg_uint8 *p_buffer, int length)
+{
+    int count;
+
+    count = 0;
+    while ( length > 0 ) {
+        if ( count == 0 )
+            os_printf("\n");
+        count = (count + 1) & 0x0F;
+        os_printf("%02X ", *p_buffer++);
+        length--;
+    }
+    os_printf("\n");
+}
+
+// ------------------------------------------------------------------------
+
+// EOF if_i82559.c
--- a/packages/devs/serial/generic/16x5x/current/ChangeLog
+++ b/packages/devs/serial/generic/16x5x/current/ChangeLog
@@ -1,3 +1,8 @@
+2001-01-24  Dave Airlie  <airlied@parthus.com>
+
+	* src/ser_16x5x.c (pc_serial_DSR): Allow RX timeouts to be interpreted
+	as RXs.
+
 2000-12-19   Dave Airlie <airlied@parthus.com>
 
 	* src/ser_16x5x.c: Add defines for FIFO control register
--- a/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c
+++ b/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c
@@ -425,8 +425,9 @@ pc_serial_DSR(cyg_vector_t vector, cyg_u
     // is pending of the low bit of the isr is *0*, not 1.
     HAL_READ_UINT8(base+REG_isr, _isr);
     while ((_isr & ISR_nIP) == 0) {
-        switch (_isr&0x6) {
+        switch (_isr&0xE) {
         case ISR_Rx:
+        case ISR_RxTO:
         {
             cyg_uint8 _lsr;
             unsigned char c;
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -25,7 +25,7 @@
 #                                                                          
 # The Initial Developer of the Original Code is Red Hat.                   
 # Portions created by Red Hat are                                          
-# Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+# Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
 # All Rights Reserved.                                                     
 # -------------------------------------------                              
 #                                                                          
@@ -448,6 +448,15 @@ package CYGPKG_DEVS_ETH_POWERPC_QUICC {
         description     "Ethernet driver for PowerPC QUICC (MPC8xx) based boards."
 }
 
+package CYGPKG_DEVS_ETH_INTEL_I82559 {
+	alias 		{ "Intel 82559 ethernet driver"
+			   devs_eth_intel_i82559 i82559_eth_driver }
+	hardware
+	directory	devs/eth/intel/i82559
+	script		intel_i82559_eth_drivers.cdl
+        description     "Ethernet driver for Intel 82559 NIC."
+}
+
 
 
 # Not sure whether this should be "hardware"; if so, it should be mentioned
--- a/packages/hal/arm/arch/current/ChangeLog
+++ b/packages/hal/arm/arch/current/ChangeLog
@@ -1,3 +1,8 @@
+2001-01-24  Jonathan Larmour  <jlarmour@redhat.com>
+
+	* src/vectors.S (init_flag): Add explicit alignment, just in case.
+	From Ilko Iliev <iliev@caretec.at>
+
 2001-01-11  Hugo Tyson  <hmt@redhat.com>
 
 	* src/vectors.S (hal_dram_size): Create hal_dram_type in memory at
--- a/packages/hal/arm/arch/current/src/vectors.S
+++ b/packages/hal/arm/arch/current/src/vectors.S
@@ -976,6 +976,7 @@ PTR(__interrupt_stack)
         .data
 
 init_flag:
+        .balign 4
         .long   0
 
         .extern hal_default_isr
--- a/packages/hal/mips/arch/current/ChangeLog
+++ b/packages/hal/mips/arch/current/ChangeLog
@@ -1,3 +1,8 @@
+2001-01-25  Jesper Skov  <jskov@redhat.com>
+
+	* include/arch.inc: Allow hal_intc_decode to be defined by variant
+	or platform.
+
 2000-12-06  Jesper Skov  <jskov@redhat.com>
 
 	* include/hal_intr.h (HAL_DELAY_US): Added.
--- a/packages/hal/mips/arch/current/include/arch.inc
+++ b/packages/hal/mips/arch/current/include/arch.inc
@@ -293,6 +293,7 @@
 	.endm
 #endif
 
+#ifndef CYGPKG_HAL_MIPS_INTC_DECODE_DEFINED
 	.macro	hal_intc_decode vnum
 	mfc0	v0,cause		# get cause register
 	nop				# delay slot
@@ -302,6 +303,7 @@
 	add	v0,v0,v1		# index into table
 	lb	\vnum,0(v0)		# pick up vector number
 	.endm
+#endif
 
 #ifndef CYGPKG_HAL_MIPS_INTC_TRANSLATE_DEFINED
 #ifdef CYGIMP_HAL_COMMON_INTERRUPTS_CHAIN
--- a/packages/hal/powerpc/arch/current/ChangeLog
+++ b/packages/hal/powerpc/arch/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-24  Jesper Skov  <jskov@redhat.com>
+
+	* src/powerpc.ld: Added .sdata to .sdata pattern.
+
 2001-01-16  Gary Thomas  <gthomas@redhat.com>
 
 	* src/vectors.S (_start): Set up IRQ environment _before_ calling
--- a/packages/hal/powerpc/arch/current/src/powerpc.ld
+++ b/packages/hal/powerpc/arch/current/src/powerpc.ld
@@ -1,4 +1,4 @@
-/*==========================================================================
+//==========================================================================
 //
 //	powerpc.ld
 //
@@ -23,7 +23,7 @@
 //                                                                          
 // The Initial Developer of the Original Code is Red Hat.                   
 // Portions created by Red Hat are                                          
-// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
 // All Rights Reserved.                                                     
 // -------------------------------------------                              
 //                                                                          
@@ -38,7 +38,7 @@
 //
 //####DESCRIPTIONEND####
 //
-//========================================================================*/
+//==========================================================================
 STARTUP(vectors.o)
 ENTRY(__exception_reset)
 #ifdef EXTRAS
@@ -111,7 +111,7 @@ GROUP(libtarget.a libgcc.a)
       /* We want the small data sections together, so single-instruction */   \
       /* offsets can access them all, and initialized data all before    */   \
       /* uninitialized, so we can shorten the on-disk segment size.      */   \
-    __SDATA_START__ = ABSOLUTE(.); *(.sdata.*)                                 \
+    __SDATA_START__ = ABSOLUTE(.); *(.sdata) *(.sdata.*)                      \
     __SDATA2_START__ = ABSOLUTE(.); *(.sdata2*) }                             \
     > _region_                                                                \
     __rom_data_start = LOADADDR(.data);                                       \
--- a/packages/hal/powerpc/mbx/current/ChangeLog
+++ b/packages/hal/powerpc/mbx/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-19  Gary Thomas  <gthomas@redhat.com>
+
+	* include/hal_diag.h: Remove unwarranted disclaimer [commentary].
+
 2001-01-03  Gary Thomas  <gthomas@redhat.com>
 
 	* cdl/hal_powerpc_mbx.cdl: Let RTC [heartbeat] rate be user
--- a/packages/hal/powerpc/mbx/current/include/hal_diag.h
+++ b/packages/hal/powerpc/mbx/current/include/hal_diag.h
@@ -8,26 +8,6 @@
 //      HAL Support for Kernel Diagnostic Routines
 //
 //=============================================================================
-//####UNSUPPORTEDBEGIN####
-//
-// -------------------------------------------
-// This source file has been contributed to eCos/Red Hat. It may have been
-// changed slightly to provide an interface consistent with those of other 
-// files.
-//
-// The functionality and contents of this file is supplied "AS IS"
-// without any form of support and will not necessarily be kept up
-// to date by Red Hat.
-//
-// All inquiries about this file, or the functionality provided by it,
-// should be directed to the 'ecos-discuss' mailing list (see
-// http://sourceware.cygnus.com/ecos/intouch.html for details).
-//
-// Maintained by:  <Unmaintained>
-// -------------------------------------------
-//
-//####UNSUPPORTEDEND####
-//=============================================================================
 //####COPYRIGHTBEGIN####
 //                                                                          
 // -------------------------------------------                              
@@ -46,7 +26,7 @@
 //                                                                          
 // The Initial Developer of the Original Code is Red Hat.                   
 // Portions created by Red Hat are                                          
-// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
 // All Rights Reserved.                                                     
 // -------------------------------------------                              
 //                                                                          
--- a/packages/hal/sh/cq7708/current/ChangeLog
+++ b/packages/hal/sh/cq7708/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-23  Jesper Skov  <jskov@redhat.com>
+
+	* include/platform.inc: Properly init interrupt VSR.
+
 2000-11-22  Jesper Skov  <jskov@redhat.com>
 
 	* include/platform.inc: Mangle symbols.
--- a/packages/hal/sh/cq7708/current/include/platform.inc
+++ b/packages/hal/sh/cq7708/current/include/platform.inc
@@ -148,6 +148,7 @@ 2:
 	# Write interrupt vector
         mov.l   $hal_vsr_table,r3
 	mov.l   $cyg_hal_default_interrupt_vsr,r4
+	add	#CYGNUM_HAL_VECTOR_INTERRUPT*4,r3
 	mov.l   r4,@r3
 	bra	2f
 	 nop
--- a/packages/hal/sh/cq7750/current/ChangeLog
+++ b/packages/hal/sh/cq7750/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-23  Jesper Skov  <jskov@redhat.com>
+
+	* include/platform.inc: Properly init interrupt VSR.
+
 2000-11-22  Jesper Skov  <jskov@redhat.com>
 
 	* include/platform.inc: Mangle symbols.
--- a/packages/hal/sh/cq7750/current/include/platform.inc
+++ b/packages/hal/sh/cq7750/current/include/platform.inc
@@ -197,6 +197,7 @@ 2:
 	# Write interrupt vector
         mov.l   $hal_vsr_table,r3
 	mov.l   $cyg_hal_default_interrupt_vsr,r4
+	add	#CYGNUM_HAL_VECTOR_INTERRUPT*4,r3
 	mov.l   r4,@r3
 	bra	2f
 	 nop
--- a/packages/hal/sh/edk7708/current/ChangeLog
+++ b/packages/hal/sh/edk7708/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-23  Jesper Skov  <jskov@redhat.com>
+
+	* include/platform.inc: Properly init interrupt VSR.
+
 2000-11-22  Jesper Skov  <jskov@redhat.com>
 
 	* include/platform.inc: Mangle symbols.
--- a/packages/hal/sh/edk7708/current/include/platform.inc
+++ b/packages/hal/sh/edk7708/current/include/platform.inc
@@ -160,6 +160,7 @@ 2:
 	# Write interrupt vector
         mov.l   $hal_vsr_table,r3
 	mov.l   $cyg_hal_default_interrupt_vsr,r4
+	add	#CYGNUM_HAL_VECTOR_INTERRUPT*4,r3
 	mov.l   r4,@r3
 	bra	2f
 	 nop
--- a/packages/kernel/current/ChangeLog
+++ b/packages/kernel/current/ChangeLog
@@ -1,3 +1,7 @@
+2001-01-24  Jesper Skov  <jskov@redhat.com>
+
+	* src/sched/mlqueue.cxx (highpri): Fix trace call.
+
 2001-01-09  Nick Garnett  <nickg@cygnus.co.uk>
 
 	* include/mlqueue.hxx:
--- a/packages/kernel/current/src/sched/mlqueue.cxx
+++ b/packages/kernel/current/src/sched/mlqueue.cxx
@@ -552,7 +552,7 @@ Cyg_Thread *
 Cyg_ThreadQueue_Implementation::highpri(void)
 {
     CYG_REPORT_FUNCTYPE("returning thread %08x");
-    CYG_REPORT_RETVAL(queue);
+    CYG_REPORT_RETVAL(get_head());
     return get_head();
 }
 
new file mode 100644
--- /dev/null
+++ b/packages/pkgconf/fixhtml.tcl
@@ -0,0 +1,103 @@
+#!/bin/sh
+# the next line restarts using tclsh \
+ exec tclsh "$0" ${1+"$@"}
+
+#===============================================================================
+#
+#    fixhtml.tcl
+#
+#    Patch HTML files generated from DocBook sources.
+#
+#===============================================================================
+#####COPYRIGHTBEGIN####
+#                                                                 
+# =============================================================== 
+# Copyright (C) 2000, 2001 Red Hat, Inc.
+#
+# This file is part of the eCos host tools.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#                                                                 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc.,  59 Temple Place - Suite 330,
+# Boston, MA  02111-1307, USA. 
+#
+# =============================================================== 
+#
+#####COPYRIGHTEND####
+#===============================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):	bartv
+# Contributors:	bartv
+# Date:		2000-03-14
+# Purpose:      HTML files generated from DocBook sources using the nwalsh
+#               stylesheets have a number of problems. Most importantly,
+#               Netscape 4.x does not understand all of the character entities
+#               defined by HTML 4.0x
+#
+#####DESCRIPTIONEND####
+#===============================================================================
+#
+
+# Find out the current year for the copyright message. Ideally
+# this would be a range extracted from the sources, but that is
+# a little bit tricky.
+
+set year [clock format [clock seconds] -format "%Y"]
+
+# The generated files all have a .htm suffix rather than a .html
+# suffix. For now this is preserved, to avoid having to change all the
+# anchors. It might be better to rename all the files to .html in
+# future, and perhaps also to change book1.htm to index.htm
+
+set files [glob *.html]
+foreach file $files {
+    set status [catch {
+	
+	set fd [open $file "r"]
+	set data [read $fd]
+	close $fd
+
+	# If there is already a (C) message on the first line, skip this file.
+	if {[regexp {[^\n]*Copyright (C) [0-9]* Red Hat.*} $data] == 0} {
+
+
+	    # The DSSSL has the annoying habit of splitting tags over several lines.
+	    # This should sort things out.
+	    regsub -all "\n>" $data ">\n" data
+	    
+	    # Add a copyright banner
+	    set data [concat "<!-- Copyright (C) $year Red Hat, Inc. -->\n" $data]
+
+	    # Take care of some character entities that Netscape does not understand
+	    regsub -all "&mgr;"    $data "\\&#03BC;" data
+	    regsub -all "&mdash;"  $data "\\&#8212;" data
+	    regsub -all "&hellip;" $data "\\&#8230;" data
+	    regsub -all "&ldquo;"  $data "\\&#8220;" data
+	    regsub -all "&rdquo;"  $data "\\&#8221;" data
+
+	    # Now write the data back to the file. Do not bother to
+	    # keep an old version lying around, the html files can be
+	    # regenerated easily enough.
+	    set fd [open $file "w"]
+	    puts -nonewline $fd $data
+	    close $fd
+	}
+    } result]
+
+    if {0 != $status} {
+	puts "Error while processing file $file\n    $result"
+	exit 1
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/packages/pkgconf/rules.doc
@@ -0,0 +1,108 @@
+#=============================================================================
+#
+#    rules.doc
+#
+#    Additional rules for processing documentation written in DocBook/SGML
+#
+#=============================================================================
+#####COPYRIGHTBEGIN####
+#                                                                          
+# -------------------------------------------                              
+# The contents of this file are subject to the Red Hat eCos Public License 
+# Version 1.1 (the "License"); you may not use this file except in         
+# compliance with the License.  You may obtain a copy of the License at    
+# http://www.redhat.com/                                                   
+#                                                                          
+# Software distributed under the License is distributed on an "AS IS"      
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+# License for the specific language governing rights and limitations under 
+# the License.                                                             
+#                                                                          
+# The Original Code is eCos - Embedded Configurable Operating System,      
+# released September 30, 1998.                                             
+#                                                                          
+# The Initial Developer of the Original Code is Red Hat.                   
+# Portions created by Red Hat are                                          
+# Copyright (C) 2001 Red Hat, Inc.                             
+# All Rights Reserved.                                                     
+# -------------------------------------------                              
+#                                                                          
+#####COPYRIGHTEND####
+#=============================================================================
+#####DESCRIPTIONBEGIN####
+#
+# Author(s):     bartv
+# Date:          2001-01-11
+# Purpose:       Rules for processing documentation
+# Description:
+#     Each package's doc directory's makefile should define the
+#     following variables:
+#       TOPLEVEL   - of the component repository
+#       MAIN_SGML  - documentation entry point
+#       OTHER_SGML - any other .sgml files accessed from main
+#       PICTURES   - referenced by the SGML files
+#####DESCRIPTIONEND####
+#=============================================================================
+
+.PHONY: default check html pdf clean
+
+# Locations of the stylesheets and other SGML support files
+CATALOG          := /usr/lib/sgml/CATALOG
+MAIN_STYLESHEETS := /usr/lib/sgml/stylesheets/nwalsh-modular
+ECOS_STYLESHEET  := $(TOPLEVEL)/pkgconf/stylesheet.dsl
+FIXHTML          := $(TOPLEVEL)/pkgconf/fixhtml.tcl
+
+# The files that will be generated:
+ifeq (,$(MAIN_HTML))
+ MAIN_HTML        := $(subst .sgml,.html,$(MAIN_SGML))
+endif
+ifeq (,$(MAIN_PDF))
+ MAIN_PDF         := $(subst .sgml,.pdf,$(MAIN_SGML))
+endif
+
+# Rules for generating pictures
+GIFS := $(foreach x,$(PICTURES),$(x).gif)
+EPS  := $(foreach x,$(PICTURES),$(x).eps)
+
+%.gif: %.fig
+	convert -crop 0x0 $< $@
+
+%.eps: %.fig
+	convert -crop 0x0 $< $@
+
+default: check
+
+# Validating an sgml document can be achieved with 
+check: $(MAIN_SGML) $(OTHER_SGML) $(GIFS) $(EPS)
+	nsgmls -vs -c $(CATALOG) $<
+
+# Generating HTML from the SGML. In practice multiple .html files may
+# be generated, but for the purposes of dependency analysis the others
+# can be ignored.
+html: $(MAIN_HTML)
+
+$(MAIN_HTML): $(MAIN_SGML) $(OTHER_SGML) $(GIFS) $(ECOS_STYLESHEET) $(FIXHTML)
+	jade -t sgml -i html -d $(ECOS_STYLESHEET)#html $<
+	tclsh $(FIXHTML)
+
+# PDF files can be generated in a similar fashion.
+pdf: $(MAIN_PDF)
+
+$(MAIN_PDF):  $(MAIN_SGML) $(OTHER_SGML) $(EPS) $(ECOS_STYLESHEET)
+	jade -o $(subst .sgml,.tex,$(MAIN_SGML)) -t tex -V tex-backend -d $(ECOS_STYLESHEET)#print $<
+	pdfjadetex $(subst .sgml,.tex,$(MAIN_SGML))
+	pdfjadetex $(subst .sgml,.tex,$(MAIN_SGML))
+	pdfjadetex $(subst .sgml,.tex,$(MAIN_SGML))
+
+#$(MAIN_PDF):  $(MAIN_SGML) $(OTHER_SGML) $(EPS) $(ECOS_STYLESHEET)
+#	jade -o $(subst .sgml,.tex,$(MAIN_SGML)) -t tex -V tex-backend -d $(ECOS_STYLESHEET)#print $<
+#	jadetex $(subst .sgml,.tex,$(MAIN_SGML))
+#	jadetex $(subst .sgml,.tex,$(MAIN_SGML))
+#	jadetex $(subst .sgml,.tex,$(MAIN_SGML))
+#	dvips -o $(subst .sgml,.ps,$(MAIN_SGML)) $(subst .sgml,.dvi,$(MAIN_SGML))
+#	ps2pdf $(subst .sgml,.ps,$(MAIN_SGML)) $(subst .sgml,.pdf,$(MAIN_SGML))
+
+# Clean. For now assume that all .html, .gif etc files are generated
+clean:
+	rm -rf *.html *.tex *.dvi *.aux *.log *.ps *.pdf *.gif *.eps
+
new file mode 100644
--- /dev/null
+++ b/packages/pkgconf/stylesheet.dsl
@@ -0,0 +1,124 @@
+<!-- {{{ Banner                 -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     stylesheet.sgml                                             -->
+<!--                                                                 -->
+<!--     Customize the nwalsh modular stylesheets.                   -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2000 Red Hat, Inc.                                -->
+<!--                                                                 -->
+<!-- This file is part of the eCos host tools.                       -->
+<!--                                                                 -->
+<!-- This program is free software; you can redistribute it and/or   -->
+<!-- modify it under the terms of the GNU General Public License as  -->
+<!-- published by the Free Software Foundation; either version 2 of  -->
+<!-- the License, or (at your option) any later version.             -->
+<!--                                                                 -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of  -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   -->
+<!-- GNU General Public License for more details.                    -->
+<!--                                                                 -->
+<!-- You should have received a copy of the GNU General Public       -->
+<!-- License along with this program; if not, write to the Free      -->
+<!-- Software Foundation, Inc.,  59 Temple Place - Suite 330,        -->
+<!-- Boston, MA  02111-1307, USA.                                    -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- Author(s):   bartv                                              -->
+<!--              Based on cygnus-both.dsl by Mark Galassi           -->
+<!-- Contact(s):  bartv                                              -->
+<!-- Date:        2000/03/15                                         -->
+<!-- Version:     0.01                                               -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY % html "IGNORE">
+<![%html;[
+<!ENTITY % print "IGNORE">
+<!ENTITY docbook.dsl SYSTEM "/usr/lib/sgml/stylesheets/nwalsh-modular/html/docbook.dsl" CDATA dsssl>
+]]>
+<!ENTITY % print "INCLUDE">
+<![%print;[
+<!ENTITY docbook.dsl SYSTEM "/usr/lib/sgml/stylesheets/nwalsh-modular/print/docbook.dsl" CDATA dsssl>
+]]>
+]>
+
+<style-sheet>
+
+<style-specification id="print" use="docbook">
+<style-specification-body> 
+
+;; ====================
+;; customize the print stylesheet
+;; ====================
+
+;; Set the paper parameters as per other eCos documentation
+(define %page-width%   7.5in)
+(define %page-height%  10.2in)
+(define %left-margin%  0.75in)
+(define %right-margin% 0.75in)
+
+;; Assume that we are only producing books, a reasonable assumption
+;; given the primary author :-)
+(define %two-side% #t)
+
+;; Use 12pt
+;;(define %visual-acuity% "presbyopic")
+
+;; Do not use graphics in admonitions, our documentation is supposed
+;; to look boring :-(
+(define %admon-graphics% #f)
+
+;; Justified text please.
+(define %default-quadding% 'justify)
+
+;; A separate page for each man page please.
+(define %refentry-new-page% #t)
+
+;; The component writer's guide man pages do not describe functions
+(define %refentry-functions% #f)
+
+</style-specification-body>
+</style-specification>
+
+<!--
+;; ====================
+;; customize the html stylesheet
+;; ====================
+-->
+<style-specification id="html" use="docbook">
+<style-specification-body> 
+
+;; .html files please. 
+(define %html-ext% ".html")
+
+;; Boring admonitions
+(define %admon-graphics% #f)
+
+(define %shade-verbatim% #t)
+
+;; Use ID attributes as name for component HTML files?
+(define %use-id-as-filename% #t)
+
+</style-specification-body>
+</style-specification>
+
+<external-specification id="docbook" document="docbook.dsl">
+
+</style-sheet>
+
--- a/packages/redboot/current/ChangeLog
+++ b/packages/redboot/current/ChangeLog
@@ -1,3 +1,27 @@
+2001-01-24  Jonathan Larmour  <jlarmour@redhat.com>
+
+	* src/main.c (cyg_start): Rework last change to use more generic
+	HAL_MEM_REAL_REGION_TOP macro.
+
+2001-01-24  Hugo Tyson  <hmt@redhat.com>
+
+	* src/main.c (cyg_start): Take notice of the hal_dram_size
+	variable (only supported on ARMs) to set ram_end.  The symbols
+	given by the CYGMEM_REGION_ram symbols are minima or defaults.
+
+2001-01-22  Gary Thomas  <gthomas@redhat.com>
+
+	* src/net/inet_addr.c (inet_aton): Fix byte order on big endian systems.
+
+	* src/net/icmp.c (__icmp_install_listener): 
+	(__icmp_remove_listener): New functions.
+	(__icmp_handler): Call listener for unhandled packets.
+
+	* include/net/net.h: Add handler for ICMP [incoming] data.
+
+	* cdl/redboot.cdl: 
+	* src/net/ping.c: New CLI command - ping a host.
+
 2001-01-18  Gary Thomas  <gthomas@redhat.com>
 
 	* include/net/net.h: 
--- a/packages/redboot/current/cdl/redboot.cdl
+++ b/packages/redboot/current/cdl/redboot.cdl
@@ -23,7 +23,7 @@
 #                                                                          
 # The Initial Developer of the Original Code is Red Hat.                   
 # Portions created by Red Hat are                                          
-# Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+# Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
 # All Rights Reserved.                                                     
 # -------------------------------------------                              
 #                                                                          
@@ -97,6 +97,7 @@ cdl_package CYGPKG_REDBOOT {
 	compile net/bootp.c net/udp.c net/ip.c net/pktbuf.c net/cksum.c
 	compile net/enet.c net/icmp.c net/tcp.c net/timers.c net/arp.c
 	compile net/tftp_client.c net/net_io.c net/inet_addr.c
+	compile -library=libextras.a net/ping.c
         description "This option includes networking support in RedBoot."
         define_proc {
             puts $::cdl_system_header "#define CYGNUM_HAL_VIRTUAL_VECTOR_AUX_CHANNELS 1"
--- a/packages/redboot/current/include/net/net.h
+++ b/packages/redboot/current/include/net/net.h
@@ -257,7 +257,6 @@ typedef struct {
     word	seqnum;
 } icmp_header_t;
 
-
 typedef struct _pktbuf {
     struct _pktbuf *next;
     union {
@@ -283,6 +282,8 @@ typedef struct _pktbuf {
 /* protocol handler */
 typedef void (*pkt_handler_t)(pktbuf_t *pkt);
 
+/* ICMP fielder */
+typedef void (*icmp_handler_t)(pktbuf_t *pkt, ip_route_t *src_route);
 
 typedef struct _udp_socket {
     struct _udp_socket	*next;
@@ -448,6 +449,8 @@ extern void __ip_send(pktbuf_t *pkt, int
  * Handle incoming ICMP packets.
  */
 extern void __icmp_handler(pktbuf_t *pkt, ip_route_t *r);
+extern int  __icmp_install_listener(icmp_handler_t handler);
+extern void __icmp_remove_listener(void);
 
 /*
  * Handle incoming UDP packets.
--- a/packages/redboot/current/src/main.c
+++ b/packages/redboot/current/src/main.c
@@ -143,6 +143,12 @@ cyg_start(void)
 
     ram_start = (unsigned char *)CYGMEM_REGION_ram;
     ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
+#ifdef HAL_MEM_REAL_REGION_TOP
+    {
+        unsigned char *ram_end_tmp = ram_end;
+        ram_end = HAL_MEM_REAL_REGION_TOP( ram_end_tmp );
+    }
+#endif
 
     bist();
 
--- a/packages/redboot/current/src/net/icmp.c
+++ b/packages/redboot/current/src/net/icmp.c
@@ -23,7 +23,7 @@
 //                                                                          
 // The Initial Developer of the Original Code is Red Hat.                   
 // Portions created by Red Hat are                                          
-// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
 // All Rights Reserved.                                                     
 // -------------------------------------------                              
 //                                                                          
@@ -48,6 +48,33 @@
 /*
  * Handle ICMP packets.
  */
+
+static icmp_handler_t icmp_handler;
+
+/*
+ * Install a handler for incoming icmp packets.
+ * Returns zero if successful, -1 if socket is already used.
+ */
+int
+__icmp_install_listener(icmp_handler_t handler)
+{
+    if (icmp_handler) {
+        return -1;
+    }
+    icmp_handler = handler;
+    return 0;
+}
+
+
+/*
+ * Remove the handler
+ */
+void
+__icmp_remove_listener(void)
+{
+    icmp_handler = (icmp_handler_t)NULL;
+}
+
 void
 __icmp_handler(pktbuf_t *pkt, ip_route_t *r)
 {
@@ -65,6 +92,8 @@ void
 	BSPLOG(bsp_log("icmp: seq<%d>\n", pkt->icmp_hdr->seqnum));
 
 	__ip_send(pkt, IP_PROTO_ICMP, r);
+    } else if (icmp_handler) {
+        (*icmp_handler)(pkt, r);
     }
     __pktbuf_free(pkt);
 }
--- a/packages/redboot/current/src/net/inet_addr.c
+++ b/packages/redboot/current/src/net/inet_addr.c
@@ -23,7 +23,7 @@
 //                                                                          
 // The Initial Developer of the Original Code is Red Hat.                   
 // Portions created by Red Hat are                                          
-// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.                             
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
 // All Rights Reserved.                                                     
 // -------------------------------------------                              
 //                                                                          
@@ -76,7 +76,11 @@ inet_aton(char *s, in_addr_t *addr)
             }
         }
         // merge result
+#ifdef __LITTLE_ENDIAN__
         res |= val << ((3-i)*8);  // 24, 16, 8, 0
+#else
+        res = (res << 8) | val;
+#endif
     }
     addr->s_addr = htonl(res);
     return true;
new file mode 100644
--- /dev/null
+++ b/packages/redboot/current/src/net/ping.c
@@ -0,0 +1,211 @@
+//==========================================================================
+//
+//      ping.c
+//
+//      Network utility - ping
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//                                                                          
+// -------------------------------------------                              
+// The contents of this file are subject to the Red Hat eCos Public License 
+// Version 1.1 (the "License"); you may not use this file except in         
+// compliance with the License.  You may obtain a copy of the License at    
+// http://www.redhat.com/                                                   
+//                                                                          
+// Software distributed under the License is distributed on an "AS IS"      
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the 
+// License for the specific language governing rights and limitations under 
+// the License.                                                             
+//                                                                          
+// The Original Code is eCos - Embedded Configurable Operating System,      
+// released September 30, 1998.                                             
+//                                                                          
+// The Initial Developer of the Original Code is Red Hat.                   
+// Portions created by Red Hat are                                          
+// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.                             
+// All Rights Reserved.                                                     
+// -------------------------------------------                              
+//                                                                          
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2001-01-22
+// Purpose:      
+// Description:  
+//              
+// This code is part of RedBoot (tm).
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <redboot.h>
+#include <net/net.h>
+
+#ifndef CYGPKG_REDBOOT_NETWORKING
+#error CYGPKG_REDBOOT_NETWORKING required!
+#else
+
+static void do_ping(int argc, char *argv[]);
+RedBoot_cmd("ping", 
+            "Network connectivity test",
+            "[-v] [-n <count>] [-t <timeout>] [-i <IP_addr>] -h <IP_addr>",
+            do_ping
+    );
+
+static bool icmp_received;
+static icmp_header_t hold_hdr;
+
+static void
+handle_icmp(pktbuf_t *pkt, ip_route_t *src_route)
+{
+    icmp_header_t *icmp;
+
+    icmp = pkt->icmp_hdr;
+    memcpy(&hold_hdr, icmp, sizeof(*icmp));
+    icmp_received = true;
+}
+
+static void
+do_ping(int argc, char *argv[])
+{
+    struct option_info opts[7];
+    long count, timeout, length, rate, start_time, end_time, timer, received, tries;
+    char *local_ip_addr, *host_ip_addr;
+    bool local_ip_addr_set, host_ip_addr_set, count_set, 
+        timeout_set, length_set, rate_set, verbose;
+    struct sockaddr_in local_addr, host_addr;
+    ip_addr_t hold_addr;
+    icmp_header_t *icmp;
+    pktbuf_t *pkt;
+    ip_header_t *ip;
+    unsigned short cksum;
+    ip_route_t dest_ip;
+
+    init_opts(&opts[0], 'n', true, OPTION_ARG_TYPE_NUM, 
+              (void **)&count, (bool *)&count_set, "<count> - number of packets to test");
+    init_opts(&opts[1], 't', true, OPTION_ARG_TYPE_NUM, 
+              (void **)&timeout, (bool *)&timeout_set, "<timeout> - max #ms per packet [rount trip]");
+    init_opts(&opts[2], 'i', true, OPTION_ARG_TYPE_STR, 
+              (void **)&local_ip_addr, (bool *)&local_ip_addr_set, "local IP address");
+    init_opts(&opts[3], 'h', true, OPTION_ARG_TYPE_STR, 
+              (void **)&host_ip_addr, (bool *)&host_ip_addr_set, "host IP address");
+    init_opts(&opts[4], 'l', true, OPTION_ARG_TYPE_NUM, 
+              (void **)&length, (bool *)&length_set, "<length> - size of payload");
+    init_opts(&opts[5], 'v', false, OPTION_ARG_TYPE_FLG, 
+              (void **)&verbose, (bool *)0, "verbose operation");
+    init_opts(&opts[6], 'r', true, OPTION_ARG_TYPE_NUM, 
+              (void **)&rate, (bool *)&rate_set, "<rate> - time between packets");
+    if (!scan_opts(argc, argv, 1, opts, 7, (void **)0, 0, "")) {
+        printf("PING - Invalid option specified\n");
+        return;
+    }   
+    // Set defaults; this has to be done _after_ the scan, since it will
+    // have destroyed all values not explicitly set.
+    if (local_ip_addr_set) {
+        if (!inet_aton(local_ip_addr, (in_addr_t *)&local_addr)) {
+            printf("PING - Invalid IP address: %s\n", local_ip_addr);
+            return;
+        }
+    } else {
+        memcpy((in_addr_t *)&local_addr, __local_ip_addr, sizeof(__local_ip_addr));
+    }
+    if (host_ip_addr_set) {
+        if (!inet_aton(host_ip_addr, (in_addr_t *)&host_addr)) {
+            printf("PING - Invalid IP address: %s\n", host_ip_addr);
+            return;
+        }
+        if (__arp_lookup((ip_addr_t *)&host_addr.sin_addr, &dest_ip) < 0) {
+            printf("PING: Can't find address of server '%s'\n", host_ip_addr);
+            return;
+        }
+    } else {
+        printf("PING - host IP address required\n");
+        return;
+    }
+#define DEFAULT_LENGTH   64
+#define DEFAULT_COUNT    10
+#define DEFAULT_TIMEOUT  1000
+#define DEFAULT_RATE     1000
+    if (!rate_set) {
+        rate = DEFAULT_RATE;
+    }
+    if (!length_set) {
+        length = DEFAULT_LENGTH;
+    }
+    if (!count_set) {
+        count = DEFAULT_COUNT;
+    }
+    if (!timeout_set) {
+        timeout = DEFAULT_TIMEOUT;
+    }
+    // Note: two prints here because 'inet_ntoa' returns a static pointer
+    printf("Network PING - from %s",
+           inet_ntoa((in_addr_t *)&local_addr));
+    printf(" to %s\n",
+           inet_ntoa((in_addr_t *)&host_addr));
+    received = 0;    
+    __icmp_install_listener(handle_icmp);
+    for (tries = 0;  tries < count;  tries++) {
+        // The network stack uses the global variable '__local_ip_addr'
+        memcpy(hold_addr, __local_ip_addr, sizeof(hold_addr));
+        memcpy(__local_ip_addr, &local_addr, sizeof(__local_ip_addr));
+        // Build 'ping' request
+        if ((pkt = __pktbuf_alloc(ETH_MAX_PKTLEN)) == NULL) {
+            // Give up if no packets - something is wrong
+            break;
+        }
+
+        icmp = pkt->icmp_hdr;
+        ip = pkt->ip_hdr;
+        pkt->pkt_bytes = length + sizeof(icmp_header_t);
+
+	icmp->type = ICMP_TYPE_ECHOREQUEST;
+        icmp->code = 0;
+	icmp->checksum = 0;
+        icmp->seqnum = htons(tries+1);
+        cksum = __sum((word *)icmp, pkt->pkt_bytes, 0);
+	icmp->checksum = htons(cksum);
+	
+        memcpy(ip->source, (in_addr_t *)&local_addr, sizeof(ip_addr_t));
+        memcpy(ip->destination, (in_addr_t *)&host_addr, sizeof(ip_addr_t));
+        ip->protocol = IP_PROTO_ICMP;
+        ip->length = htons(pkt->pkt_bytes);
+
+        __ip_send(pkt, IP_PROTO_ICMP, &dest_ip);
+        __pktbuf_free(pkt);
+
+        start_time = MS_TICKS();
+        timer = start_time + timeout;
+        icmp_received = false;
+        while (!icmp_received && (MS_TICKS() < timer)) {
+            __enet_poll();
+        } 
+        end_time = MS_TICKS();
+
+        timer = MS_TICKS() + rate;
+        while (MS_TICKS() < timer) {
+            __enet_poll();
+        } 
+
+        // Clean up
+        memcpy(__local_ip_addr, &hold_addr, sizeof(__local_ip_addr));
+
+        if (icmp_received) {
+            received++;
+            if (verbose) {
+                printf("icmp - seq: %d, time: %d (ticks)\n",
+                       ntohs(hold_hdr.seqnum), end_time-start_time);
+            }
+        }
+    }
+    __icmp_remove_listener();
+    // Report
+    printf("PING - received %ld of %ld expected\n", received, count);
+}
+
+#endif //CYGPKG_REDBOOT_NETWORKING