added intermediate driver for connecting lance ethernet to sun3 obio
diff --git a/machine/sun/Makefile.am b/machine/sun/Makefile.am
index ba80a5c..2255c01 100644
--- a/machine/sun/Makefile.am
+++ b/machine/sun/Makefile.am
@@ -12,7 +12,8 @@
 	sun-cgsix.c \
 	sun-fb.c sun-fb.h \
 	sun-si.c \
-	sun-obie.c
+	sun-obie.c \
+	sun-oble.c
 libtme_machine_sun_la_LDFLAGS = -version-info 0:0:0
 libtme_machine_sun_la_LIBADD = $(top_builddir)/libtme/libtme.la \
 	$(top_builddir)/generic/libtme-generic.la
diff --git a/machine/sun/Makefile.in b/machine/sun/Makefile.in
index 2fc51d1..f1e4f9e 100644
--- a/machine/sun/Makefile.in
+++ b/machine/sun/Makefile.in
@@ -77,7 +77,8 @@
 libtme_machine_sun_la_DEPENDENCIES = $(top_builddir)/libtme/libtme.la \
 	$(top_builddir)/generic/libtme-generic.la
 am_libtme_machine_sun_la_OBJECTS = sun-mmu.lo sun-bwtwo.lo \
-	sun-cgtwo.lo sun-cgsix.lo sun-fb.lo sun-si.lo sun-obie.lo
+	sun-cgtwo.lo sun-cgsix.lo sun-fb.lo sun-si.lo sun-obie.lo \
+	sun-oble.lo
 libtme_machine_sun_la_OBJECTS = $(am_libtme_machine_sun_la_OBJECTS)
 libtme_machine_sun_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -250,7 +251,8 @@
 	sun-cgsix.c \
 	sun-fb.c sun-fb.h \
 	sun-si.c \
-	sun-obie.c
+	sun-obie.c \
+	sun-oble.c
 
 libtme_machine_sun_la_LDFLAGS = -version-info 0:0:0
 libtme_machine_sun_la_LIBADD = $(top_builddir)/libtme/libtme.la \
@@ -374,6 +376,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-fb.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-mmu.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-obie.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-oble.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun-si.Plo@am__quote@
 
 .c.o:
diff --git a/machine/sun/sun-oble.c b/machine/sun/sun-oble.c
new file mode 100644
index 0000000..5942200
--- /dev/null
+++ b/machine/sun/sun-oble.c
@@ -0,0 +1,490 @@
+/* $Id:$ */
+
+/* machine/sun/sun-oble.c - classic Sun onboard Lance Ethernet implementation: */
+
+/*
+ * Copyright (c) 2012 Thomas Bogendoerfer
+ * All rights reserved.
+ *
+ * Based on sun-obie.c,  Copyright (c) 2004 Matt Fredette
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Matt Fredette.
+ * 4. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tme/common.h>
+_TME_RCSID("$Id$");
+
+/* includes: */
+#include <tme/element.h>
+#undef TME_BUS_VERSION
+#define TME_BUS_VERSION TME_X_VERSION(0, 0)
+#include <tme/generic/bus.h>
+#include <tme/machine/sun.h>
+
+/* macros: */
+
+/* register offsets and sizes: */
+#define TME_SUN_OBLE_REG_CSR	(0)
+#define TME_SUN_OBLE_SIZ_CSR	(4)
+
+/* structures: */
+
+/* the card: */
+struct tme_sun_oble {
+
+  /* backpointer to our element: */
+  struct tme_element *tme_sun_oble_element;
+
+  /* the mutex protecting the card: */
+  tme_mutex_t tme_sun_oble_mutex;
+
+  /* the bus connection for the card's registers: */
+  struct tme_bus_connection *tme_sun_oble_conn_regs;
+
+  /* the bus connection for the card's memory: */
+  struct tme_bus_connection *tme_sun_oble_conn_memory;
+
+  /* the bus connection for the card's am7990 chip: */
+  struct tme_bus_connection *tme_sun_oble_conn_am7990;
+};
+
+/* a sun_oble internal bus connection: */
+struct tme_sun_oble_connection {
+
+  /* the external bus connection: */
+  struct tme_bus_connection tme_sun_oble_connection;
+
+  /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection
+     is for the registers: */
+  tme_uint8_t tme_sun_oble_connection_regs;
+};
+
+/* globals: */
+
+/* our bus signals sets: */
+static const struct tme_bus_signals _tme_sun_oble_bus_signals_generic = TME_BUS_SIGNALS_GENERIC;
+
+/* the sun_oble bus signal handler: */
+static int
+_tme_sun_oble_bus_signal(struct tme_bus_connection *conn_bus, 
+			 unsigned int signal)
+{
+  struct tme_bus_connection *conn_out_bus;
+  struct tme_sun_oble *sun_oble;
+  int rc;
+
+  /* return now if this is not a generic bus signal: */
+  if (TME_BUS_SIGNAL_INDEX(signal)
+      > _tme_sun_oble_bus_signals_generic.tme_bus_signals_count) {
+    return (TME_OK);
+  }
+
+  /* recover our data structures: */
+  sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+  /* if this bus signal is from the am7990: */
+  if (conn_bus->tme_bus_connection.tme_connection_other
+      == &sun_oble->tme_sun_oble_conn_am7990->tme_bus_connection) {
+
+    /* this must be the unspecified interrupt signal: */
+    assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC);
+	  
+    /* get outgoing bus connection: */
+    conn_out_bus = sun_oble->tme_sun_oble_conn_regs;
+	
+  }
+
+  /* otherwise, this bus signal must be from obio: */
+  else {
+    assert (conn_bus->tme_bus_connection.tme_connection_other
+	    == &sun_oble->tme_sun_oble_conn_regs->tme_bus_connection);
+
+    conn_out_bus = sun_oble->tme_sun_oble_conn_am7990;
+  }
+
+  /* call out the bus interrupt signal edge: */
+  rc = (conn_out_bus != NULL
+	? ((*conn_out_bus->tme_bus_signal)
+	   (conn_out_bus, signal))
+	: TME_OK);
+
+  return (rc);
+}
+
+/* the sun_oble bus signals adder for the am7990: */
+static int
+_tme_sun_oble_bus_signals_add(struct tme_bus_connection *conn_bus,
+			     struct tme_bus_signals *bus_signals_caller)
+{
+  const struct tme_bus_signals *bus_signals;
+  tme_uint32_t signal_first;
+
+  /* we only support the generic: */
+  switch (bus_signals_caller->tme_bus_signals_id) {
+  case TME_BUS_SIGNALS_ID_GENERIC:
+    bus_signals = &_tme_sun_oble_bus_signals_generic;
+    signal_first = _tme_sun_oble_bus_signals_generic.tme_bus_signals_first;
+    break;
+  default:
+    return (ENOENT);
+  }
+  
+  /* XXX we should check versions here: */
+  *bus_signals_caller = *bus_signals;
+  bus_signals_caller->tme_bus_signals_first = signal_first;
+  return (TME_OK);
+}
+
+/* the sun_oble TLB adder for the Am7990: */
+static int
+_tme_sun_oble_tlb_set_add(struct tme_bus_connection *conn_bus,
+			  struct tme_bus_tlb_set_info *tlb_set_info)
+{
+  struct tme_sun_oble *sun_oble;
+
+  /* recover our data structures: */
+  sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+  /* pass the am7990 request through to the mainbus: */
+  conn_bus = sun_oble->tme_sun_oble_conn_memory;
+  return (conn_bus != NULL
+	  ? (*conn_bus->tme_bus_tlb_set_add)(conn_bus, 
+					     tlb_set_info)
+	  : ENXIO);
+}
+
+/* the sun_oble TLB filler for the memory: */
+static int
+_tme_sun_oble_tlb_fill(struct tme_bus_connection *conn_bus,
+		       struct tme_bus_tlb *tlb, 
+		       tme_bus_addr_t address, 
+		       unsigned int cycles)
+{
+  struct tme_sun_oble *sun_oble;
+
+  /* the address must be within range: */
+  assert(address <= 0xffffff);
+
+  /* recover our data structures: */
+  sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+
+  /* pass the am7990's request through to the mainbus: */
+  conn_bus = sun_oble->tme_sun_oble_conn_memory;
+  return (conn_bus != NULL
+	  ? (*conn_bus->tme_bus_tlb_fill)(conn_bus, 
+					  tlb,
+					  address,
+					  cycles)
+	  : ENXIO);
+}
+
+/* the sun_oble TLB filler for the board registers: */
+static int
+_tme_sun_oble_tlb_fill_regs(struct tme_bus_connection *conn_bus,
+			   struct tme_bus_tlb *tlb, 
+			   tme_bus_addr_t address, unsigned int cycles)
+{
+  struct tme_sun_oble *sun_oble;
+  struct tme_bus_connection *conn_am7990;
+  struct tme_bus_tlb tlb_mapping;
+  int rc;
+
+  /* the address must be within range: */
+  assert(address < TME_SUN_OBLE_SIZ_CSR);
+
+  /* recover our data structures: */
+  sun_oble = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
+  conn_am7990 = sun_oble->tme_sun_oble_conn_am7990;
+
+  /* call the Am7990 TLB fill function: */
+  rc = (conn_am7990 != NULL
+	? (*conn_am7990->tme_bus_tlb_fill)(conn_am7990, tlb,
+					   address, cycles)
+	: EINVAL);
+		
+  /* if that succeeded: */
+  if (rc == TME_OK) {
+    /* create the mapping TLB entry: */
+    tlb_mapping.tme_bus_tlb_addr_first = TME_SUN_OBLE_REG_CSR;
+    tlb_mapping.tme_bus_tlb_addr_last = TME_SUN_OBLE_SIZ_CSR - 1;
+    tlb_mapping.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
+			
+    /* map the filled TLB entry: */
+    tme_bus_tlb_map(tlb, 0, &tlb_mapping, 0);
+  }
+  return (rc);
+}
+
+/* this scores a new connection: */
+static int
+_tme_sun_oble_connection_score(struct tme_connection *conn, unsigned int *_score)
+{
+  struct tme_sun_oble *sun_oble;
+  struct tme_sun_oble_connection *conn_sun_oble;
+
+  /* both sides must be generic bus connections: */
+  assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
+  assert(conn->tme_connection_other->tme_connection_type
+	 == conn->tme_connection_type);
+
+  /* recover our data structures: */
+  sun_oble = conn->tme_connection_element->tme_element_private;
+  conn_sun_oble = (struct tme_sun_oble_connection *)conn;
+
+  /* this is a generic bus connection, so just score it nonzero and
+     return.  note that there's no good way to differentiate a
+     connection to a bus from a connection to just another chip, so we
+     always return a nonzero score here: */
+  *_score = 1;
+  return (TME_OK);
+}
+
+/* this makes a new connection: */
+static int
+_tme_sun_oble_connection_make(struct tme_connection *conn, unsigned int state)
+{
+  struct tme_sun_oble *sun_oble;
+  struct tme_sun_oble_connection *conn_sun_oble;
+  struct tme_bus_connection *conn_bus;
+
+  /* both sides must be generic bus connections: */
+  assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
+  assert(conn->tme_connection_other->tme_connection_type
+	 == conn->tme_connection_type);
+
+  /* recover our data structures: */
+  sun_oble = conn->tme_connection_element->tme_element_private;
+  conn_sun_oble = (struct tme_sun_oble_connection *)conn;
+  conn_bus = &conn_sun_oble->tme_sun_oble_connection;
+
+  /* we're always set up to answer calls across the connection, so we
+     only have to do work when the connection has gone full, namely
+     taking the other side of the connection: */
+  if (state == TME_CONNECTION_FULL) {
+
+    /* lock our mutex: */
+    tme_mutex_lock(&sun_oble->tme_sun_oble_mutex);
+
+    /* save our connection: */
+    if (conn_bus->tme_bus_signals_add != NULL) {
+      sun_oble->tme_sun_oble_conn_am7990 = (struct tme_bus_connection *) conn->tme_connection_other;
+    }
+    else if (conn_sun_oble->tme_sun_oble_connection_regs) {
+      sun_oble->tme_sun_oble_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
+    }
+    else {
+      sun_oble->tme_sun_oble_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
+    }
+
+    /* unlock our mutex: */
+    tme_mutex_unlock(&sun_oble->tme_sun_oble_mutex);
+  }
+
+  return (TME_OK);
+}
+
+/* this breaks a connection: */
+static int
+_tme_sun_oble_connection_break(struct tme_connection *conn, unsigned int state)
+{
+  abort();
+}
+
+/* this makes a new connection side for a sun_oble: */
+static int
+_tme_sun_oble_connections_new(struct tme_element *element,
+			     const char * const *args,
+			     struct tme_connection **_conns,
+			     char **_output)
+{
+  struct tme_sun_oble *sun_oble;
+  struct tme_sun_oble_connection *conn_sun_oble;
+  struct tme_bus_connection *conn_bus;
+  struct tme_connection *conn;
+  unsigned int am7990;
+  tme_uint8_t regs;
+  int usage;
+  int rc;
+
+  /* recover our data structure: */
+  sun_oble = (struct tme_sun_oble *) element->tme_element_private;
+  
+  /* we don't bother locking the mutex simply to check if connections
+     already exist: */
+
+  /* check our arguments: */
+  usage = FALSE;
+  rc = 0;
+  am7990 = FALSE;
+  regs = FALSE;
+
+  /* if this connection is for the registers: */
+  if (TME_ARG_IS(args[1], "csr")) {
+
+    /* if we already have a register connection, complain: */
+    if (sun_oble->tme_sun_oble_conn_regs != NULL) {
+      rc = EEXIST;
+    }
+
+    /* otherwise, make the new connection: */
+    else {
+      regs = TRUE;
+    }
+  }
+
+  /* else, if this connection is for the memory: */
+  else if (TME_ARG_IS(args[1], "memory")) {
+
+    /* if we already have a memory connection, complain: */
+    if (sun_oble->tme_sun_oble_conn_memory != NULL) {
+      rc = EEXIST;
+    }
+  }
+
+  /* else, the connection must be for the am7990: */
+  else if (args[1] == NULL) {
+    
+    /* if we already have an am7990 connection, complain: */
+    if (sun_oble->tme_sun_oble_conn_am7990 != NULL) {
+      rc = EEXIST;
+    }
+
+    /* otherwise, make the new conection: */
+    else {
+      am7990 = TRUE;
+    }
+  }
+
+  /* otherwise, this is a bad argument: */
+  else {
+    tme_output_append_error(_output,
+			    "%s %s, ",
+			    args[1],
+			    _("unexpected"));
+    usage = TRUE;
+  }
+
+  if (usage) {
+    tme_output_append_error(_output, 
+			    "%s %s [ csr | memory ]",
+			    _("usage:"),
+			    args[0]);
+    rc = EINVAL;
+  }
+  
+  if (rc) {
+    return (rc);
+  }
+
+  /* make a new connection: */
+  conn_sun_oble = tme_new0(struct tme_sun_oble_connection, 1);
+  conn_bus = &conn_sun_oble->tme_sun_oble_connection;
+  conn = &conn_bus->tme_bus_connection;
+
+  /* fill in the generic connection: */
+  conn->tme_connection_next = *_conns;
+  conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
+  conn->tme_connection_score = _tme_sun_oble_connection_score;
+  conn->tme_connection_make = _tme_sun_oble_connection_make;
+  conn->tme_connection_break = _tme_sun_oble_connection_break;
+
+  /* fill in the generic bus connection: */
+  conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0;
+  conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL;
+  if (am7990) {
+    conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0xffffff;
+    conn_bus->tme_bus_signals_add = _tme_sun_oble_bus_signals_add;
+    conn_bus->tme_bus_signal = _tme_sun_oble_bus_signal;
+    conn_bus->tme_bus_tlb_set_add = _tme_sun_oble_tlb_set_add;
+    conn_bus->tme_bus_tlb_fill = _tme_sun_oble_tlb_fill;
+  }
+  else if (regs) {
+    conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_OBLE_SIZ_CSR - 1;
+    conn_bus->tme_bus_signal = _tme_sun_oble_bus_signal;
+    conn_bus->tme_bus_tlb_fill = _tme_sun_oble_tlb_fill_regs;
+  }
+  else {
+    conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0;
+  }
+
+  /* fill in the internal information: */
+  conn_sun_oble->tme_sun_oble_connection_regs = regs;
+
+  /* return the connection side possibility: */
+  *_conns = conn;
+  return (TME_OK);
+}
+
+/* the new sun_oble function: */
+int
+tme_sun_oble(struct tme_element *element, const char * const *args, char **_output)
+{
+  struct tme_sun_oble *sun_oble;
+  int arg_i;
+  int usage;
+
+  /* check our arguments: */
+  usage = 0;
+  arg_i = 1;
+  for (;;) {
+
+    /* if we ran out of arguments: */
+    if (args[arg_i] == NULL) {
+
+      break;
+    }
+
+    /* otherwise this is a bad argument: */
+    else {
+      tme_output_append_error(_output,
+			      "%s %s, ",
+			      args[arg_i],
+			      _("unexpected"));
+      usage = TRUE;
+      break;
+    }
+  }
+
+  if (usage) {
+    tme_output_append_error(_output, 
+			    "%s %s",
+			    _("usage:"),
+			    args[0]);
+    return (EINVAL);
+  }
+
+  /* start the sun_oble structure: */
+  sun_oble = tme_new0(struct tme_sun_oble, 1);
+  sun_oble->tme_sun_oble_element = element;
+  tme_mutex_init(&sun_oble->tme_sun_oble_mutex);
+
+  /* fill the element: */
+  element->tme_element_private = sun_oble;
+  element->tme_element_connections_new = _tme_sun_oble_connections_new;
+
+  return (TME_OK);
+}
diff --git a/machine/sun3/sun3-mainbus.c b/machine/sun3/sun3-mainbus.c
index 292f3d4..1812e09 100644
--- a/machine/sun3/sun3-mainbus.c
+++ b/machine/sun3/sun3-mainbus.c
@@ -810,6 +810,11 @@
   return (tme_sun_obie(element, args, _output));
 }
 
+/* this creates a new Sun-3 oble: */
+TME_ELEMENT_SUB_NEW_DECL(tme_machine_sun3,oble) {
+  return (tme_sun_oble(element, args, _output));
+}
+
 /* this creates a new Sun-3 bwtwo: */
 TME_ELEMENT_SUB_NEW_DECL(tme_machine_sun3,bwtwo) {
   return (tme_sun_bwtwo(element, args, _output));
diff --git a/tme/machine/sun.h b/tme/machine/sun.h
index 3ea4b35..f2c416f 100644
--- a/tme/machine/sun.h
+++ b/tme/machine/sun.h
@@ -162,6 +162,9 @@
 /* onboard Intel Ethernet support: */
 int tme_sun_obie _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));
 
+/* onboard Lance Ethernet support: */
+int tme_sun_oble _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));
+
 /* bwtwo support: */
 int tme_sun_bwtwo _TME_P((struct tme_element *, _tme_const char * _tme_const *, char **));