This is the mail archive of the ecos-patches@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: RealTek 8139 driver, 4. revision


On Tue, 2003-11-11 at 08:59, Eric Doenges wrote:
> Hi,
> 
> 
> this is the fourth (and hopefully final =8^) revision of my RealTek
> 8139 driver. Compared to the 3. revision released way back in August,
> the only changes are in the documentation and the PC-specific
> .inl file, which now tells the driver to handle cache coherency in
> software. The same limitations that existed in August still apply:
> 
> a) The driver assumes the MAC address, media selection, etc. is
>     configured via an EEPROM; these settings cannot be changed by the
>     driver.
> 
> b) The 'twister' cannot be tuned.
> 
> c) Interrupt muxing like the Intel 82559 driver has is not supported.
>     If multiple 8139s share one interrupt, chained interrupts have to
>     be enabled for the HAL.
> 
> d) The multicast acceptance filter code is completely untested, since
>     I have no multicast test bed. A kind soul recommended testing with
>     an IPv6 network; however, I don't have that either.
> 
> e) All testing has been done on a custom architecture (Equator BSP),
>     not on a i386 PC like the included (sample) .inl file might suggest.
>     (This is because I totally failed to get eCos to boot on my PC at
>     home). As a result, it may not work as expected on other platforms.
> 
> f) It's slow. The 8139 is a low-cost chip that makes heavy demands on
>     the CPU. You need a fast target to get anywhere near 100MBit/s
>     performance with this chip (this is not really a driver problem -
>     Linux on the same hardware is only marginally faster).
> 
> One more thing - RedHat has now confirmed my copyright assignment, so
> the driver can now go into the CVS repository.
> 
> Enjoy,

Commited, along with ChangeLog entries (**PLEASE folks, don't forget
these!)  I also had to make up the ecos.db entries :-(

-- 
Gary Thomas <gary@mlbassoc.com>
MLB Associates
Index: ChangeLog
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/ChangeLog,v
retrieving revision 1.127
diff -u -5 -p -r1.127 ChangeLog
--- ChangeLog	9 Nov 2003 23:09:50 -0000	1.127
+++ ChangeLog	13 Nov 2003 13:35:32 -0000
@@ -72,10 +72,14 @@
 
 	* ecos.db: Added new packages CYGPKG_DEVS_FLASH_SST_39VF400 and
 	CYGPKG_DEVS_FLASH_ARM_E7T.  Updated e7t target to include FLASH
 	drivers.
 
+2003-07-09  Eric Doenges <Eric.Doenges@DynaPel.com>
+
+	* ecos.db: Add Realtek 8139 (PCI) ethernet driver.
+
 2003-06-12  John Dallaway  <jld@ecoscentric.com>
 
 	* ecosadmin.tcl: Add repository merge capability (undocumented and
 	unsupported at present).
 
Index: ecos.db
===================================================================
RCS file: /misc/cvsfiles/ecos/packages/ecos.db,v
retrieving revision 1.111
diff -u -5 -p -r1.111 ecos.db
--- ecos.db	9 Nov 2003 23:09:50 -0000	1.111
+++ ecos.db	12 Nov 2003 16:38:18 -0000
@@ -5258,10 +5258,48 @@ target moab {
 }
 ##-------------------------------------------------------------------------------------------
 
 # --------------------------------------------------------------------------
 
+# Realtek 8139 (PCI) Ethernet driver
+package CYGPKG_DEVS_ETH_RLTK_8139 {
+	alias 		{ "Realtek 8139 ethernet driver" rltk8139_eth_driver }
+	hardware
+	directory	devs/eth/rltk/8139
+	script		rltk_8139_eth_drivers.cdl
+        description     "Ethernet driver for Realtek 8139 (PCI) card."
+}
+
+package CYGPKG_DEVS_ETH_I386_PC_RLTK8139 {
+	alias 		{ "Intel PC with Realtek 8139 ethernet driver" pc_rltk8139_eth_driver }
+	hardware
+	directory	devs/eth/i386/pc/rltk8139
+	script		i386_pc_rltk8139_eth_drivers.cdl
+        description     "Intel PC using Realtek 8139 (PCI) card."
+}
+
+target pc_rltk8139 {
+        alias		{ "i386 PC target using Realtek 8139 networking" }
+	packages        { CYGPKG_HAL_I386
+                          CYGPKG_HAL_I386_GENERIC
+                          CYGPKG_HAL_I386_PC
+                          CYGPKG_HAL_I386_PCMB
+			  CYGPKG_IO_PCI
+                          CYGPKG_IO_SERIAL_GENERIC_16X5X
+	                  CYGPKG_IO_SERIAL_I386_PC
+			  CYGPKG_DEVS_ETH_RLTK_8139
+			  CYGPKG_DEVS_ETH_I386_PC_RLTK8139
+                          CYGPKG_DEVICES_WALLCLOCK_DALLAS_DS12887
+                          CYGPKG_DEVICES_WALLCLOCK_I386_PC
+        }
+        description "
+    	    The pc target provides the packages needed to run eCos binaries 
+            on a standard i386 PC motherboard, using a Realtek 8139 network card."
+}
+
+# --------------------------------------------------------------------------
+
 package CYGPKG_VNC_SERVER {
     alias       { "VNC server" vnc_server }
     directory   net/vnc_server
     script      vnc-server.cdl
     description "VNC server."
Index: devs/eth/rltk/8139/current/ChangeLog
===================================================================
RCS file: devs/eth/rltk/8139/current/ChangeLog
diff -N devs/eth/rltk/8139/current/ChangeLog
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/rltk/8139/current/ChangeLog	13 Nov 2003 13:36:29 -0000
@@ -0,0 +1,43 @@
+2003-07-09  Eric Doenges <Eric.Doenges@DynaPel.com>
+
+	* src/if_8139.h: 
+	* src/if_8139.c: 
+	* doc/README: 
+	* cdl/rltk_8139_eth_drivers.cdl: 
+	New package - PCI ethernet driver for RTL8139 cards,
+	(using the Intel 82259 driver as inspiration).
+	
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
Index: devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl
===================================================================
RCS file: devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl
diff -N devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/rltk/8139/current/cdl/rltk_8139_eth_drivers.cdl	6 Aug 2003 14:24:07 -0000
@@ -0,0 +1,171 @@
+# ====================================================================
+#
+#	rltk_8139_eth_drivers.cdl
+#
+#	RealTek 8139 ethernet driver
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      Eric Doenges
+# Original data:
+# Contributors:
+# Date:           2003-07-16
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_RLTK_8139 {
+    display       "RealTek 8139 ethernet driver"
+    description   "Ethernet driver for RealTek 8139 controller."
+
+    parent        CYGPKG_IO_ETH_DRIVERS
+    active_if     CYGPKG_IO_ETH_DRIVERS
+    active_if     CYGINT_DEVS_ETH_RLTK_8139_REQUIRED
+
+    implements    CYGINT_IO_ETH_MULTICAST
+
+    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/8139_info.h
+    # and tell them that it is available
+    define_proc {
+	    puts $::cdl_system_header \
+      "#define CYGBLD_DEVS_ETH_DEVICE_H <pkgconf/devs_eth_rltk_8139.h>"
+
+      puts $::cdl_header "#include CYGDAT_DEVS_ETH_RLTK_8139_CFG";
+    }
+
+    compile       -library=libextras.a if_8139.c
+
+    cdl_component CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS {
+      display "Share interrupt with other devices"
+      default_value 1
+      description "
+        If this option is enabled, the driver does not assume that it is
+        in sole possession of the interrupt pin used by the 8139."
+
+      cdl_option CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 {
+        display "Mask 8139 interrupts on chip"
+        default_value 1
+        description "
+          If this option is enabled, the driver masks interrupts in the 8139's
+          status register, and does not mask the interrupt vector. This is
+          only useful if the 8139 must share it's interrupt line with other
+          devices."
+      }
+    }
+
+    cdl_option CYGDBG_DEVS_ETH_RLTK_8139_CHATTER {
+      display "Print debugging messages"
+      default_value 0
+      description   "
+        If this option is set, a lot of debugging messages are printed
+        to the console to help debug the driver."
+    }
+
+#    cdl_component CYGDBG_DEVS_ETH_RLTK_8139_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_RLTK_8139_KEEP_8139_STATISTICS {
+#	    display "Keep RealTek 8139 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_RLTK_8139_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_option CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX {
+        display       "Size of the receive ring"
+        flavor  data
+				legal_values  0 to 2
+        default_value { CYGPKG_REDBOOT ? 0 : 2 }
+        define        RX_BUF_LEN_IDX
+        description   "
+                The 8139 stores all received packets in a single 'rx ring'
+                located somewhere in physical memory. The size of this ring
+                can be varied from ~8k to ~64k; however the driver currently
+                supports a maximum buffer size of only ~32k (so we can use
+                the 8139's WRAP mode). The actual buffer size is
+                8192<<x + 16 + 1536 bytes, with x being the value of this
+                option."
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_RLTK_8139_OPTIONS {
+        display "RealTek 8139 ethernet driver build options"
+        flavor  none
+	      no_define
+
+        cdl_option CYGPKG_DEVS_ETH_RLTK_8139_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 RealTek 8139 ethernet driver package. These
+                flags are used in addition to the set of global flags."
+        }
+    }
+}
+# EOF rltk_8139_eth_drivers.cdl
Index: devs/eth/rltk/8139/current/doc/README
===================================================================
RCS file: devs/eth/rltk/8139/current/doc/README
diff -N devs/eth/rltk/8139/current/doc/README
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/rltk/8139/current/doc/README	11 Nov 2003 15:13:10 -0000
@@ -0,0 +1,164 @@
+Some notes on the RealTek 8139 driver
+
+
+1. Using the driver
+
+This driver follows the customization model used by many other drivers
+to separate those parts of the code that are device specific from those
+that are platform specific by requiring two packages to actually use the
+driver -- the driver itself and a platform glue package that contains
+only a .cdl and an .inl file (see the devs/i386/pc/rltk8139 package for
+an example).
+
+Both the driver and the glue packages must be added to the package
+database before you can use them. My entries look like this:
+
+package CYGPKG_DEVS_ETH_RLTK_8139 {
+  alias     { "RealTek 8139 ethernet driver"
+              devs_eth_rltk_8139 8139_eth_driver }
+  hardware
+  directory devs/eth/rltk/8139
+  script    rltk_8139_eth_drivers.cdl
+        description     "Ethernet driver for RealTek 8139 NIC."
+}
+
+and
+
+package CYGPKG_DEVS_ETH_I386_RLTK8139 {
+  alias     { "Standard PC with RealTek 8139 ethernet device"
+              devs_eth_i386_pc_rltk8139 }
+  hardware
+  directory devs/eth/i386/pc/rltk8139
+  script    i386_pc_rltk8139_eth_drivers.cdl
+  description "Ethernet driver for the RealTek 8139 family of chips."
+}
+
+Finally, you will need to create a new target that includes the RealTek
+driver. The easiest way to this is copy an existing target and add the
+two packages defined above (and removing the Intel 82259 packages in case
+of an i386 pc target).
+
+
+2. Cache Coherency
+
+Since the 8139 reads data directly from memory via the PCI bus, you may
+have to worry about data cache coherency. For eCos, there are basically
+three cases (turning the data cache off is not considered a serious solution):
+
+a. Either the CPU has no data cache, or the CPU has cache snooping logic
+that will detect memory accesses by PCI bus master devices and flush the cache
+when necessary. In this case, nothing special needs to be done.
+
+b. The MMU is configured to access memory uncached in a certain address space.
+In this case, the macro CYGARC_UNCACHED_ADDRESS() can be used to convert
+normal (cached) into uncached accesses. The driver always uses this macro for
+accessing the transmit and receive buffers, since if the HAL doesn't
+support this mechanism, the macro does nothing and no harm is done.
+
+c. The data cache needs to be flushed/invalidated by the driver. In this case,
+you must define CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY in the
+platform specific .inl file. Furthermore, the HAL macros HAL_DCACHE_INVALIDATE
+and HAL_DCACHE_FLUSH must be defined. Next, you must ensure that the buffers
+are aligned to cache line boundaries; otherwise, the code could fail in
+mysterious ways.
+
+One way to do this is to define the following in the .inl file:
+
+#define CACHE_ALIGNED __attribute__ ((aligned (HAL_DCACHE_LINE_SIZE)))
+
+Then, use this attribute on the transmit and receive buffer definitions:
+
+static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN] CACHE_ALIGNED;
+
+Note that this may fail for long cache lines, since the 'aligned' attribute
+does not allow arbitrarily large alignment parameters. Unfortunately, the gcc
+documentation does not say what the maximum alignment that can be specified
+is. Additionally, the linker may also be limited in the maximum alignment that
+can be used. In such cases, you'll have to bite the bullet and define more
+space than would be strictly necessary, and ensure the necessary alignment
+like this:
+
+static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE];
+
+Then, reference the buffers in the Rltk8139 definition like this:
+
+(cyg_uint8 *)((int)(&rltk8139_eth0_rx_ring[0] + HAL_DCACHE_LINE_SIZE)
+                    & ~(HAL_DCACHE_LINE_SIZE - 1))
+
+This assumes the cache line size is a power of 2; this is the case for all
+CPUs I know of. It also assumes an int can hold a pointer; if this is
+not true for your platform, use an integral type that can.
+
+Another thing to watch out for is that the buffers should also end on
+a cache line boundary. If your linker places the buffers sequentially in
+memory, you will only have to do this for the last buffer defined (since
+all buffers will start on cache line boundaries):
+
+static cyg_uint8
+rltk8139_eth0_tx_buffer[(TX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE - 1)
+                        & ~(HAL_DCACHE_LINE_SIZE - 1)] CACHE_ALIGNED;
+
+
+3. Interrupt sharing
+
+If the 8139 must share it's interrupt request line with other devices, the
+HAL option 'chained interrupts' must be enabled. The 8139 driver does not
+support IRQ muxing like the Intel 82559 driver does (see also *Limitations*).
+
+The driver's ISR does not clear the interrupt status bits since I believe this
+should only be done after the conditions that caused those bits to be set
+have been handled by the '_deliver' routine. Instead, the interrupt is masked.
+There are two ways to do this (configurable with a CDL option):
+
+a. The interrupt vector is masked. Personally I think this is a bad idea
+   because this will also block interrupts from all other devices sharing
+   this interrupt until the network thread gets around to calling the
+   '_deliver' routine.
+
+b. Mask the interrupt request using the 8139's interrupt mask register. This
+   way, other devices' interrupt requests can still be serviced. Enable the
+   CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139 option to use this.
+
+
+4. Limitations
+
+There are a number of limitations associated with this driver:
+
+a. The configuration of the NIC (MAC address, media selection, etc.) is
+   loaded from the serial EEPROM (which is assumed to exist) and cannot be
+   changed either at compile or run time.
+
+b. The 'twister' cannot be tuned. As far as I can make out, the 'twister'
+   can be tuned to improve signal quality over long lines. The RealTek
+   data sheet does not document the twister; and the code in the Linux
+   driver that does this is totally incomprehensible to me.
+
+c. If multiple 8139s share the same interrupt, chained interrupts have to
+   be used. No IRQ MUXing (like the Intel 82559 driver has) is supported.
+
+d. Programming the multicast acceptance filter is now implemented, but not
+   tested because eCos doesn't have such a test program (or at least I
+   couldn't find any). Since I have never used multicasting myself, I don't
+   feel competent to write one. Someone suggested setting up an IPv6 network
+   for testing, since it seems IPv6 makes use of multicasting in normal
+   operation, but I haven't got around to doing that.
+
+e. It's fairly slow. This is not really the driver's fault - the 8139 requires
+   a fast CPU to get anything approaching decent speed because all messages
+   have to be copied around in memory.
+
+
+5. Credits
+
+The 8139's data sheet is not really all that helpful, since it contains
+a lot of omissions and some data that is simply incorrect. As such, I am
+indebted to Bill Paul for his well-documented OpenBSD driver, which was
+invaluable for figuring out how the chip is supposed to work. The idea of
+using 'enum' instead of '#define' came from the Linux 8139 driver, which I
+initially wanted to port to eCos, but didn't because I found it extremely
+hard to read and understand. (Note that I didn't copy any code from those
+drivers to avoid tainting eCos' license). The basic structure of the driver
+and .cdl files was taken from the eCos i82559 driver.
+
+I'd also like all the people who have downloaded and tested the driver, and
+contributed bug reports and fixes.
Index: devs/eth/rltk/8139/current/src/if_8139.c
===================================================================
RCS file: devs/eth/rltk/8139/current/src/if_8139.c
diff -N devs/eth/rltk/8139/current/src/if_8139.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/rltk/8139/current/src/if_8139.c	18 Sep 2003 08:57:38 -0000
@@ -0,0 +1,1325 @@
+//==========================================================================
+//
+//      if_8139.c
+//
+//	RealTek 8139 ethernet driver
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####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):    Eric Doenges
+// Contributors: Chris Nimmers, Gary Thomas, Andy Dyer
+// Date:         2003-07-09
+// Purpose:
+// Description:  hardware driver for RealTek 8139 ethernet
+// Notes:        This is a very basic driver that will send and receive
+//               packets and not much else. A lot of features of the 8139
+//               are not supported (power management, MII interface,
+//               access to the serial eeprom, 'twister tuning', etc.).
+//
+//               Many of the configuration options (like media type and
+//               speed) the 8139 has are taken directly from the serial
+//               eeprom and are not currently configurable from this driver.
+//
+//               I've tentatively added some code to handle cache coherency
+//               issues for platforms that do not have a separate address
+//               space for uncached memory access and do not do cache
+//               snooping for PCI bus masters. This code can be activated by
+//               defining CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+//               in the platform specific .inl file. Note that if
+//               CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY is
+//               defined, the .inl file is also responsible for making sure
+//               the receive and transmit buffers are located in memory in
+//               such a way that flushing or invalidating cache lines for
+//               these buffers will not affect any other buffers. See the
+//               README in the doc directory for some suggestions on how
+//               to do this.
+//
+//               Since the official data sheet for this chip is a bit
+//               vague, I had to look at the Linux and OpenBSD drivers to
+//               understand the basic workings of the chip; however, I have
+//               not copied any code from those drivers to avoid tainting
+//               eCos' license.
+//
+//        FIXME:
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+#include <pkgconf/system.h>
+#ifdef CYGPKG_IO_ETH_DRIVERS
+#include <pkgconf/io_eth_drivers.h>
+#endif
+#include <pkgconf/devs_eth_rltk_8139.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/cyg_ass.h>
+#include <cyg/infra/diag.h>
+#include <cyg/hal/hal_arch.h>
+#include <cyg/hal/drv_api.h>
+#include <cyg/hal/hal_cache.h>
+#include <cyg/io/eth/netdev.h>
+#include <cyg/io/eth/eth_drv.h>
+
+#include <string.h> /* for memset */
+
+#ifdef CYGPKG_IO_PCI
+#include <cyg/io/pci.h>
+#else
+#error "This driver requires the PCI package (CYGPKG_IO_PCI)"
+#endif
+
+#include <cyg/io/pci.h>
+
+/* Necessary for memory mapping macros */
+#include CYGHWR_MEMORY_LAYOUT_H
+
+/* Check if we should be dumping debug information or not */
+#if defined CYGDBG_DEVS_ETH_RLTK_8139_CHATTER \
+    && (CYGDBG_DEVS_ETH_RLTK_8139_CHATTER > 0)
+#define DEBUG_RLTK8139_DRIVER
+#endif
+
+#include "if_8139.h"
+
+/* Which interrupts we will handle */
+#define RLTK8139_IRQ (IR_SERR|IR_FOVW|IR_RXOVW|IR_TER|IR_TOK|IR_RER|IR_ROK)
+
+/* Allow platform-specific configuration of the driver */
+#ifndef CYGDAT_DEVS_ETH_RLTK_8139_INL
+#error "CYGDAT_DEVS_ETH_RLTK_8139_INL not defined"
+#else
+#include CYGDAT_DEVS_ETH_RLTK_8139_INL
+#endif
+
+/*
+ * If software cache coherency is required, the HAL_DCACHE_INVALIDATE
+ * hal macro must be defined as well.
+ */
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+#if !defined HAL_DCACHE_INVALIDATE || !defined HAL_DCACHE_FLUSH
+#error "HAL_DCACHE_INVALIDATE/HAL_DCACHE_FLUSH not defined for this platform but CYGPKG_DEVS_ETH_RLTK_8139_CACHE_COHERENCY was defined."
+#endif
+#endif
+
+/* Local driver function declarations */
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+static cyg_uint32 rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data);
+#endif
+
+#ifdef ETH_DRV_SET_MC_LIST
+static cyg_uint32 ether_crc(cyg_uint8 *data, int length);
+static void rltk8139_set_multicast_list(Rltk8139_t *rltk8139_info,
+                                        struct eth_drv_mc_list *mc_list);
+#endif
+
+static void rltk8139_reset(struct eth_drv_sc *sc);
+static bool rltk8139_init(struct cyg_netdevtab_entry *tab);
+static void rltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr,
+                           int flags);
+static void rltk8139_stop(struct eth_drv_sc *sc);
+static int rltk8139_control(struct eth_drv_sc *sc, unsigned long key,
+                            void *data, int   data_length);
+static int rltk8139_can_send(struct eth_drv_sc *sc);
+static void rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
+                          int sg_len, int total_len, unsigned long key);
+static void rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
+                          int sg_len);
+static void rltk8139_deliver(struct eth_drv_sc *sc);
+static void rltk8139_poll(struct eth_drv_sc *sc);
+static int rltk8139_int_vector(struct eth_drv_sc *sc);
+
+#ifdef DEBUG_RLTK8139_DRIVER
+void rltk8139_print_state(struct eth_drv_sc *sc);
+#endif
+
+/*
+ * Define inline functions to access the card. This will also handle
+ * endianess issues in one place. This code was lifted from the eCos
+ * i82559 driver.
+ */
+#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)
+{
+  HAL_WRITE_UINT8( io_address, value);
+}
+
+static inline void
+OUTW(cyg_uint16 value, cyg_uint32 io_address)
+{
+  HAL_WRITE_UINT16(io_address,
+                   (((value & 0xff) << 8) | ((value & 0xff00) >> 8)) );
+}
+
+static inline void
+OUTL(cyg_uint32 value, cyg_uint32 io_address)
+{
+  HAL_WRITE_UINT32(io_address,
+                   ((((value) & 0xff) << 24) | (((value) & 0xff00) << 8)
+                    | (((value) & 0xff0000) >> 8)
+                    | (((value) >> 24) & 0xff)) );
+}
+
+static inline cyg_uint8
+INB(cyg_uint32 io_address)
+{
+  cyg_uint8 d;
+  HAL_READ_UINT8(io_address, d);
+  return d;
+}
+
+static inline cyg_uint16
+INW(cyg_uint32 io_address)
+{
+  cyg_uint16 d;
+  HAL_READ_UINT16( io_address, d );
+  return (((d & 0xff) << 8) | ((d & 0xff00) >> 8));
+}
+
+static inline cyg_uint32
+INL(cyg_uint32 io_address)
+{
+  cyg_uint32 d;
+  HAL_READ_UINT32(io_address, d);
+  return ((((d) & 0xff) << 24) | (((d) & 0xff00) << 8)
+          | (((d) & 0xff0000) >> 8) | (((d) >> 24) & 0xff));
+}
+#else
+
+// Maintaining the same styleee as above...
+#define HAL_CTOLE32(x)  ((((x))))
+#define HAL_LE32TOC(x)  ((((x))))
+
+#define HAL_CTOLE16(x)  ((((x))))
+#define HAL_LE16TOC(x)  ((((x))))
+
+static inline void OUTB(cyg_uint8  value, cyg_uint32 io_address)
+{   HAL_WRITE_UINT8( io_address, value );   }
+
+static inline void OUTW(cyg_uint16 value, cyg_uint32 io_address)
+{   HAL_WRITE_UINT16( io_address, value );   }
+
+static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address)
+{   HAL_WRITE_UINT32( io_address, value );   }
+
+static inline cyg_uint8  INB(cyg_uint32 io_address)
+{   cyg_uint8  _t_; HAL_READ_UINT8(  io_address, _t_ ); return _t_;   }
+
+static inline cyg_uint16 INW(cyg_uint32 io_address)
+{   cyg_uint16 _t_; HAL_READ_UINT16( io_address, _t_ ); return _t_;   }
+
+static inline cyg_uint32 INL(cyg_uint32 io_address)
+{   cyg_uint32 _t_; HAL_READ_UINT32( io_address, _t_ ); return _t_;   }
+
+#endif // byteorder
+
+
+/*
+ * Table of all known PCI device/vendor ID combinations for the RealTek 8139.
+ * Add them as you get to know them.
+ */
+#define CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES 1
+static pci_identifier_t
+known_8139_aliases[CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES] = {
+  { 0x10ec, 0x8139, NULL } /* This is the offical RealTek vendor/device code */
+};
+
+
+/*
+ * Check if the device description matches a known 8139 alias.
+ */
+static cyg_bool
+rltk8139_find_match_func(cyg_uint16 vendor_id, cyg_uint16 device_id,
+                         cyg_uint32 class_id, void *p)
+{
+  int i;
+
+
+  for (i = 0; i < CYGNUM_DEVS_ETH_RLTK_8139_KNOWN_ALIASES; ++i) {
+    if (((known_8139_aliases[i].vendor_id == PCI_ANY_ID) ||
+         (known_8139_aliases[i].vendor_id == vendor_id)) &&
+        ((known_8139_aliases[i].device_id == PCI_ANY_ID) ||
+         (known_8139_aliases[i].device_id == device_id)))
+      return true;
+  }
+
+  return false;
+}
+
+
+/*
+ * Find the Nth 8139 device on all attached PCI busses and do some initial
+ * PCI-type initialization. Also setup the interrupt for use in eCos.
+ */
+static bool
+rltk8139_find(int n_th, struct eth_drv_sc *sc)
+{
+  Rltk8139_t *rltk8139_info;
+  cyg_pci_device_id pci_device_id;
+  cyg_pci_device pci_device_info;
+  cyg_uint16 command;
+  int found = -1;
+
+
+  /* Go through all PCI devices until we find the Nth 8139 chip */
+  do {
+    pci_device_id = CYG_PCI_NULL_DEVID;
+    if (!cyg_pci_find_matching(&rltk8139_find_match_func, NULL,
+                               &pci_device_id))
+      return false;
+    else
+      found += 1;
+  } while (found != n_th);
+
+  /* Save device ID in driver private data in case we ever need it again */
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+  rltk8139_info->pci_device_id = pci_device_id;
+
+  /* Now that we have found the device, we can extract some data about it */
+  cyg_pci_get_device_info(pci_device_id, &pci_device_info);
+
+  /* Get the assigned interrupt and set up ISR and DSR for it. */
+  if (cyg_pci_translate_interrupt(&pci_device_info, &rltk8139_info->vector)) {
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf(" Wired to HAL interrupt vector %d\n", rltk8139_info->vector);
+#endif
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+    /*
+     * Note that we use the generic eth_drv_dsr routine instead of
+     * our own.
+     */
+    cyg_drv_interrupt_create(rltk8139_info->vector, 0,
+                             (CYG_ADDRWORD)sc,
+                             rltk8139_isr,
+                             eth_drv_dsr,
+                             &rltk8139_info->interrupt_handle,
+                             &rltk8139_info->interrupt);
+    cyg_drv_interrupt_attach(rltk8139_info->interrupt_handle);
+#endif
+  }
+  else {
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf(" Does not generate interrupts.\n");
+#endif
+  }
+
+  /*
+   * Call 'cyg_pci_configure_device' for those platforms that do not
+   * configure the PCI bus during HAL initialization. According to Nick
+   * Garnett, there are good reasons to not configure PCI devices during HAL
+   * initialization. Also according to Nick, calling
+   * 'cyg_pci_configure_device' for devices already configured should have no
+   * effect and thus is safe to do.
+   */
+  if (cyg_pci_configure_device(&pci_device_info)) {
+#ifdef DEBUG_RLTK8139_DRIVER
+    int i;
+    diag_printf("Found device #%d on bus %d, devfn 0x%02x:\n", n_th,
+                CYG_PCI_DEV_GET_BUS(pci_device_id),
+                CYG_PCI_DEV_GET_DEVFN(pci_device_id));
+
+    if (pci_device_info.command & CYG_PCI_CFG_COMMAND_ACTIVE)
+      diag_printf(" Note that board is active. Probed"
+                  " sizes and CPU addresses are invalid!\n");
+
+    diag_printf(" Vendor    0x%04x", pci_device_info.vendor);
+    diag_printf("\n Device    0x%04x", pci_device_info.device);
+    diag_printf("\n Command   0x%04x, Status 0x%04x\n",
+                pci_device_info.command, pci_device_info.status)
+      ;
+
+    diag_printf(" Class/Rev 0x%08x", pci_device_info.class_rev);
+    diag_printf("\n Header 0x%02x\n", pci_device_info.header_type);
+
+    diag_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
+                pci_device_info.header.normal.sub_vendor,
+                pci_device_info.header.normal.sub_id);
+
+    for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
+      diag_printf(" BAR[%d]    0x%08x /", i, pci_device_info.base_address[i]);
+      diag_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
+                  pci_device_info.base_size[i], pci_device_info.base_map[i]);
+    }
+#endif
+  }
+  else {
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("Failed to configure 8139 device #%d\n", n_th);
+#endif
+    return false;
+  }
+
+  /*
+   * Enable memory mapped and port based I/O and busmastering. We currently
+   * only support IO space accesses; memory mapping is enabled so that bit
+   * DVRLOAD in CONFIG1 is cleared automatically.
+   *
+   * NOTE: it seems that for some configurations/HALs, the device is already
+   *       activated at this point, even though eCos' documentation suggests
+   *       it shouldn't be. At least in my case, this is not a problem.
+   */
+  cyg_pci_read_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND,
+                             &command);
+  command |= (CYG_PCI_CFG_COMMAND_IO | CYG_PCI_CFG_COMMAND_MEMORY
+              | CYG_PCI_CFG_COMMAND_MASTER);
+  cyg_pci_write_config_uint16(pci_device_info.devid, CYG_PCI_CFG_COMMAND,
+                              command);
+
+  /*
+   * This is the base address used to talk to the device. The 8139's IOAR
+   * and MEMAR registers are BAR0 and BAR1, respectively.
+   */
+  rltk8139_info->base_address = pci_device_info.base_map[0];
+
+  /*
+   * Read the MAC address. The RealTek data sheet seems to claim this should
+   * only be read in 4 byte accesses, but the code below works just fine.
+   */
+  for (found = 0; found < 6; ++found)
+    rltk8139_info->mac[found] = INB(rltk8139_info->base_address + IDR0 + found);
+
+  /*
+   * This is the indicator for "uses an interrupt". The code was lifted
+   * from the eCos Intel 82559 driver.
+   */
+  if (rltk8139_info->interrupt_handle != 0) {
+    cyg_drv_interrupt_acknowledge(rltk8139_info->vector);
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+    cyg_drv_interrupt_unmask(rltk8139_info->vector);
+#endif
+  }
+
+  return true;
+}
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+/*
+ * Interrupt service routine. We do not clear the interrupt status bits
+ * (since this should really only be done after handling whatever caused
+ * the interrupt, and that is done in the '_deliver' routine), but instead
+ * clear the interrupt mask.
+ *
+ * If we are sharing interrupts with other devices, we have two options
+ * (configurable):
+ *
+ * 1. Mask the interrupt vector completly. Personally I think this is a bad
+ *    idea because the other devices sharing this interrupt are also masked
+ *    until the network thread gets around to calling the '_deliver' routine.
+ *
+ * 2. Use the interrupt mask register in the 8139 to mask just the interrupt
+ *    request coming from the 8139. This way, the other devices' requests
+ *    can still be serviced.
+ */
+static cyg_uint32
+rltk8139_isr(cyg_vector_t vector, cyg_addrword_t data)
+{
+  Rltk8139_t *rltk8139_info;
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS
+  cyg_uint16 isr;
+#endif
+
+  rltk8139_info = (Rltk8139_t *)(((struct eth_drv_sc *)data)->driver_private);
+
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SHARE_INTERRUPTS
+  /*
+   * If interrupt sharing is enabled, check if the interrupt is really
+   * intended for us. Note that while the RealTek data sheet claims that
+   * reading the interrupt status register will clear all it's bits,
+   * this is not true, so we can read it without problems.
+   */
+  if (!(isr = INW(rltk8139_info->base_address + ISR)))
+    return 0;
+#endif
+
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139
+  /* Clear the interrupt mask to stop the current request. */
+  OUTW(0, rltk8139_info->base_address + IMR);
+#else
+  /* Mask the interrupt */
+  cyg_interrupt_mask(vector);
+#endif
+
+  /* Acknowledge the interrupt for those platforms were this is necessary */
+  cyg_interrupt_acknowledge(vector);
+
+  return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);
+}
+#endif /* ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE */
+
+/*
+ * Reset the chip. This function is not exported to higher level software.
+ */
+static void
+rltk8139_reset(struct eth_drv_sc *sc)
+{
+  rltk8139_stop(sc);
+  rltk8139_start(sc, NULL, 0);
+}
+
+#ifdef ETH_DRV_SET_MC_LIST
+/*
+ * I assume (hope !) that this is identical to Ethernet's CRC algorithm
+ * specified in IEEE 802.3. It does seem to calculate the same CRC that
+ * the 8139 itself does, so I think it is correct.
+ * Note that while Ethernet's polynomial is usually specified as 04C11DB7,
+ * we must use EDB88320 because we shift the bits to the left, not the right.
+ * (See ftp://ftp.rocksoft.com/papers/crc_v3.txt for a good description of
+ * CRC algorithms).
+ */
+static cyg_uint32
+ether_crc(cyg_uint8 *data, int length)
+{
+  int bit;
+  cyg_uint32 crc = 0xFFFFFFFFU;
+
+  while (length-- > 0) {
+    crc ^= *data++;
+    for (bit = 0; bit < 8; ++bit) {
+      if (crc & 1)
+        crc = (crc >> 1) ^ 0xEDB88320U;
+      else
+        crc = (crc >> 1);
+    }
+  }
+
+  return crc ^ 0xFFFFFFFFU;
+}
+
+
+/*
+ * Set up multicast filtering. The way I understand existing driver code
+ * (Linux and OpenBSD), the 8139 calculates the ethernet CRC of
+ * incoming addresses and uses the top 6 bits as an index into a hash
+ * table. If the corresponding bit is set in MAR0..7, the address is
+ * accepted.
+ */
+static void
+rltk8139_set_multicast_list(Rltk8139_t *rltk8139_info,
+                            struct eth_drv_mc_list *mc_list)
+{
+  cyg_uint32 mar[2], hash;
+  int i;
+
+  /* If 'mc_list' is NULL, accept all multicast packets. */
+  if (!mc_list) {
+    mar[0] = 0xFFFFFFFFU;
+    mar[1] = 0xFFFFFFFFU;
+  }
+  else {
+    mar[0] = 0;
+    mar[1] = 0;
+
+    for (i = 0; i < mc_list->len; ++i) {
+      hash = ether_crc(&mc_list->addrs[i][0], ETHER_ADDR_LEN) >> 26;
+      mar[hash >> 5] |= (1 << (hash & 0x1F));
+    }
+  }
+
+  /* Program the new filter values */
+  OUTL(mar[0], rltk8139_info->base_address + MAR0);
+  OUTL(mar[1], rltk8139_info->base_address + MAR4);
+}
+#endif /* ifdef ETH_DRV_SET_MC_LIST */
+
+
+/*
+ * Initialize the network interface. Since the chips is reset by calling
+ * _stop() and _start(), any code that will never need to be executed more
+ * than once after system startup should go here.
+ */
+static bool
+rltk8139_init(struct cyg_netdevtab_entry *tab)
+{
+  struct eth_drv_sc *sc;
+  Rltk8139_t *rltk8139_info;
+
+
+  sc = (struct eth_drv_sc *)(tab->device_instance);
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  /*
+   * Initialize the eCos PCI library. According to the documentation, it
+   * is safe to call this function multiple times, so we call it just to
+   * be sure it has been done.
+   */
+  cyg_pci_init();
+
+  /*
+   * Scan the PCI bus for the specified chip. The '_find' function will also
+   * do some basic PCI initialization.
+   */
+  if (!rltk8139_find(rltk8139_info->device_num, sc)) {
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_init: could not find RealTek 8139 chip #%d.\n",
+                rltk8139_info->device_num);
+#endif
+    return false;
+  }
+
+  /*
+   * The initial tx threshold is set here to prevent it from being reset
+   * with every _start().
+   */
+  rltk8139_info->tx_threshold = 3;
+
+  /* Initialize upper level driver */
+  (sc->funs->eth_drv->init)(sc, rltk8139_info->mac);
+
+  return true;
+}
+
+
+/*
+ * (Re)Start the chip, initializing data structures and enabling the
+ * transmitter and receiver. Currently, 'flags' is unused by eCos.
+ */
+static void
+rltk8139_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
+{
+  Rltk8139_t *rltk8139_info;
+  int i;
+
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_start(%s)\n", sc->dev_name);
+#endif
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  /*
+   * Reset the chip. Existing driver code implies that this may take up
+   * to 10ms; since I don't know under what exact circumstances this code may
+   * be called I busy wait here regardless.
+   */
+  OUTB(RST, rltk8139_info->base_address + CR);
+  while (INB(rltk8139_info->base_address + CR) & RST);
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_start(%s): 8139 was successfully reset.\n",
+              sc->dev_name);
+#endif
+
+  /*
+   * Clear the key storage area. These keys are used by the eCos networking
+   * support code to keep track of individual packets.
+   */
+  for (i = 0; i < NUM_TX_DESC; ++i)
+    rltk8139_info->tx_desc_key[i] = 0;
+
+  /* Initialize transmission buffer control */
+  rltk8139_info->tx_free_desc = 0;
+  rltk8139_info->tx_num_free_desc = NUM_TX_DESC;
+
+  /*
+   * Set the requested MAC address if enaddr != NULL. This is a special
+   * feature of my '_start' function since it's used to reset the chip after
+   * errors as well.
+   */
+  if (enaddr != NULL) {
+    for (i = 0; i < 6; ++i) {
+      rltk8139_info->mac[i] = enaddr[i];
+      OUTB(enaddr[i], rltk8139_info->base_address + IDR0 + i);
+    }
+  }
+
+  /*
+   * Now setup the transmission and reception buffers. These could be done
+   * in _init() and kept around, but putting them here fits better logically.
+   */
+  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer
+                                            + 0 * TX_BUF_SIZE)),
+       rltk8139_info->base_address + TSAD0);
+  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer
+                                            + 1 * TX_BUF_SIZE)),
+       rltk8139_info->base_address + TSAD1);
+  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer
+                                            + 2 * TX_BUF_SIZE)),
+       rltk8139_info->base_address + TSAD2);
+  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)(rltk8139_info->tx_buffer
+                                            + 3 * TX_BUF_SIZE)),
+       rltk8139_info->base_address + TSAD3);
+  OUTL(CYGARC_PCI_DMA_ADDRESS((cyg_uint32)rltk8139_info->rx_ring),
+       rltk8139_info->base_address + RBSTART);
+
+  /*
+   * Enable the transmitter and receiver, then clear the missed packet
+   * counter.
+   */
+  OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE),
+       rltk8139_info->base_address + CR);
+  OUTL(0, rltk8139_info->base_address + MPC);
+
+  /*
+   * It seems the receiver and transmitter configuration can only
+   * be set after the transmitter/receiver have been enabled.
+   */
+  OUTL(TXCFG, rltk8139_info->base_address + TCR);
+  OUTL(RXCFG | AM, rltk8139_info->base_address + RCR);
+
+  /*
+   * Enable the transmitter and receiver again. I'm not sure why this is
+   * necessary; the Linux driver does it so we do it here just to be on
+   * the safe side.
+   */
+  OUTB(INB(rltk8139_info->base_address + CR) | (TE|RE),
+       rltk8139_info->base_address + CR);
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+  /*
+   * If this driver was not compiled in stand alone (without interrupts)
+   * mode, enable interrupts.
+   */
+  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
+#endif
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  rltk8139_print_state(sc);
+#endif
+}
+
+
+/*
+ * Stop the chip, disabling the transmitter and receiver.
+ */
+static void
+rltk8139_stop(struct eth_drv_sc *sc)
+{
+  Rltk8139_t *rltk8139_info;
+
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_stop(%s)\n", sc->dev_name);
+#endif
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  /* Disable receiver and transmitter */
+  OUTB(INB(rltk8139_info->base_address + CR) & ~(TE|RE),
+       rltk8139_info->base_address + CR);
+
+  /* Mask all interrupts */
+  OUTW(0, rltk8139_info->base_address + IMR);
+}
+
+
+/*
+ * 8139 control function. Unlike a 'real' ioctl function, this function is
+ * not required to tell the caller why a request failed, only that it did
+ * (see the eCos documentation).
+ */
+static int
+rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,
+                 int data_length)
+{
+  int i;
+  Rltk8139_t *rltk8139_info;
+
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_control(%08x, %lx)\n", sc, key);
+#endif
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  switch (key) {
+#ifdef ETH_DRV_SET_MAC_ADDRESS
+  case ETH_DRV_SET_MAC_ADDRESS:
+    if ( 6 != data_length )
+      return 1;
+
+    /* Set the mac address */
+    for (i = 0; i < 6; ++i) {
+      rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i);
+      OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i);
+    }
+    return 0;
+#endif
+
+#ifdef ETH_DRV_GET_MAC_ADDRESS
+    case ETH_DRV_GET_MAC_ADDRESS:
+      if (6 != data_length)
+        return 1;
+
+      memcpy(data, rltk8139_info->mac, 6);
+      return 0;
+#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)
+    break;
+#endif
+
+#ifdef ETH_DRV_SET_MC_LIST
+  case ETH_DRV_SET_MC_LIST:
+    /*
+     * Program the 8139's multicast filter register. If the eth_drv_mc_list
+     * contains at least one element, set the accept multicast bit in the
+     * receive config register.
+     */
+    rltk8139_set_multicast_list(rltk8139_info, (struct eth_drv_mc_list *)data);
+    if (((struct eth_drv_mc_list *)data)->len > 0)
+      OUTL(INL(rltk8139_info->base_address + RCR) | AM,
+           rltk8139_info->base_address + RCR);
+    else
+      OUTL(INL(rltk8139_info->base_address + RCR) & ~AM,
+           rltk8139_info->base_address + RCR);
+
+    return 0;
+#endif // ETH_DRV_SET_MC_LIST
+
+#ifdef ETH_DRV_SET_MC_ALL
+  case ETH_DRV_SET_MC_ALL:
+    /*
+     * Set the accept multicast bit in the receive config register and
+     * program the multicast filter to accept all addresses.
+     */
+    rltk8139_set_multicast_list(rltk8139_info, NULL);
+    OUTL(INL(rltk8139_info->base_address + RCR) | AM,
+         rltk8139_info->base_address + RCR);
+    return 0;
+#endif // ETH_DRV_SET_MC_ALL
+
+  default:
+    return 1;
+  }
+
+  return 1;
+}
+
+
+/*
+ * Check if a new packet can be sent.
+ */
+static int
+rltk8139_can_send(struct eth_drv_sc *sc)
+{
+  return ((Rltk8139_t *)(sc->driver_private))->tx_num_free_desc;
+}
+
+
+/*
+ * Send a packet over the wire.
+ */
+static void
+rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
+              int total_len, unsigned long key)
+{
+  Rltk8139_t *rltk8139_info;
+  cyg_uint8 *tx_buffer;
+  struct eth_drv_sg *last_sg;
+  int desc;
+
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_send(%s, %08x, %d, %d, %08lx)\n",
+              sc->dev_name, sg_list, sg_len, total_len, key);
+#endif
+
+  CYG_ASSERT(total_len <= TX_BUF_SIZE, "packet too long");
+
+  /*
+   * Get the next free descriptor to send. We lock out all interrupts
+   * and scheduling because we really, really do not want to be interrupted
+   * at this point.
+   *
+   * IMPORTANT NOTE: the RealTek data sheet does not really make this clear,
+   * but when they talk about a 'ring' of transmit descriptors, they
+   * _really_ mean it, i.e. you _must_ use descriptor #1 after descriptor
+   * #0 even if transmission of descriptor #0 has already completed.
+   */
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+  cyg_interrupt_disable();
+#endif
+
+  /*
+   * Sanity check to see if '_send' was called even though there is no free
+   * descriptor. This is probably unnecessary.
+   */
+  if (rltk8139_info->tx_num_free_desc == 0) {
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+    cyg_interrupt_enable();
+#endif
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_send(%s): no free descriptor available\n",
+                sc->dev_name);
+#endif
+    return;
+  }
+
+  /*
+   * Get the free descriptor and advance the descriptor counter modulo
+   * TX_NUM_DESC. We assume that TX_NUM_DESC will always be a power of 2.
+   */
+  desc = rltk8139_info->tx_free_desc;
+  rltk8139_info->tx_free_desc = (rltk8139_info->tx_free_desc + 1)
+    & (NUM_TX_DESC - 1);
+
+  /* Decrement the number of free descriptors */
+  rltk8139_info->tx_num_free_desc -= 1;
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+  /* Reenable interrupts at this point */
+  cyg_interrupt_enable();
+#endif
+
+  /*
+   * Determine the buffer memory to use and tell the hardware about it.
+   * Since we use fixed buffer addresses, we do not need to set up TSADx.
+   * Memorize the key so we can call the tx_done callback correctly.
+   *
+   * While it would be possible to set TSADx to the packet directly if
+   * it is stored in a linear memory area with 32 bit alignment, it seems
+   * this happens so seldomly that it's simply not worth the extra
+   * runtime check.
+   */
+  tx_buffer = CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer
+                                      + TX_BUF_SIZE * desc);
+  rltk8139_info->tx_desc_key[desc] = key;
+
+  /*
+   * Copy the data to the designated position. Note that unlike the eCos
+   * Intel 82559 driver, we simply assume that all the scatter/gather list
+   * elements' lengths will add up to total_len exactly, and don't check
+   * to make sure.
+   */
+  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
+    memcpy(tx_buffer, (void *)(sg_list->buf), sg_list->len);
+    tx_buffer += sg_list->len;
+  }
+
+  /*
+   * Make sure the packet has the minimum ethernet packet size, padding
+   * with zeros if necessary.
+   */
+  if (total_len < MIN_ETH_FRAME_SIZE) {
+    memset(tx_buffer, 0, MIN_ETH_FRAME_SIZE - total_len);
+    total_len = MIN_ETH_FRAME_SIZE;
+  }
+
+  /*
+   * Flush the data cache here if necessary. This ensures the 8139 can
+   * read the correct data from the transmit buffer.
+   */
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+  HAL_DCACHE_FLUSH(rltk8139_info->tx_buffer + TX_BUF_SIZE * desc, total_len);
+#endif
+
+  /*
+   * Now setup the correct transmit descriptor to actually send the data.
+   * The early TX threshold is incremented by the driver until we reach a
+   * size that prevents transmit underruns. (An earlier attempt to calculate
+   * this parameter from the packet size didn't work).
+   */
+  OUTL((rltk8139_info->tx_threshold << ERTXTH_SHIFT) | (total_len & SIZE),
+       rltk8139_info->base_address + TSD0 + (desc<<2));
+}
+
+
+/*
+ * This routine actually retrieves data from the receive ring by
+ * copying it into the specified scatter/gather buffers. Again,
+ * we assume the scatter/gather list is OK and don't check against
+ * total length.
+ */
+static void
+rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
+              int sg_len)
+{
+  Rltk8139_t *rltk8139_info;
+  struct eth_drv_sg *last_sg;
+  cyg_uint8 *rx_buffer;
+
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+  rx_buffer = rltk8139_info->rx_current;
+
+  /*
+   * Invalidate the cache line(s) mapped to the receive buffer
+   * if necessary.
+   */
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+  HAL_DCACHE_INVALIDATE(rx_buffer, rltk8139_info->rx_size);
+#endif
+
+  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
+    memcpy((void *)(sg_list->buf), rx_buffer, sg_list->len);
+    rx_buffer += sg_list->len;
+  }
+}
+
+
+/*
+ * This function does all the heavy lifting associated with interrupts.
+ */
+static void
+rltk8139_deliver(struct eth_drv_sc *sc)
+{
+  Rltk8139_t *rltk8139_info;
+  cyg_uint16 status, pci_status;
+  cyg_uint32 tsd;
+  int desc;
+
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  /*
+   * The RealTek data sheet claims that reading the ISR will clear
+   * it. This is incorrect; to clear a bit in the ISR, a '1' must be
+   * written to the ISR instead. We immediately clear the interrupt
+   * bits at this point.
+   */
+  status = INW(rltk8139_info->base_address + ISR);
+  OUTW(status, rltk8139_info->base_address + ISR);
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_deliver(%s): %04x\n", sc->dev_name, status);
+#endif
+
+  /*
+   * Check for a PCI error. This seems like a very serious error to
+   * me, so we will reset the chip and hope for the best.
+   */
+  if (status & IR_SERR) {
+    cyg_pci_read_config_uint16(rltk8139_info->pci_device_id,
+                               CYG_PCI_CFG_STATUS, &pci_status);
+    cyg_pci_write_config_uint16(rltk8139_info->pci_device_id,
+                                CYG_PCI_CFG_STATUS, pci_status);
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_deliver(%s): PCI error %04x\n",
+                sc->dev_name, pci_status);
+#endif
+
+    rltk8139_reset(sc);
+    return;
+  }
+
+  /* Check for transmission complete (with errors or not) */
+  if ((status & IR_TER) || (status & IR_TOK)) {
+    /*
+     * Figure out which descriptors' status must be checked. We lock out
+     * interrupts while manipulating the descriptor list because we do not
+     * want to be interrupted at this point.
+     */
+    while (1) {
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+      cyg_interrupt_disable();
+#endif
+
+      /* Check if all descriptors are ready, in which case we are done. */
+      if (rltk8139_info->tx_num_free_desc >= NUM_TX_DESC) {
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+        cyg_interrupt_enable();
+#endif
+        break;
+      }
+
+      desc = (rltk8139_info->tx_free_desc
+              - (NUM_TX_DESC - rltk8139_info->tx_num_free_desc))
+        & (NUM_TX_DESC - 1);
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+      cyg_interrupt_enable();
+#endif
+      /* Get the current status of the descriptor */
+      tsd = INL(rltk8139_info->base_address + TSD0 + (desc<<2));
+
+      /*
+       * If a transmit FIFO underrun occurred, increment the threshold
+       * value.
+       */
+      if ((tsd & TUN) && (rltk8139_info->tx_threshold < 64))
+        rltk8139_info->tx_threshold += 1;
+
+      /*
+       * Check if a transmission completed OK. RealTek's data sheet implies
+       * that a successful transmission that experiences underrun will only
+       * set TUN. This is not true; TOK is set for all successful
+       * transmissions.
+       */
+      if (tsd & TOK) {
+        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], 0);
+      }
+      else if (tsd & TABT) {
+        /*
+         * Set the CLRABT bit in TCR. Since I haven't encountered any
+         * transmission aborts so far, I don't really know if this code
+         * will work or not.
+         */
+        OUTL(INL(rltk8139_info->base_address + TCR) & CLRABT,
+             rltk8139_info->base_address + TCR);
+        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], -1);
+      }
+      else {
+        /*
+         * This descriptor is not ready. Since the descriptors are used
+         * in a ring, this means that no more descriptors are ready.
+         */
+        break;
+      }
+
+      /*
+       * Clear the saved key value. This is not really necessary, since
+       * the key value is never used to determine if a descriptor is
+       * valid or not. However, clearing it is a tidier IMO.
+       */
+      rltk8139_info->tx_desc_key[desc] = 0;
+
+      /*
+       * Increment the free descriptor count and go through the loop again
+       * to see if more descriptors are ready.
+       */
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+      cyg_interrupt_disable();
+#endif
+      rltk8139_info->tx_num_free_desc += 1;
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+      cyg_interrupt_enable();
+#endif
+    }
+  }
+
+  if (status & IR_ROK) {
+    /*
+     * Received a frame. Note that '_deliver' does not actually copy any
+     * data; it just determines how many bytes are available and tells
+     * the generic ethernet driver about it, which then calls into
+     * the '_recv' function to copy the data.
+     */
+    cyg_uint16 rx_pos;
+    cyg_uint32 header, length;
+
+    /*
+     * CAPR contains the index into the receive buffer. It is controlled
+     * completely in software. For some reason, CAPR points 16 bytes
+     * before the actual start of the packet.
+     */
+    rx_pos = (INW(rltk8139_info->base_address + CAPR) + 16) % RX_BUF_LEN;
+
+    /*
+     * Loop until the rx buffer is empty. I have no idea how the 8139
+     * determines if the buffer still contains a packet; it may check
+     * that CAPR points 16 bytes before CBR.
+     */
+    while (!(INB(rltk8139_info->base_address + CR) & BUFE)) {
+      /*
+       * Invalidate the data cache for the cache line containing the header
+       * if necessary.
+       */
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+      HAL_DCACHE_INVALIDATE(&rltk8139_info->rx_ring[rx_pos],
+                            sizeof(cyg_uint32));
+#endif
+
+      /*
+       * The 8139 prepends each packet with a 32 bit packet header that
+       * contains a 16 bit length and 16 bit status field, in little-endian
+       * byte order.
+       */
+      header = HAL_LE32TOC(*((volatile cyg_uint32 *)CYGARC_UNCACHED_ADDRESS(&rltk8139_info->rx_ring[rx_pos])));
+
+      /*
+       * If the 8139 is still copying data for this packet into the
+       * receive ring, it will set packet length to 0xfff0. This shouldn't
+       * ever happen because we do not use early receive.
+       */
+      if ((header >> 16) == 0xFFF0)
+        break;
+
+      /*
+       * Since the 8139 appends the ethernet CRC to every packet, we
+       * must subtract 4 from the length to get the true packet length.
+       */
+      length = (header >> 16) - 4;
+
+      /*
+       * Check if the packet was received correctly. The OpenBSD driver
+       * resets the chip if this is not the case; we attempt to salvage
+       * following packets by doing nothing.
+       */
+      if (!(header & HDR_ROK)) {
+      }
+      else {
+        /*
+         * Packet was received OK. Determine from where to start copying
+         * bytes. This is saved in the driver private area so rlt8139_recv
+         * doesn't have to redetermine this information. Then, inform
+         * the generic ethernet driver about the packet.
+         */
+        rltk8139_info->rx_current = CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + rx_pos + 4);
+        rltk8139_info->rx_size = length;
+
+        /* Tell eCos about the packet */
+        (sc->funs->eth_drv->recv)(sc, length);
+      }
+
+      /*
+       * Update CAPR. CAPR must be aligned to a 32 bit boundary, and should
+       * point 16 bytes before it's actual position.
+       */
+      rx_pos = ((rx_pos + length + 8 + 3) & ~3) % RX_BUF_LEN;
+      OUTW((rx_pos - 16) % RX_BUF_LEN, rltk8139_info->base_address + CAPR);
+    }
+  }
+
+  if (status & IR_RXOVW) {
+    /*
+     * In case of a receive buffer overflow, the RealTek data sheet claims we
+     * should update CAPR and then write a '1'?to ROK in ISR. However, none of
+     * the other 8139 drivers I have looked at do this, so we will just reset
+     * the chip instead.
+     */
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_deliver(%s): receive buffer overflow\n",
+                sc->dev_name);
+#endif
+    rltk8139_reset(sc);
+    return;
+  }
+
+  if (status & IR_FOVW) {
+    /*
+     * Rx FIFO overflow. According to RealTek's data sheet, this is cleared
+     * by writing a '1' to RXOVW. Again, none of the 8139 drivers I have
+     * seen actually do this, so we reset the chip instead.
+     */
+#ifdef DEBUG_RLTK8139_DRIVER
+    diag_printf("rltk8139_deliver(%s): receive FIFO overflow\n",
+                sc->dev_name);
+#endif
+    rltk8139_reset(sc);
+    return;
+  }
+
+#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
+  /* Finally, reenable interrupts */
+#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139
+  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
+#else
+  cyg_interrupt_unmask(rltk8139_info->vector);
+#endif
+#endif
+}
+
+
+/*
+ * '_poll' does the same thing as '_deliver'. It is called periodically when
+ * the ethernet driver is operated in non-interrupt mode, for instance by
+ * RedBoot.
+ */
+static void
+rltk8139_poll(struct eth_drv_sc *sc)
+{
+  Rltk8139_t *rltk8139_info;
+  cyg_uint16 isr;
+
+
+#ifdef DEBUG_RLTK8139_DRIVER
+  diag_printf("rltk8139_poll(%s)\n", sc->dev_name);
+#endif
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  /*
+   * Get the current interrupt status. If anything changed, call
+   * _deliver.
+   */
+  if ((isr = INW(rltk8139_info->base_address + ISR)))
+    rltk8139_deliver(sc);
+}
+
+
+/*
+ * Return the interrupt vector used by this device.
+ */
+static int
+rltk8139_int_vector(struct eth_drv_sc *sc)
+{
+  return ((Rltk8139_t *)(sc->driver_private))->vector;
+}
+
+
+/*
+ * Quick and dirty register dump. This is somewhat dangerous, since
+ * we read the register space 32 bits at a time, regardless of actual
+ * register sizes.
+ */
+#ifdef DEBUG_RLTK8139_DRIVER
+void
+rltk8139_print_state(struct eth_drv_sc *sc) {
+  int i;
+  Rltk8139_t *rltk8139_info;
+
+
+  rltk8139_info = (Rltk8139_t *)(sc->driver_private);
+
+  for (i = IDR0; i < FFER; i += 16) {
+    diag_printf("8139 reg address 0x%02x = 0x%08x", i,
+                INL(rltk8139_info->base_address + i));
+    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 4));
+    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 8));
+    diag_printf(" 0x%08x\n", INL(rltk8139_info->base_address + i + 12));
+  }
+}
+#endif
Index: devs/eth/rltk/8139/current/src/if_8139.h
===================================================================
RCS file: devs/eth/rltk/8139/current/src/if_8139.h
diff -N devs/eth/rltk/8139/current/src/if_8139.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/rltk/8139/current/src/if_8139.h	1 Sep 2003 09:16:40 -0000
@@ -0,0 +1,366 @@
+#ifndef CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H
+#define CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H
+/*==========================================================================
+//
+//        8139_info.h
+//
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     Eric Doenges
+// Contributors:  Chris Nimmers, Gary Thomas, Andy Dyer
+// Date:          2003-07-09
+// Description:
+//
+//####DESCRIPTIONEND####
+*/
+#include <pkgconf/devs_eth_rltk_8139.h>
+
+
+/*
+ * Used to define all vendor/device ID combinations we know about to find
+ * the chip.
+ */
+typedef struct {
+  cyg_uint16 vendor_id;
+  cyg_uint16 device_id;
+  void *data;
+} pci_identifier_t;
+
+#define PCI_ANY_ID (0xFFFF)
+
+/*
+ * Valid receive buffer sizes are 8k+16, 16k+16, 32k+16, or 64k+16.
+ * For the last case, WRAP mode should not be enabled. Since we do not
+ * currently want to support unwrapped mode, do not use 64k+16 at this
+ * point. The buffer length is set via the configuration mechanism.
+ */
+#if (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX < 0) |\
+    (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX > 2)
+#error "The receive ring size index must be in the range of 0 to 2"
+#endif
+#define RX_BUF_LEN      (8192 << (CYGNUM_DEVS_ETH_RLTK_8139_RX_BUF_LEN_IDX))
+#define RX_BUF_PAD      16
+#define RX_BUF_WRAP_PAD 2048 /* spare padding to handle lack of packet wrap */
+#define RX_BUF_TOT_LEN  (RX_BUF_LEN + RX_BUF_PAD + RX_BUF_WRAP_PAD)
+
+/* Number of Tx descriptor registers. */
+#define NUM_TX_DESC     4
+
+/*
+ * Max supported ethernet frame size. The 8139 cannot transmit packets more
+ * than 1792 bytes long. Also, since transmit buffers must be 32-bit
+ * aligned, MAX_ETH_FRAME_SIZE should always be a multiple of 4.
+ */
+#define MIN_ETH_FRAME_SIZE      60      /* without FCS */
+#define MAX_ETH_FRAME_SIZE      1536    /* is this with/without FCS ? */
+
+/* Size of the Tx buffers. */
+#define TX_BUF_SIZE     MAX_ETH_FRAME_SIZE
+#define TX_BUF_TOT_LEN  (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* Rx buffer level before first PCI transfer ('5' is 512 bytes) */
+#define RX_FIFO_THRESH	5
+
+/*
+ * Maximum PCI rx and tx bursts. This value ranges from '0' (16 bytes)
+ * to '7' (unlimited), with MXDMA = 2^(4 + 'value').
+ */
+#define RX_DMA_BURST		6
+#define TX_DMA_BURST		6
+
+/*
+ * Device driver private data
+ */
+typedef struct {
+  /* Device number. Used for actually finding the device */
+  cyg_uint32 device_num;
+
+  /* Receive buffer ring area */
+  cyg_uint8 *rx_ring;
+
+  /* Transmit buffer area */
+  cyg_uint8 *tx_buffer;
+
+  /* PCI device ID */
+  cyg_pci_device_id pci_device_id;
+
+  /* Address for memory mapped I/O */
+  cyg_uint32 base_address;
+
+  /* Our current MAC address */
+  unsigned char mac[6];
+
+  /* tx FIFO threshold. */
+  cyg_uint8 tx_threshold;
+
+  /* This is the first free descriptor. */
+  int tx_free_desc;
+
+  /* This is the number of currently free descriptors */
+  int tx_num_free_desc;
+
+  /* Keys to match _send calls with the tx_done callback */
+  unsigned long tx_desc_key[NUM_TX_DESC];
+
+  /*
+   * This is used to (temporarily) store the address of the current
+   * received packet. We save it here to avoid having to calculate it
+   * several times.
+   */
+  cyg_uint8 *rx_current;
+  cyg_uint32 rx_size;
+
+  /* Interrupt handling stuff */
+  cyg_vector_t  vector;
+  cyg_handle_t  interrupt_handle;
+  cyg_interrupt interrupt;
+} Rltk8139_t;
+
+
+/*
+ * Register offsets and bit definitions. These use the names in the 8139
+ * data sheet, not those found e.g. in the Linux driver for the 8139.
+ */
+enum {
+  IDR0    =  0x0, /* mac address, seemingly in big-endian order */
+  IDR1    =  0x1,
+  IDR2    =  0x2,
+  IDR3    =  0x3,
+  IDR4    =  0x4,
+  IDR5    =  0x5,
+  MAR0    =  0x8, /* multicast registers (0-7) */
+  MAR1    =  0x9,
+  MAR2    =  0xA,
+  MAR3    =  0xB,
+  MAR4    =  0xC,
+  MAR5    =  0xD,
+  MAR6    =  0xE,
+  MAR7    =  0xF,
+  TSD0    = 0x10, /* L, transmit status of descriptor 0 */
+  TSD1    = 0x14,
+  TSD2    = 0x18,
+  TSD3    = 0x1C,
+  TSAD0   = 0x20, /* L, transmit start address of descriptor 0 */
+  TSAD1   = 0x24,
+  TSAD2   = 0x28,
+  TSAD3   = 0x2C,
+  RBSTART = 0x30, /* L, receive buffer start address */
+  ERBCR   = 0x34, /* W, early receive byte count register */
+  ERSR    = 0x36, /* B, early receive status register */
+  CR      = 0x37, /* B, command register */
+  CAPR    = 0x38, /* W, current address of packet read */
+  CBR     = 0x3A, /* W, current buffer address */
+  IMR     = 0x3C, /* W, interrupt mask register */
+  ISR     = 0x3E, /* W, interrupt status register */
+  TCR     = 0x40, /* L, transmit configuration register */
+  RCR     = 0x44, /* L, receive configuration register */
+  TCTR    = 0x48, /* L, timer count register */
+  MPC     = 0x4C, /* L, missed packet counter */
+  CR9346  = 0x50, /* B, 93C46 (serial eeprom) command register */
+  CONFIG0 = 0x51, /* B, configuration register 0 */
+  CONFIG1 = 0x52, /* B, configuration register 1 */
+  TIMERINT= 0x54, /* L, timer interrupt register */
+  MSR     = 0x58, /* B, media status register */
+  CONFIG3 = 0x59, /* B, configuration register 0 */
+  CONFIG4 = 0x5A, /* B, configuration register 1 */
+  MULINT  = 0x5C, /* W, multiple interrupt select */
+  RERID   = 0x5E, /* B, PCI revision ID; should be 0x10 */
+  TSAD    = 0x60, /* W, transmit status of all descriptors */
+  BMCR    = 0x62, /* W, basic mode control register */
+  BMSR    = 0x64, /* W, basic mode status register */
+  ANAR    = 0x66, /* W, auto-negotiation advertisement register */
+  ANLPAR  = 0x68, /* W, auto-negotiation link partner register */
+  ANER    = 0x6A, /* W, auto-negotiation expansion register */
+  DIS     = 0x6C, /* W, disconnect counter */
+  FCSC    = 0x6E, /* W, false carrier sense counter */
+  NWAYTR  = 0x70, /* W, N-way test register */
+  REC     = 0x72, /* W, RX_ER counter */
+  CSCR    = 0x74, /* W, CS configuration register */
+  PHY1_PARM = 0x78, /* L, PHY parameter 1 */
+  TW_PARM = 0x7C, /* L, twister parameter */
+  PHY2_PARM = 0x80, /* B, PHY parameter 2 */
+  CRC0    = 0x84, /* B, power management CRC register for wakeup frame 0 */
+  CRC1    = 0x85, /* B, power management CRC register for wakeup frame 1 */
+  CRC2    = 0x86, /* B, power management CRC register for wakeup frame 2 */
+  CRC3    = 0x87, /* B, power management CRC register for wakeup frame 3 */
+  CRC4    = 0x88, /* B, power management CRC register for wakeup frame 4 */
+  CRC5    = 0x89, /* B, power management CRC register for wakeup frame 5 */
+  CRC6    = 0x8A, /* B, power management CRC register for wakeup frame 6 */
+  CRC7    = 0x8B, /* B, power management CRC register for wakeup frame 7 */
+  WAKEUP0 = 0x8C, /* Q, power management wakeup frame 0 (64 bits) */
+  WAKEUP1 = 0x94, /* Q, power management wakeup frame 1 (64 bits) */
+  WAKEUP2 = 0x9C, /* Q, power management wakeup frame 2 (64 bits) */
+  WAKEUP3 = 0xA4, /* Q, power management wakeup frame 3 (64 bits) */
+  WAKEUP4 = 0xAC, /* Q, power management wakeup frame 4 (64 bits) */
+  WAKEUP5 = 0xB4, /* Q, power management wakeup frame 5 (64 bits) */
+  WAKEUP6 = 0xBC, /* Q, power management wakeup frame 6 (64 bits) */
+  WAKEUP7 = 0xC4, /* Q, power management wakeup frame 7 (64 bits) */
+  LSBCRC0 = 0xCC, /* B, LSB of mask byte of wakeup frame 0 offset 12 to 75 */
+  LSBCRC1 = 0xCD, /* B, LSB of mask byte of wakeup frame 1 offset 12 to 75 */
+  LSBCRC2 = 0xCE, /* B, LSB of mask byte of wakeup frame 2 offset 12 to 75 */
+  LSBCRC3 = 0xCF, /* B, LSB of mask byte of wakeup frame 3 offset 12 to 75 */
+  LSBCRC4 = 0xD0, /* B, LSB of mask byte of wakeup frame 4 offset 12 to 75 */
+  LSBCRC5 = 0xD1, /* B, LSB of mask byte of wakeup frame 5 offset 12 to 75 */
+  LSBCRC6 = 0xD2, /* B, LSB of mask byte of wakeup frame 6 offset 12 to 75 */
+  LSBCRC7 = 0xD3, /* B, LSB of mask byte of wakeup frame 7 offset 12 to 75 */
+  FLASH   = 0xD4, /* L, flash memory read/write register */
+  CONFIG5 = 0xD8, /* B, configuration register #5 */
+  FER     = 0xF0, /* L, function event register (CardBus only) */
+  FEMR    = 0xF4, /* L, function event mask register (CardBus only) */
+  FPSR    = 0xF8, /* L, function present state register (CardBus only) */
+  FFER    = 0xFC  /* L, function force event register (CardBus only) */
+};
+
+/* Receive status register in Rx packet header */
+enum {
+  MAR  = (1<<15), /* multicast address received */
+  PAM  = (1<<14), /* physical address matched */
+  BAR  = (1<<13), /* broadcast address received */
+  ISE  = (1<<5),  /* invalid symbol error */
+  RUNT = (1<<4),  /* runt packet (<64 bytes) received */
+  LONG = (1<<3),  /* long packet (>4K bytes) received */
+  CRC  = (1<<2),  /* CRC error */
+  FAE  = (1<<1),  /* frame alignment error */
+  ROK  = (1<<0)   /* receive OK */
+};
+
+/* Transmit status register */
+enum {
+  CRS    = (1<<31), /* carrier sense lost */
+  TABT   = (1<<30), /* transmit abort */
+  OWC    = (1<<29), /* out of window collision */
+  CDH    = (1<<28), /* CD heart beat */
+  NCC_SHIFT = 24,
+  NCC    = (0xF<<24), /* number of collision count */
+  ERTXTH_SHIFT = 16,
+  ERTXTH = (0x1F<<16), /* early tx threshold, in multiples of 32 bytes */
+  TOK    = (1<<15), /* transmission OK */
+  TUN    = (1<<14), /* transmit FIFO underrun */
+  OWN    = (1<<13), /* own */
+  SIZE   = 0xFFF    /* descriptor size */
+};
+
+/* Command register */
+enum {
+  RST  = (1<<4),  /* reset */
+  RE   = (1<<3),  /* receiver enable */
+  TE   = (1<<2),  /* transmitter enable */
+  BUFE = (1<<0)   /* buffer empty */
+};
+
+/* Transmit configuration register */
+enum {
+  CLRABT = (1<<0) /* clear abort */
+};
+
+/* Receive configuration register */
+enum {
+  ERTH_SHIFT = 24,      /* Early Rx threshold bits (4) */
+  MULERINT   = (1<<17), /* multiple early interrupt */
+  RER8       = (1<<16), /* ? */
+  RXFTH_SHIFT= 13,      /* Rx FIFO threshold */
+  RBLEN_SHIFT= 11,      /* Rx buffer length */
+  MXDMA_SHIFT= 8,       /* max DMA burst size per Rx DMA burst */
+  WRAP       = (1<<7),  /* WRAP mode */
+  SEL9356    = (1<<6),  /* EEPROM select */
+  AER        = (1<<5),  /* accept error packets */
+  AR         = (1<<4),  /* accept runt packets */
+  AB         = (1<<3),  /* accept broadcast packets */
+  AM         = (1<<2),  /* accept multicast packets */
+  APM        = (1<<1),  /* accept physical match packets (our MAC) */
+  AAP        = (1<<0),  /* accept physical address packets (any MAC) */
+};
+
+/* TSAD (transmit status of all descriptors */
+enum {
+  TOK3  = (1<<15),
+  TOK2  = (1<<14),
+  TOK1  = (1<<13),
+  TOK0  = (1<<12),
+  TUN3  = (1<<11),
+  TUN2  = (1<<10),
+  TUN1  = (1<<9),
+  TUN0  = (1<<8),
+  TABT3 = (1<<7),
+  TABT2 = (1<<6),
+  TABT1 = (1<<5),
+  TABT0 = (1<<4),
+  OWN3  = (1<<3),
+  OWN2  = (1<<2),
+  OWN1  = (1<<1),
+  OWN0  = (1<<0)
+};
+
+/* Interrupt mask/status register */
+enum {
+  IR_SERR    = (1<<15), /* system error interrupt */
+  IR_TIMEOUT = (1<<14), /* time out interrupt */
+  IR_LENCHG  = (1<<13), /* cable length change interrupt */
+  IR_FOVW    = (1<<6),  /* Rx FIFO overflow */
+  IR_FUN     = (1<<5),  /* Packet underrun or link change interrupt */
+  IR_RXOVW   = (1<<4),  /* Rx buffer overflow */
+  IR_TER     = (1<<3),  /* transmit error interrupt */
+  IR_TOK     = (1<<2),  /* transmit OK interrupt */
+  IR_RER     = (1<<1),  /* receive error interrupt */
+  IR_ROK     = (1<<0)   /* receive OK interrupt */
+};
+
+/* Packet header bits */
+enum {
+  HDR_MAR  = (1<<15), /* multicast address received */
+  HDR_PAM  = (1<<14), /* physical address matched */
+  HDR_BAR  = (1<<13), /* broadcast address matched */
+  HDR_ISE  = (1<<5),  /* invalid symbol error */
+  HDR_RUNT = (1<<4),  /* runt packet received (packet < 64 bytes) */
+  HDR_LONG = (1<<3),  /* long packet (>4k) */
+  HDR_CRC  = (1<<2),  /* CRC error */
+  HDR_FAE  = (1<<1),  /* frame alignment error */
+  HDR_ROK  = (1<<0)   /* receive OK */
+};
+
+
+/*
+ * Define some options to use
+ */
+#define TXCFG ((0x3 << 24) | (TX_DMA_BURST << MXDMA_SHIFT))
+#define RXCFG ((RX_FIFO_THRESH << RXFTH_SHIFT) |\
+               (RX_BUF_LEN_IDX << RBLEN_SHIFT) |\
+               (RX_DMA_BURST << MXDMA_SHIFT) |\
+               WRAP | AB | APM)
+
+#endif /* ifndef CYGONCE_DEVS_ETH_REALTEK_8139_INFO_H */
Index: devs/eth/i386/pc/rltk8139/current/ChangeLog
===================================================================
RCS file: devs/eth/i386/pc/rltk8139/current/ChangeLog
diff -N devs/eth/i386/pc/rltk8139/current/ChangeLog
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/i386/pc/rltk8139/current/ChangeLog	12 Nov 2003 16:22:11 -0000
@@ -0,0 +1,40 @@
+2003-07-09  Eric Doenges <Eric.Doenges@DynaPel.com>
+
+	* include/devs_eth_i386_pc_rltk8139.inl: 
+	* cdl/i386_pc_rltk8139_eth_drivers.cdl: 
+	New package - RTL8139 PCI ethernet card driver 
+	
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
Index: devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl
===================================================================
RCS file: devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl
diff -N devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/i386/pc/rltk8139/current/cdl/i386_pc_rltk8139_eth_drivers.cdl	19 Jul 2003 10:25:22 -0000
@@ -0,0 +1,92 @@
+# ====================================================================
+#
+#      i386_pc_rltk8139_eth_drivers.cdl
+#
+#      Ethernet drivers - support for RealTek 8139 ethernet controller
+#      on i386 PC target
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos 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 or (at your option) any later version.
+##
+## eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      Eric Doenges
+# Contributors:
+# Date:           2003-07-16
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_DEVS_ETH_I386_PC_RLTK8139 {
+    display       "PC RealTek 8139 ethernet driver"
+    description   "Ethernet driver for standard PC's."
+
+    parent        CYGPKG_IO_ETH_DRIVERS
+    active_if	  CYGPKG_IO_ETH_DRIVERS
+    active_if     CYGPKG_HAL_I386_PC
+
+    include_dir   cyg/io
+
+    # FIXME: This really belongs in the RealTek_8139 package ?
+    cdl_interface CYGINT_DEVS_ETH_RLTK_8139_REQUIRED {
+        display   "RealTek 8139 ethernet driver required"
+    }
+
+    define_proc {
+        puts $::cdl_system_header "/***** ethernet driver proc output start *****/"
+        puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_RLTK_8139_INL <cyg/io/devs_eth_i386_pc_rltk8139.inl>"
+        puts $::cdl_system_header "#define CYGDAT_DEVS_ETH_RLTK_8139_CFG <pkgconf/devs_eth_i386_pc_rltk8139.h>"
+        puts $::cdl_system_header "/*****  ethernet driver proc output end  *****/"
+    }
+
+    cdl_component CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0 {
+        display       "Ethernet port 0 driver"
+        flavor        bool
+        default_value 1
+
+        implements CYGHWR_NET_DRIVERS
+        implements CYGHWR_NET_DRIVER_ETH0
+        implements CYGINT_DEVS_ETH_RLTK_8139_REQUIRED
+
+        cdl_option CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME {
+            display       "Device name for the ETH0 ethernet port 0 driver"
+            flavor        data
+            default_value {"\"eth0\""}
+            description   "
+                This option sets the name of the ethernet device for the
+                RealTek 8139 ethernet port 0."
+        }
+    }
+}
Index: devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl
===================================================================
RCS file: devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl
diff -N devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ devs/eth/i386/pc/rltk8139/current/include/devs_eth_i386_pc_rltk8139.inl	13 Nov 2003 13:32:43 -0000
@@ -0,0 +1,90 @@
+//==========================================================================
+//
+//      devs/eth/i386/pc/rltk8139/include/devs_eth_i386_pc_rltk8139.inl
+//
+//      i386 PC RealTek 8139 ethernet I/O definitions.
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos 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 or (at your option) any later version.
+//
+// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   Eric Doenges
+// Contributors:
+// Date:        2003-07-16
+// Purpose:     i386 PC RealTek 8139 ethernet definitions
+//####DESCRIPTIONEND####
+//==========================================================================
+
+// 
+// CAUTION! This driver has *not* been tested on PC hardware.  It may work
+// or not :-)  If there are problems, they are probably cache related.
+// If you find such, please let us know.
+//
+//#define CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
+
+#define CACHE_ALIGNED __attribute__ ((aligned (HAL_DCACHE_LINE_SIZE)))
+
+#ifdef CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0
+
+static cyg_uint8 rltk8139_eth0_rx_ring[RX_BUF_TOT_LEN] CACHE_ALIGNED;
+static cyg_uint8
+rltk8139_eth0_tx_buffer[(TX_BUF_TOT_LEN + HAL_DCACHE_LINE_SIZE - 1)
+                        & ~(HAL_DCACHE_LINE_SIZE - 1)] CACHE_ALIGNED;
+static Rltk8139_t rltk8139_eth0_priv_data = {
+  0, rltk8139_eth0_rx_ring, rltk8139_eth0_tx_buffer
+};
+
+ETH_DRV_SC(rltk8139_sc0,
+           &rltk8139_eth0_priv_data,
+           CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME,
+           rltk8139_start,
+           rltk8139_stop,
+           rltk8139_control,
+           rltk8139_can_send,
+           rltk8139_send,
+           rltk8139_recv,
+           rltk8139_deliver,
+           rltk8139_poll,
+           rltk8139_int_vector
+           );
+
+NETDEVTAB_ENTRY(rltk8139_netdev0,
+                "rltk8139_" CYGDAT_DEVS_ETH_I386_PC_RLTK8139_ETH0_NAME,
+                rltk8139_init,
+                &rltk8139_sc0);
+
+#endif // CYGPKG_DEVS_ETH_I386_PC_RLTK8139_ETH0
+
+// EOF devs_eth_i386_pc_rltk8139.inl

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]