summaryrefslogtreecommitdiffstats
path: root/c/src/libchip
diff options
context:
space:
mode:
authorRalf Corsepius <ralf.corsepius@rtems.org>2006-01-09 15:41:42 +0000
committerRalf Corsepius <ralf.corsepius@rtems.org>2006-01-09 15:41:42 +0000
commit9d8ad283c2ac3b3ec694a5e6a3dcdabc3a4841d1 (patch)
treee5882b80a81d5c645b80e72ee0ade5189e4d8163 /c/src/libchip
parent2006-01-09 Ralf Corsepius <ralf.corsepius@rtems.org> (diff)
downloadrtems-9d8ad283c2ac3b3ec694a5e6a3dcdabc3a4841d1.tar.bz2
2006-01-09 Ralf Corsepius <ralf.corsepius@rtems.org>
* libchip/network/smc91111.c libchip/network/smc91111config.h libchip/network/smc91111exp.h libchip/network/smc91111.h: New. Merger from rtems-4-6-branch. * libchip/Makefile.am: Reflect adding smc91111*.
Diffstat (limited to 'c/src/libchip')
-rw-r--r--c/src/libchip/Makefile.am10
-rw-r--r--c/src/libchip/network/smc91111.c1588
-rw-r--r--c/src/libchip/network/smc91111.h552
-rw-r--r--c/src/libchip/network/smc91111config.h132
-rw-r--r--c/src/libchip/network/smc91111exp.h19
5 files changed, 2297 insertions, 4 deletions
diff --git a/c/src/libchip/Makefile.am b/c/src/libchip/Makefile.am
index 63f1da3f77..f964b6ef26 100644
--- a/c/src/libchip/Makefile.am
+++ b/c/src/libchip/Makefile.am
@@ -29,16 +29,18 @@ endif
# network
if LIBCHIP
if HAS_NETWORKING
+noinst_LIBRARIES += libnetchip.a
+libnetchip_a_CPPFLAGS = $(AM_CPPFLAGS)
+libnetchip_a_CPPFLAGS += -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
include_libchip_HEADERS += network/cs8900.h network/i82586var.h \
network/if_fxpvar.h network/sonic.h
include_libchip_HEADERS += network/open_eth.h network/if_dcreg.h
-
-libnetchip_CPPFLAGS = -D__INSIDE_RTEMS_BSD_TCPIP_STACK__
-noinst_LIBRARIES += libnetchip.a
libnetchip_a_SOURCES = network/cs8900.c network/dec21140.c network/i82586.c \
network/sonic.c network/if_fxp.c network/elnk.c network/open_eth.c \
network/if_dc.c
-libnetchip_a_CPPFLAGS = $(AM_CPPFLAGS) $(libnetchip_CPPFLAGS)
+# FIXME: These don't compile
+include_libchip_HEADERS += network/smc91111.h network/smc91111exp.h
+# libnetchip_a_SOURCES += network/smc91111.c network/smc91111config.h
endif
endif
diff --git a/c/src/libchip/network/smc91111.c b/c/src/libchip/network/smc91111.c
new file mode 100644
index 0000000000..94ea6fc6b0
--- /dev/null
+++ b/c/src/libchip/network/smc91111.c
@@ -0,0 +1,1588 @@
+/*
+ * $Id$
+ */
+
+#include <rtems.h>
+#include <errno.h>
+
+/*
+ * This driver currently only supports architectures with the old style
+ * exception processing. The following checks try to keep this
+ * from being compiled on systems which can't support this driver.
+ *
+ * NOTE: As of 28 September 2005, this has only been tested on the SPARC,
+ * so that is all it is enabled for.
+ */
+
+#if defined(__sparc__)
+ #define SMC91111_SUPPORTED
+#endif
+
+#if defined(SMC91111_SUPPORTED)
+
+#include <bsp.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <rtems/error.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#define SMC91111_INTERRUPT_EVENT RTEMS_EVENT_1 /* RTEMS event used by interrupt handler to signal driver tasks. This must not be any of the events used by the network task synchronization. */
+#define SMC91111_START_TRANSMIT_EVENT RTEMS_EVENT_2 /* RTEMS event used to start transmit/receive daemon. This must not be the same as INTERRUPT_EVENT. */
+#define SMC91111_TX_WAIT_EVENT RTEMS_EVENT_3 /* event to send when tx buffers become available */
+
+/* Set to perms of:
+ 0 disables all debug output
+ 1 for process debug output
+ 2 for added data IO output: get_reg, put_reg
+ 4 for packet allocation/free output
+ 8 for only startup status, so we can tell we're installed OK
+ 16 dump phy read/write
+ 32 precise register dump
+ 64 dump packets
+*/
+/*#define DEBUG (-1)*/
+/*#define DEBUG (-1 & ~(16))*/
+#define DEBUG (0)
+
+#include "smc91111config.h"
+#include <libchip/smc91111.h>
+
+struct lan91cxx_priv_data smc91111;
+
+int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd);
+static cyg_uint16 lan91cxx_read_phy(struct lan91cxx_priv_data *cpd,
+ cyg_uint8 phyaddr, cyg_uint8 phyreg);
+static void lan91cxx_write_phy(struct lan91cxx_priv_data *cpd,
+ cyg_uint8 phyaddr, cyg_uint8 phyreg,
+ cyg_uint16 value);
+static void lan91cxx_start(struct ifnet *ifp);
+static void smc91111_start(struct ifnet *ifp);
+static int smc_probe(struct lan91cxx_priv_data *cpd);
+static void smc91111_stop(struct lan91cxx_priv_data *cpd);
+static void smc91111_init(void *arg);
+static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd);
+#if 0
+static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd);
+static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd);
+#endif
+
+#define min(l,r) ((l) < (r) ? (l) : (r))
+#define max(l,r) ((l) > (r) ? (l) : (r))
+
+/* \ ------------- Interrupt ------------- \ */
+rtems_isr lan91cxx_interrupt_handler(rtems_vector_number v)
+{
+ struct lan91cxx_priv_data *cpd = &smc91111;
+ unsigned short irq, event;
+ unsigned short oldbase;
+ unsigned short oldpointer;
+ INCR_STAT(cpd, interrupts);
+ DEBUG_FUNCTION();
+
+ HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
+ oldpointer = get_reg(cpd, LAN91CXX_POINTER);
+
+ /* Get the (unmasked) requests */
+ irq = get_reg(cpd, LAN91CXX_INTERRUPT);
+ event = irq & (irq >> 8) & 0xff;
+ if (0 == event)
+ return;
+
+ /*put_reg(cpd, LAN91CXX_INTERRUPT, irq ); *//* ack interrupts */
+
+ if (event & LAN91CXX_INTERRUPT_ERCV_INT) {
+ db_printf("Early receive interrupt");
+ } else if (event & LAN91CXX_INTERRUPT_EPH_INT) {
+ db_printf("ethernet protocol handler failures");
+ } else if (event & LAN91CXX_INTERRUPT_RX_OVRN_INT) {
+ db_printf("receive overrun");
+ } else if (event & LAN91CXX_INTERRUPT_ALLOC_INT) {
+ db_printf("allocation interrupt");
+ } else {
+
+ if (event & LAN91CXX_INTERRUPT_TX_SET) {
+ DEBUG_puts("#tx error\n");
+ db_printf("#*tx irq\n");
+ lan91cxx_finish_sent(cpd);
+ put_reg(cpd, LAN91CXX_INTERRUPT,
+ (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT);
+
+ /*rtems_event_send (cpd->txDaemonTid, SMC91111_INTERRUPT_EVENT); */
+ /*put_reg(cpd, LAN91CXX_INTERRUPT, (irq & 0xff00) | LAN91CXX_INTERRUPT_TX_INT); */
+ /*rtems_event_send (cpd->txDaemonTid, SMC91111_TX_WAIT_EVENT); */
+ }
+ if (event & LAN91CXX_INTERRUPT_RCV_INT) {
+ db_printf("#*rx irq\n");
+ rtems_event_send(cpd->rxDaemonTid,
+ SMC91111_INTERRUPT_EVENT);
+ }
+ if (event &
+ ~(LAN91CXX_INTERRUPT_TX_SET | LAN91CXX_INTERRUPT_RCV_INT))
+ db_printf("Unknown interrupt\n");
+ }
+ db_printf("out %s\n", __FUNCTION__);
+
+ put_reg(cpd, LAN91CXX_POINTER, oldpointer);
+ HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), oldbase);
+}
+
+/* \ ------------- Rx receive ------------- \ */
+
+ /**/
+/* This function is called as a result of the "readpacket()" call.*/
+/* Its job is to actually fetch data for a packet from the hardware once*/
+/* memory buffers have been allocated for the packet. Note that the buffers*/
+/* may come in pieces, using a mbuf list. */
+static void lan91cxx_recv(struct lan91cxx_priv_data *cpd, struct mbuf *m)
+{
+ struct ifnet *ifp = &cpd->arpcom.ac_if;
+ struct ether_header *eh;
+ short mlen = 0, plen;
+ char *start;
+ rxd_t *data = NULL, val, lp;
+ struct mbuf *n;
+ lp = 0;
+ dbg_prefix = "<";
+
+ DEBUG_FUNCTION();
+ INCR_STAT(cpd, rx_deliver);
+
+ /* ############ read packet ############ */
+
+ put_reg(cpd, LAN91CXX_POINTER,
+ (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
+ LAN91CXX_POINTER_AUTO_INCR));
+ val = get_data(cpd);
+
+ /* packet length (minus header/footer) */
+#ifdef LAN91CXX_32BIT_RX
+ val = CYG_LE32_TO_CPU(val);
+ plen = (val >> 16) - 6;
+#else
+ val = CYG_LE16_TO_CPU(val);
+ plen = get_data(cpd);
+ plen = CYG_LE16_TO_CPU(plen) - 6;
+#endif
+
+ if (LAN91CXX_RX_STATUS_IS_ODD(cpd, val))
+ plen++;
+
+ for (n = m; n; n = n->m_next) {
+#ifdef LAN91CXX_32BIT_RX
+ if (mlen == 2) {
+#if DEBUG & 64
+ db_printf("Appending to last apacket\n");
+#endif
+
+ val = get_data(cpd);
+ *((unsigned short *)data) = (val >> 16) & 0xffff;
+ plen -= 2;
+ data = (rxd_t *) n->m_data;
+ start = (char *)data;
+ mlen = n->m_len;
+ if ((data) && (mlen > 1)) {
+ *((unsigned short *)data)++ = (val & 0xffff);
+ plen -= 2;
+ mlen -= 2;
+ }
+ } else {
+ data = (rxd_t *) n->m_data;
+ start = (char *)data;
+ mlen = n->m_len;
+ }
+#else
+ data = (rxd_t *) n->m_data;
+ start = (char *)data;
+ mlen = n->m_len;
+#endif
+
+ db1_printf("<[packet : mlen 0x%x, plen 0x%x]\n", mlen, plen);
+
+ if (data) {
+ while (mlen >= sizeof(*data)) {
+#ifdef LAN91CXX_32BIT_RX
+ val = get_data(cpd);
+ *((unsigned short *)data)++ =
+ (val >> 16) & 0xffff;
+ *((unsigned short *)data)++ = (val & 0xffff);
+#else
+ *data++ = get_data(cpd);
+#endif
+ mlen -= sizeof(*data);
+ plen -= sizeof(*data);
+ }
+ } else { /* must actively discard ie. read it from the chip anyway. */
+ while (mlen >= sizeof(*data)) {
+ (void)get_data(cpd);
+ mlen -= sizeof(*data);
+ plen -= sizeof(*data);
+ }
+ }
+
+#if DEBUG & 64
+ lp = 0;
+ while (((int)start) < ((int)data)) {
+ unsigned char a = *(start++);
+ unsigned char b = *(start++);
+ db64_printf("%02x %02x ", a, b);
+ lp += 2;
+ if (lp >= 16) {
+ db64_printf("\n");
+ lp = 0;
+ }
+ }
+ db64_printf(" \n");
+
+#endif
+ }
+ val = get_data(cpd); /* Read control word (and potential data) unconditionally */
+#ifdef LAN91CXX_32BIT_RX
+ if (plen & 2) {
+ if (data) {
+ *((unsigned short *)data)++ = (val >> 16) & 0xffff;
+ val <<= 16;
+ }
+ }
+ if (plen & 1)
+ *(unsigned char *)data = val >> 24;
+#else
+ val = CYG_LE16_TO_CPU(val);
+ cp = (unsigned char *)data;
+
+ CYG_ASSERT(val & LAN91CXX_CONTROLBYTE_RX, "Controlbyte is not for Rx");
+ CYG_ASSERT((1 == mlen) == (0 != LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)),
+ "Controlbyte does not match");
+ if (data && (1 == mlen) && LAN91CXX_CONTROLBYTE_IS_ODD(cpd, val)) {
+ cval = val & 0x00ff; /* last byte contains data */
+ *cp = cval;
+ }
+#endif
+
+ val = get_reg(cpd, LAN91CXX_FIFO_PORTS);
+ if (0x8000 & val) { /* Then the Rx FIFO is empty */
+ db4_printf
+ ("<+Rx packet NOT freed, stat is %x (expected %x)\n",
+ val, cpd->rxpacket);
+ } else {
+ db4_printf("<+Rx packet freed %x (expected %x)\n",
+ 0xff & (val >> 8), cpd->rxpacket);
+ }
+
+ CYG_ASSERT((0xff & (val >> 8)) == cpd->rxpacket,
+ "Unexpected rx packet");
+
+ /* ############ free packet ############ */
+ /* Free packet */
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
+
+ dbg_prefix = "";
+
+ /* Remove the mac header. This is different from the NetBSD stack. */
+ eh = mtod(m, struct ether_header *);
+ m->m_data += sizeof(struct ether_header);
+ m->m_len -= sizeof(struct ether_header);
+ m->m_pkthdr.len -= sizeof(struct ether_header);
+
+ ether_input(ifp, eh, m);
+
+}
+
+/* allocate mbuf chain */
+static struct mbuf *smc91111_allocmbufchain(int totlen, struct ifnet *ifp)
+{
+
+ struct mbuf *m, *m0, *newm;
+ int len;
+
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 == 0)
+ return (0);
+ m0->m_pkthdr.rcvif = ifp;
+ m0->m_pkthdr.len = totlen;
+ len = MHLEN;
+ m = m0;
+
+ /* This loop goes through and allocates mbufs for all the data we will be copying in. */
+ while (totlen > 0) {
+ if (totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0)
+ goto bad;
+ len = MCLBYTES;
+ }
+
+ if (m == m0) {
+ caddr_t newdata = (caddr_t)
+ ALIGN(m->m_data +
+ sizeof(struct ether_header)) -
+ sizeof(struct ether_header);
+ len -= newdata - m->m_data;
+ m->m_data = newdata;
+ }
+
+ m->m_len = len = min(totlen, len);
+
+ totlen -= len;
+ if (totlen > 0) {
+ MGET(newm, M_DONTWAIT, MT_DATA);
+ if (newm == 0)
+ goto bad;
+ len = MLEN;
+ m = m->m_next = newm;
+ }
+ }
+ return (m0);
+
+ bad:
+ m_freem(m0);
+ return (0);
+}
+
+static int readpacket(struct lan91cxx_priv_data *cpd)
+{
+ struct mbuf *m;
+ unsigned short stat, complen;
+ struct ifnet *ifp = &cpd->arpcom.ac_if;
+#ifdef LAN91CXX_32BIT_RX
+ cyg_uint32 val;
+#endif
+
+ DEBUG_FUNCTION();
+
+ /* ############ read packet nr ############ */
+ stat = get_reg(cpd, LAN91CXX_FIFO_PORTS);
+ db1_printf("+LAN91CXX_FIFO_PORTS: 0x%04x\n", stat);
+
+ if (0x8000 & stat) {
+ /* Then the Rx FIFO is empty */
+ db4_printf("!RxEvent with empty fifo\n");
+ return 0;
+ }
+
+ INCR_STAT(cpd, rx_count);
+
+ db4_printf("+Rx packet allocated %x (previous %x)\n",
+ 0xff & (stat >> 8), cpd->rxpacket);
+
+ /* There is an Rx Packet ready */
+ cpd->rxpacket = 0xff & (stat >> 8);
+
+ /* ############ read packet header ############ */
+ /* Read status and (word) length */
+ put_reg(cpd, LAN91CXX_POINTER,
+ (LAN91CXX_POINTER_RCV | LAN91CXX_POINTER_READ |
+ LAN91CXX_POINTER_AUTO_INCR | 0x0000));
+#ifdef LAN91CXX_32BIT_RX
+ val = get_data(cpd);
+ val = CYG_LE32_TO_CPU(val);
+ stat = val & 0xffff;
+ complen = ((val >> 16) & 0xffff) - 6; /* minus header/footer words */
+#else
+ stat = get_data(cpd);
+ stat = CYG_LE16_TO_CPU(stat);
+ complen = get_data(cpd);
+ complen = CYG_LE16_TO_CPU(len) - 6; /* minus header/footer words */
+#endif
+
+#ifdef KEEP_STATISTICS
+ if (stat & LAN91CXX_RX_STATUS_ALIGNERR)
+ INCR_STAT(cpd, rx_align_errors);
+ /*if ( stat & LAN91CXX_RX_STATUS_BCAST ) INCR_STAT( ); */
+ if (stat & LAN91CXX_RX_STATUS_BADCRC)
+ INCR_STAT(cpd, rx_crc_errors);
+ if (stat & LAN91CXX_RX_STATUS_TOOLONG)
+ INCR_STAT(cpd, rx_too_long_frames);
+ if (stat & LAN91CXX_RX_STATUS_TOOSHORT)
+ INCR_STAT(cpd, rx_short_frames);
+ /*if ( stat & LAN91CXX_RX_STATUS_MCAST ) INCR_STAT( ); */
+#endif /* KEEP_STATISTICS */
+
+ if ((stat & LAN91CXX_RX_STATUS_BAD) == 0) {
+ INCR_STAT(cpd, rx_good);
+ /* Then it's OK */
+
+ if (LAN91CXX_RX_STATUS_IS_ODD(cpd, stat))
+ complen++;
+
+#if DEBUG & 1
+ db_printf("good rx - stat: 0x%04x, len: 0x%04x\n", stat,
+ complen);
+#endif
+ /* Check for bogusly short packets; can happen in promisc mode: */
+ /* Asserted against and checked by upper layer driver. */
+ if (complen > sizeof(struct ether_header)) {
+ /* then it is acceptable; offer the data to the network stack */
+
+ complen = ((complen + 3) & ~3);
+
+ m = smc91111_allocmbufchain(complen, ifp);
+ {
+ struct mbuf *n = m;
+ db_printf("mbuf-chain:");
+ while (n) {
+ db_printf("[%x:%x]",
+ (unsigned int)(n->
+ m_data),
+ (unsigned int)(n->m_len));
+ n = n->m_next;
+ }
+ db_printf("\n");
+ }
+
+ if (m) {
+ /* fetch packet data into mbuf chain */
+ lan91cxx_recv(cpd, m);
+ return 1;
+ }
+ }
+ /*(sc->funs->eth_drv->recv)(sc, len); */
+ }
+
+ /* Not OK for one reason or another... */
+ db1_printf("!bad rx: stat: 0x%04x, len: 0x%04x\n", stat, complen);
+
+ /* ############ free packet ############ */
+ /* Free packet */
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_remrel_rx_frame);
+ return 1;
+
+}
+
+static void smc91111_rxDaemon(void *arg)
+{
+ struct lan91cxx_priv_data *cpd = arg;
+ rtems_event_set events;
+ DEBUG_FUNCTION();
+
+ for (;;) {
+ rtems_bsdnet_event_receive(INTERRUPT_EVENT,
+ RTEMS_WAIT | RTEMS_EVENT_ANY,
+ RTEMS_NO_TIMEOUT, &events);
+
+ /* read until read fifo is empty */
+ while (!(get_reg(cpd, LAN91CXX_FIFO_PORTS) & 0x8000)) {
+ readpacket(cpd);
+ }
+ }
+}
+
+/* \ ------------- Tx send ------------- \ */
+
+static void sendpacket(struct ifnet *ifp, struct mbuf *m)
+{
+ struct lan91cxx_priv_data *cpd = ifp->if_softc;
+ int i, len, plen, tcr;
+ struct mbuf *n = m;
+ unsigned short *sdata = NULL;
+ unsigned short ints, control;
+ cyg_uint16 packet, status;
+ dbg_prefix = ">";
+ DEBUG_FUNCTION();
+
+ cpd->txbusy = 1;
+
+ /* Worry about the TX engine stopping. */
+ tcr = get_reg(cpd, LAN91CXX_TCR);
+ if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
+ db1_printf("> ENGINE RESTART: tcr %x\n", tcr);
+ tcr |= LAN91CXX_TCR_TXENA;
+ put_reg(cpd, LAN91CXX_TCR, tcr);
+ }
+
+ /* ############ packet allocation ############ */
+
+ /* Find packet length */
+ plen = 0;
+ while (n) {
+ plen += n->m_len;
+ n = n->m_next;
+ }
+
+ /* Alloc new TX packet */
+ do {
+ put_reg(cpd, LAN91CXX_MMU_COMMAND,
+ LAN91CXX_MMU_alloc_for_tx | ((plen >> 8) & 0x07));
+
+ i = 1024 * 1024;
+ do {
+ status = get_reg(cpd, LAN91CXX_INTERRUPT);
+ } while (0 == (status & LAN91CXX_INTERRUPT_ALLOC_INT)
+ && (--i > 0));
+ if (i)
+ packet = get_reg(cpd, LAN91CXX_PNR);
+ else
+ packet = 0xffff;
+ db1_printf(">+allocated packet %04x\n", packet);
+
+ packet = packet >> 8;
+ if (packet & 0x80) {
+ /* Hm.. Isn't this a dead end? */
+ db1_printf("Allocation failed! Retrying...\n");
+ continue;
+ }
+ } while (0);
+
+ db4_printf(">+Tx packet allocated %x (previous %x)\n",
+ packet, cpd->txpacket);
+
+ cpd->txpacket = packet;
+
+ /* ############ assemble packet data ############ */
+
+ /* prepare send */
+ put_reg(cpd, LAN91CXX_PNR, packet);
+ /* Note: Check FIFO state here before continuing? */
+ put_reg(cpd, LAN91CXX_POINTER, LAN91CXX_POINTER_AUTO_INCR | 0x0000);
+ /* Pointer is now set, and the proper bank is selected for */
+ /* data writes. */
+
+ /* Prepare header: */
+ put_data(cpd, CYG_CPU_TO_LE16(0)); /* reserve space for status word */
+ /* packet length (includes status, byte-count and control shorts) */
+ put_data(cpd, CYG_CPU_TO_LE16(0x7FE & (plen + 6))); /* Always even, always < 15xx(dec) */
+
+ /* Put data into buffer */
+ n = m;
+ while (n) {
+ sdata = (unsigned short *)n->m_data;
+ len = n->m_len;
+
+ CYG_ASSERT((0 == (len & 1)
+ || !(n->m_next)), "!odd length");
+ CYG_ASSERT(sdata, "!No sg data pointer here");
+
+ while (len >= sizeof(*sdata)) {
+ put_data(cpd, *sdata++);
+ len -= sizeof(*sdata);
+ }
+ n = n->m_next;
+ }
+#if DEBUG & 64
+ n = m;
+ while (n) {
+ int lp = 0;
+ unsigned char *start = (unsigned char *)n->m_data;
+ len = n->m_len;
+ while (len > 0) {
+ unsigned char a = *(start++);
+ unsigned char b = *(start++);
+ db64_printf("%02x %02x ", a, b);
+ lp += 2;
+ if (lp >= 16) {
+ db64_printf("\n");
+ lp = 0;
+ }
+ len -= 2;
+ }
+ n = n->m_next;
+ }
+ db64_printf(" \n");
+#endif
+
+ m_freem(m);
+ CYG_ASSERT(sdata, "!No sg data pointer outside");
+
+ /* Lay down the control short unconditionally at the end. */
+ /* (or it might use random memory contents) */
+ control = 0;
+ if (1 & plen) {
+ /* Need to set ODD flag and insert the data */
+ unsigned char onebyte = *(unsigned char *)sdata;
+ control = onebyte;
+ control |= LAN91CXX_CONTROLBYTE_ODD;
+ }
+ control |= LAN91CXX_CONTROLBYTE_CRC; /* Just in case... */
+ put_data(cpd, CYG_CPU_TO_LE16(control));
+
+ /* ############ start transmit ############ */
+
+ /* Ack TX empty int and unmask it. */
+ ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
+ put_reg(cpd, LAN91CXX_INTERRUPT,
+ ints | LAN91CXX_INTERRUPT_TX_EMPTY_INT);
+ put_reg(cpd, LAN91CXX_INTERRUPT, ints | LAN91CXX_INTERRUPT_TX_INT_M); /* notify on error only (Autorelease) */
+
+ /* Enqueue the packet */
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_enq_packet);
+
+ ints = get_reg(cpd, LAN91CXX_INTERRUPT);
+ db1_printf(">END: ints at TX: %04x\n", ints);
+ dbg_prefix = "";
+}
+
+void smc91111_txDaemon(void *arg)
+{
+ struct lan91cxx_priv_data *cpd = arg;
+ struct ifnet *ifp = &cpd->arpcom.ac_if;
+ struct mbuf *m;
+ rtems_event_set events;
+ DEBUG_FUNCTION();
+
+ for (;;) {
+ /*
+ * Wait for packet
+ */
+
+ rtems_bsdnet_event_receive
+ (SMC91111_START_TRANSMIT_EVENT,
+ RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events);
+
+ /*IF_DEQUEUE (&ifp->if_snd, m);
+ if (m) {
+ sendpacket (ifp, m);
+ } */
+
+ for (;;) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (!m)
+ break;
+ sendpacket(ifp, m);
+ }
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ }
+
+}
+
+/* start transmit */
+static void smc91111_start(struct ifnet *ifp)
+{
+ struct lan91cxx_priv_data *cpd = ifp->if_softc;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ rtems_event_send(cpd->txDaemonTid, START_TRANSMIT_EVENT);
+ ifp->if_flags |= IFF_OACTIVE;
+
+}
+
+/* called after a tx error interrupt, freet the packet */
+static void lan91cxx_finish_sent(struct lan91cxx_priv_data *cpd)
+{
+ unsigned short packet, tcr;
+ int success = 1;
+ int saved_packet;
+
+ DEBUG_FUNCTION();
+
+ INCR_STAT(cpd, tx_complete);
+
+ saved_packet = get_reg(cpd, LAN91CXX_PNR);
+
+ /* Ack and mask TX interrupt set */
+ /*ints = get_reg(cpd, LAN91CXX_INTERRUPT) & 0xff00;
+ ints |= LAN91CXX_INTERRUPT_TX_SET_ACK;
+ ints &= ~LAN91CXX_INTERRUPT_TX_SET_M;
+ put_reg(cpd, LAN91CXX_INTERRUPT, ints); */
+
+ /* Get number of completed packet and read the status word */
+ packet = get_reg(cpd, LAN91CXX_FIFO_PORTS);
+ db1_printf("%s:START: fifo %04x \n", __FUNCTION__, packet);
+
+ {
+ unsigned short reg;
+
+ reg = get_reg(cpd, LAN91CXX_EPH_STATUS);
+
+ /* Covering each bit in turn... */
+ if (reg & LAN91CXX_STATUS_TX_UNRN)
+ INCR_STAT(cpd, tx_underrun);
+ if (reg & LAN91CXX_STATUS_LOST_CARR)
+ INCR_STAT(cpd, tx_carrier_loss);
+ if (reg & LAN91CXX_STATUS_LATCOL)
+ INCR_STAT(cpd, tx_late_collisions);
+ if (reg & LAN91CXX_STATUS_TX_DEFR)
+ INCR_STAT(cpd, tx_deferred);
+ if (reg & LAN91CXX_STATUS_SQET)
+ INCR_STAT(cpd, tx_sqetesterrors);
+ if (reg & LAN91CXX_STATUS_16COL)
+ INCR_STAT(cpd, tx_max_collisions);
+ if (reg & LAN91CXX_STATUS_MUL_COL)
+ INCR_STAT(cpd, tx_mult_collisions);
+ if (reg & LAN91CXX_STATUS_SNGL_COL)
+ INCR_STAT(cpd, tx_single_collisions);
+ if (reg & LAN91CXX_STATUS_TX_SUC)
+ INCR_STAT(cpd, tx_good);
+
+ cpd->stats.tx_total_collisions =
+ cpd->stats.tx_late_collisions +
+ cpd->stats.tx_max_collisions +
+ cpd->stats.tx_mult_collisions +
+ cpd->stats.tx_single_collisions;
+
+ /* We do not need to look in the Counter Register (LAN91CXX_COUNTER)
+ because it just mimics the info we already have above. */
+ }
+
+ /* We do not really care about Tx failure. Ethernet is not a reliable
+ medium. But we do care about the TX engine stopping. */
+ tcr = get_reg(cpd, LAN91CXX_TCR);
+ if (0 == (LAN91CXX_TCR_TXENA & tcr)) {
+ db1_printf("%s: ENGINE RESTART: tcr %x \n", __FUNCTION__, tcr);
+ tcr |= LAN91CXX_TCR_TXENA;
+ put_reg(cpd, LAN91CXX_TCR, tcr);
+ success = 0; /* And treat this as an error... */
+ }
+
+ packet &= 0xff;
+
+ /* and then free the packet */
+ put_reg(cpd, LAN91CXX_PNR, cpd->txpacket);
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_rel_packet);
+
+ while (get_reg(cpd, LAN91CXX_MMU_COMMAND) & LAN91CXX_MMU_COMMAND_BUSY) ;
+ /* Don't change Packet Number Reg until busy bit is cleared */
+ /* Per LAN91C111 Spec, Page 50 */
+ put_reg(cpd, LAN91CXX_PNR, saved_packet);
+
+}
+
+/* \ ------------- Helpers ------------- \ */
+
+/*
+ * Show interface statistics
+ */
+static void smc91111_stats(struct lan91cxx_priv_data *priv)
+{
+ printf("tx_good :%-8d", priv->stats.tx_good);
+ printf("tx_max_collisions :%-8d", priv->stats.tx_max_collisions);
+ printf("tx_late_collisions :%-8d", priv->stats.tx_late_collisions);
+ printf("tx_underrun :%-8d", priv->stats.tx_underrun);
+ printf("tx_carrier_loss :%-8d", priv->stats.tx_carrier_loss);
+ printf("tx_deferred :%-8d", priv->stats.tx_deferred);
+ printf("tx_sqetesterrors :%-8d", priv->stats.tx_sqetesterrors);
+ printf("tx_single_collisions:%-8d", priv->stats.tx_single_collisions);
+ printf("tx_mult_collisions :%-8d", priv->stats.tx_mult_collisions);
+ printf("tx_total_collisions :%-8d", priv->stats.tx_total_collisions);
+ printf("rx_good :%-8d", priv->stats.rx_good);
+ printf("rx_crc_errors :%-8d", priv->stats.rx_crc_errors);
+ printf("rx_align_errors :%-8d", priv->stats.rx_align_errors);
+ printf("rx_resource_errors :%-8d", priv->stats.rx_resource_errors);
+ printf("rx_overrun_errors :%-8d", priv->stats.rx_overrun_errors);
+ printf("rx_collisions :%-8d", priv->stats.rx_collisions);
+ printf("rx_short_frames :%-8d", priv->stats.rx_short_frames);
+ printf("rx_too_long_frames :%-8d", priv->stats.rx_too_long_frames);
+ printf("rx_symbol_errors :%-8d", priv->stats.rx_symbol_errors);
+ printf("interrupts :%-8d", priv->stats.interrupts);
+ printf("rx_count :%-8d", priv->stats.rx_count);
+ printf("rx_deliver :%-8d", priv->stats.rx_deliver);
+ printf("rx_resource :%-8d", priv->stats.rx_resource);
+ printf("rx_restart :%-8d", priv->stats.rx_restart);
+ printf("tx_count :%-8d", priv->stats.tx_count);
+ printf("tx_complete :%-8d", priv->stats.tx_complete);
+ printf("tx_dropped :%-8d", priv->stats.tx_dropped);
+}
+
+/*
+ * Driver ioctl handler
+ */
+static int smc91111_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct lan91cxx_priv_data *cpd = ifp->if_softc;
+ int error = 0;
+ DEBUG_FUNCTION();
+
+ switch (command) {
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ db_printf("SIOCSIFADDR\n");
+ ether_ioctl(ifp, command, data);
+ break;
+
+ case SIOCSIFFLAGS:
+ db_printf("SIOCSIFFLAGS\n");
+ switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+ case IFF_RUNNING:
+ smc91111_stop(cpd);
+ break;
+
+ case IFF_UP:
+ smc91111_init(cpd);
+ break;
+
+ case IFF_UP | IFF_RUNNING:
+ smc91111_stop(cpd);
+ smc91111_init(cpd);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case SIO_RTEMS_SHOW_STATS:
+ db_printf("SIO_RTEMS_SHOW_STATS\n");
+ smc91111_stats(cpd);
+ break;
+
+ /*
+ * FIXME: All sorts of multicast commands need to be added here!
+ */
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+/*
+ * Attach an SMC91111 driver to the system
+ */
+int _rtems_smc91111_driver_attach (struct rtems_bsdnet_ifconfig *config,
+ struct scmv91111_configuration * chip)
+{
+ struct ifnet *ifp;
+ struct lan91cxx_priv_data *cpd;
+ int unitNumber;
+ char *unitName;
+ int mtu;
+ DEBUG_FUNCTION();
+
+/* /\* activate io area *\/ */
+/* switch (sparc_leon23_get_psr_version()) { */
+/* case 0: */
+/* case 2: */
+/* db_printf("Activating Leon2 io port\n"); */
+/* /\*configure pio *\/ */
+/* *((volatile unsigned int *)0x80000000) |= 0x10f80000; */
+/* *((volatile unsigned int *)0x800000A8) |= */
+/* (0xe0 | chip->vector) << (8 * (chip->pio - 4)); */
+/* break; */
+/* default: */
+/* { */
+/* unsigned long irq_pio, irq_mctrl, addr_pio, addr_mctrl; */
+/* if ((addr_pio = */
+/* amba_find_apbslv_addr(VENDOR_GAISLER, */
+/* GAISLER_PIOPORT, &irq_pio)) */
+/* && (addr_mctrl = */
+/* amba_find_apbslv_addr(VENDOR_ESA, */
+/* ESA_MCTRL, &irq_mctrl))) { */
+/* LEON3_IOPORT_Regs_Map *io = */
+/* (LEON3_IOPORT_Regs_Map *) addr_pio; */
+/* db_printf */
+/* ("Activating Leon3 io port for smsc_lan91cxx (pio:%x mctrl:%x)\n", */
+/* (unsigned int)addr_pio, */
+/* (unsigned int)addr_mctrl); */
+/* *((volatile unsigned int *)addr_mctrl) |= 0x10f80000; /\*mctrl ctrl 1 *\/ */
+/* io->irqmask |= (1 << chip->pio); */
+/* io->irqpol |= (1 << chip->pio); */
+/* io->irqedge |= (1 << chip->pio); */
+/* io->iodir &= ~(1 << chip->pio); */
+/* } else { */
+/* return 0; */
+/* } */
+/* } */
+/* } */
+
+ /* parse driver name */
+ if ((unitNumber =
+ rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) {
+ db_printf("Unitnumber < 0: %d\n", unitNumber);
+ return 0;
+ }
+
+ db_printf("Unitnumber: %d, baseaddr: 0x%p\n", unitNumber, chip->baseaddr);
+
+ cpd = &smc91111;
+ ifp = &cpd->arpcom.ac_if;
+ memset(cpd, 0, sizeof(*cpd));
+
+ cpd->config = *chip;
+ cpd->base = chip->baseaddr;
+
+ if (smc_probe(cpd)) {
+ return 0;
+ }
+
+ if (config->hardware_address) {
+ memcpy(cpd->arpcom.ac_enaddr, config->hardware_address,
+ ETHER_ADDR_LEN);
+ } else {
+ /* dummy default address */
+ cpd->arpcom.ac_enaddr[0] = 0x12;
+ cpd->arpcom.ac_enaddr[1] = 0x13;
+ cpd->arpcom.ac_enaddr[2] = 0x14;
+ cpd->arpcom.ac_enaddr[3] = 0x15;
+ cpd->arpcom.ac_enaddr[4] = 0x16;
+ cpd->arpcom.ac_enaddr[5] = 0x17;
+ }
+
+ cpd->enaddr[0] = cpd->arpcom.ac_enaddr[0];
+ cpd->enaddr[1] = cpd->arpcom.ac_enaddr[1];
+ cpd->enaddr[2] = cpd->arpcom.ac_enaddr[2];
+ cpd->enaddr[3] = cpd->arpcom.ac_enaddr[3];
+ cpd->enaddr[4] = cpd->arpcom.ac_enaddr[4];
+ cpd->enaddr[5] = cpd->arpcom.ac_enaddr[5];
+ cpd->rpc_cur_mode =
+ LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
+ LAN91CXX_RPCR_ANEG;
+
+ if (config->mtu)
+ mtu = config->mtu;
+ else
+ mtu = ETHERMTU;
+
+ /*
+ * Set up network interface values
+ */
+ ifp->if_softc = cpd;
+ ifp->if_unit = unitNumber;
+ ifp->if_name = unitName;
+ ifp->if_mtu = mtu;
+ ifp->if_init = smc91111_init;
+ ifp->if_ioctl = smc91111_ioctl;
+ ifp->if_start = smc91111_start;
+ ifp->if_output = ether_output;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
+ if (ifp->if_snd.ifq_maxlen == 0)
+ ifp->if_snd.ifq_maxlen = ifqmaxlen;
+
+ /*
+ * Attach the interface
+ */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+#ifdef DEBUG
+ printf("SMC91111 : driver has been attached\n");
+#endif
+
+ return 1;
+};
+
+/* \ ------------- Initialization ------------- \ */
+
+/*
+ * Initialize and start the device
+ */
+static void smc91111_init(void *arg)
+{
+ struct lan91cxx_priv_data *cpd = arg;
+ struct ifnet *ifp = &cpd->arpcom.ac_if;
+ DEBUG_FUNCTION();
+
+ if (cpd->txDaemonTid == 0) {
+
+ lan91cxx_hardware_init(cpd);
+ lan91cxx_start(ifp);
+
+ cpd->rxDaemonTid = rtems_bsdnet_newproc("DCrx", 4096,
+ smc91111_rxDaemon, cpd);
+ cpd->txDaemonTid =
+ rtems_bsdnet_newproc("DCtx", 4096, smc91111_txDaemon, cpd);
+ }
+
+ /*
+ * Tell the world that we're running.
+ */
+ ifp->if_flags |= IFF_RUNNING;
+}
+
+/*
+ * Stop the device
+ */
+static void smc91111_stop(struct lan91cxx_priv_data *cpd)
+{
+ struct ifnet *ifp = &cpd->arpcom.ac_if;
+ DEBUG_FUNCTION();
+
+ ifp->if_flags &= ~IFF_RUNNING;
+
+ /* Reset chip */
+ put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
+ put_reg(cpd, LAN91CXX_RCR, 0);
+ cpd->txbusy = cpd->within_send = 0;
+
+}
+
+int lan91cxx_hardware_init(struct lan91cxx_priv_data *cpd)
+{
+ unsigned short val;
+ int i;
+
+ DEBUG_FUNCTION();
+
+ cpd->txbusy = cpd->within_send = 0;
+
+ /* install interrupt vector */
+ db_printf("Install lan91cxx irqvector at %d\n", cpd->config.vector);
+ set_vector(lan91cxx_interrupt_handler, cpd->config.vector, 1);
+
+ /* Reset chip */
+ put_reg(cpd, LAN91CXX_RCR, LAN91CXX_RCR_SOFT_RST);
+ put_reg(cpd, LAN91CXX_RCR, 0);
+ HAL_DELAY_US(100000);
+ put_reg(cpd, LAN91CXX_CONFIG, 0x9000);
+ put_reg(cpd, LAN91CXX_RCR, 0);
+ put_reg(cpd, LAN91CXX_TCR, 0);
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
+
+ val = get_reg(cpd, LAN91CXX_EPH_STATUS);
+ /* probe chip by reading the signature in BS register */
+ val = get_banksel(cpd);
+ db9_printf("LAN91CXX - supposed BankReg @ %x = %04x\n",
+ (unsigned int)(cpd->base + LAN91CXX_BS), val);
+
+ if ((0xff00 & val) != 0x3300) {
+ printf("No 91Cxx signature");
+ printf("smsc_lan91cxx_init: No 91Cxx signature found\n");
+ return 0;
+ }
+
+ val = get_reg(cpd, LAN91CXX_REVISION);
+
+ db9_printf("LAN91CXX - type: %01x, rev: %01x\n",
+ (val >> 4) & 0xf, val & 0xf);
+
+ /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
+ cpd->c111_reva = (val == 0x3390);
+
+ /* The controller may provide a function used to set up the ESA */
+ if (cpd->config_enaddr)
+ (*cpd->config_enaddr) (cpd);
+
+ db9_printf("LAN91CXX - status: %04x\n", val);
+ /* Use statically configured ESA from the private data */
+ db9_printf
+ ("LAN91CXX - static ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ cpd->enaddr[0], cpd->enaddr[1], cpd->enaddr[2],
+ cpd->enaddr[3], cpd->enaddr[4], cpd->enaddr[5]);
+ /* Set up hardware address */
+ for (i = 0; i < sizeof(cpd->enaddr); i += 2)
+ put_reg(cpd, LAN91CXX_IA01 + i / 2,
+ cpd->enaddr[i] | (cpd->enaddr[i + 1] << 8));
+
+ return 1;
+}
+
+/*
+ This function is called to "start up" the interface. It may be called
+ multiple times, even when the hardware is already running. It will be
+ called whenever something "hardware oriented" changes and should leave
+ the hardware ready to send/receive packets.
+*/
+static void lan91cxx_start(struct ifnet *ifp)
+{
+ struct lan91cxx_priv_data *cpd = ifp->if_softc;
+
+ cyg_uint16 intr;
+ cyg_uint16 phy_ctl;
+ int delay;
+ DEBUG_FUNCTION();
+
+ HAL_DELAY_US(100000);
+
+ /* 91C111 Errata. Internal PHY comes up disabled. Must enable here. */
+ phy_ctl = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CTRL);
+ phy_ctl &= ~LAN91CXX_PHY_CTRL_MII_DIS;
+ lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, phy_ctl);
+
+ /* Start auto-negotiation */
+ put_reg(cpd, LAN91CXX_RPCR,
+ LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
+ LAN91CXX_RPCR_ANEG);
+ cpd->rpc_cur_mode =
+ LAN91CXX_RPCR_LEDA_RX | LAN91CXX_RPCR_LEDB_LINK |
+ LAN91CXX_RPCR_ANEG;
+
+ /* wait for auto-negotiation to finish. */
+ /* give it ~5 seconds before giving up (no cable?) */
+ delay = 50;
+ while (!(lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT) & 0x20)) {
+ if (--delay <= 0) {
+ printf("Timeout autonegotiation\n");
+ break;
+ }
+ HAL_DELAY_US(100000);
+ }
+
+ put_reg(cpd, LAN91CXX_MMU_COMMAND, LAN91CXX_MMU_reset_mmu);
+
+ put_reg(cpd, LAN91CXX_INTERRUPT, 0); /* disable interrupts */
+ intr = get_reg(cpd, LAN91CXX_INTERRUPT);
+ put_reg(cpd, LAN91CXX_INTERRUPT, intr & /* ack old interrupts */
+ (LAN91CXX_INTERRUPT_TX_INT |
+ LAN91CXX_INTERRUPT_TX_EMPTY_INT |
+ LAN91CXX_INTERRUPT_RX_OVRN_INT | LAN91CXX_INTERRUPT_ERCV_INT));
+ put_reg(cpd, LAN91CXX_RCR,
+ LAN91CXX_RCR_STRIP_CRC | LAN91CXX_RCR_RXEN |
+ LAN91CXX_RCR_ALMUL);
+ put_reg(cpd, LAN91CXX_TCR, LAN91CXX_TCR_TXENA | LAN91CXX_TCR_PAD_EN);
+ put_reg(cpd, LAN91CXX_CONTROL, LAN91CXX_CONTROL_AUTO_RELEASE); /* */
+ put_reg(cpd, LAN91CXX_INTERRUPT, /* enable interrupts */
+ LAN91CXX_INTERRUPT_RCV_INT_M);
+
+ if ((0
+#ifdef ETH_DRV_FLAGS_PROMISC_MODE
+ != (flags & ETH_DRV_FLAGS_PROMISC_MODE)
+#endif
+ ) || (ifp->if_flags & IFF_PROMISC)
+ ) {
+ /* Then we select promiscuous mode. */
+ unsigned short rcr;
+ rcr = get_reg(cpd, LAN91CXX_RCR);
+ rcr |= LAN91CXX_RCR_PRMS;
+ put_reg(cpd, LAN91CXX_RCR, rcr);
+ }
+}
+
+/* \ ------------- Probe ------------- \ */
+
+static const char *chip_ids[15] = {
+ NULL, NULL, NULL,
+ /* 3 */ "SMC91C90/91C92",
+ /* 4 */ "SMC91C94",
+ /* 5 */ "SMC91C95",
+ /* 6 */ "SMC91C96",
+ /* 7 */ "SMC91C100",
+ /* 8 */ "SMC91C100FD",
+ /* 9 */ "SMC91C11xFD",
+ NULL, NULL,
+ NULL, NULL, NULL
+};
+
+static int smc_probe(struct lan91cxx_priv_data *cpd)
+{
+ unsigned short bank;
+ unsigned short revision_register;
+
+ DEBUG_FUNCTION();
+
+ /* First, see if the high byte is 0x33 */
+ HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
+ bank = CYG_LE16_TO_CPU(bank);
+ if ((bank & 0xFF00) != 0x3300) {
+ db_printf("<1>Smc probe bank check 1 failed.\n");
+ return -ENODEV;
+ }
+ /* The above MIGHT indicate a device, but I need to write to further
+ test this. */
+ HAL_WRITE_UINT16(cpd->base + (LAN91CXX_BS), CYG_CPU_TO_LE16(0 >> 3));
+ HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank);
+ bank = CYG_LE16_TO_CPU(bank);
+ if ((bank & 0xFF00) != 0x3300) {
+ db_printf("<1>Smc probe bank check 2 failed.\n");
+ return -ENODEV;
+ }
+#if SMC_DEBUG > 3
+ {
+ unsigned short bank16, bank16_0, bank16_1;
+ HAL_READ_UINT16(cpd->base + (LAN91CXX_BS), bank16);
+ bank = CYG_LE16_TO_CPU(bank);
+ HAL_READ_UINT8(cpd->base + (LAN91CXX_BS), bank16_0);
+ HAL_READ_UINT8(cpd->base + (LAN91CXX_BS + 1), bank16_1);
+
+ db_printf
+ ("smc_probe:Bank read as a 16 bit value:0x%04x\n", bank16);
+ db_printf
+ ("smc_probe:Bank read as an 8 bit value:0x%02x\n",
+ bank16_0);
+ db_printf
+ ("smc_probe:Bank + 1 read as an 8 bit value:0x%02x\n",
+ bank16_1);
+ }
+#endif
+
+ /* check if the revision register is something that I recognize.
+ These might need to be added to later, as future revisions
+ could be added. */
+ revision_register = get_reg(cpd, LAN91CXX_REVISION);
+ if (!chip_ids[(revision_register >> 4) & 0xF]) {
+ /* I don't recognize this chip, so... */
+ db_printf
+ ("smc_probe: IO %x: Unrecognized revision register:"
+ " %x, Contact author. \n", (unsigned int)cpd->base,
+ revision_register);
+
+ return -ENODEV;
+ }
+ db_printf("LAN91CXX(0x%x) - type: %s, rev: %01x\n",
+ revision_register,
+ chip_ids[(revision_register >> 4) & 0xF],
+ revision_register & 0xf);
+
+ /* Set RevA flag for LAN91C111 so we can cope with the odd-bit bug. */
+ if (revision_register == 0x3390) {
+ db_printf("!Revision A\n");
+ }
+
+ return 0;
+}
+
+#if 0
+/* \ ------------- PHY read/write ------------- \ */
+/*Sets the PHY to a configuration as determined by the user*/
+static int lan91cxx_phy_fixed(struct lan91cxx_priv_data *cpd)
+{
+ int my_fixed_caps;
+ int cfg1;
+
+ DEBUG_FUNCTION();
+ db4_printf("lan91cxx_phy_fixed: full duplex: %d, speed: %d\n",
+ cpd->config.ctl_rfduplx, cpd->config.ctl_rspeed);
+
+ /* Enter Link Disable state */
+ cfg1 = lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_CONFIG1);
+ cfg1 |= PHY_CFG1_LNKDIS;
+ lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CONFIG1, cfg1);
+
+ /* Set our fixed capabilities, Disable auto-negotiation */
+ my_fixed_caps = 0;
+
+ if (cpd->config.ctl_rfduplx)
+ my_fixed_caps |= LAN91CXX_PHY_CTRL_DPLX;
+
+ if (cpd->config.ctl_rspeed == 100)
+ my_fixed_caps |= LAN91CXX_PHY_CTRL_SPEED;
+
+ /* Write capabilities to the phy control register */
+ lan91cxx_write_phy(cpd, 0, LAN91CXX_PHY_CTRL, my_fixed_caps);
+
+ /* Re-Configure the Receive/Phy Control register */
+ put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
+
+ return (1);
+}
+#endif
+
+#if 0
+/*Configures the specified PHY using Autonegotiation. */
+static void lan91cxx_phy_configure(struct lan91cxx_priv_data *cpd)
+{
+
+ unsigned int phyaddr;
+ unsigned int my_phy_caps; /* My PHY capabilities */
+ unsigned int my_ad_caps; /* My Advertised capabilities */
+ unsigned int status = 0;
+ int failed = 0, delay;
+
+ DEBUG_FUNCTION();
+
+ /* Set the blocking flag */
+ cpd->autoneg_active = 1;
+
+ /* Get the detected phy address */
+ phyaddr = cpd->phyaddr;
+
+ /* Reset the PHY, setting all other bits to zero */
+ lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG, PHY_CNTL_RST);
+
+ /* Wait for the reset to complete, or time out */
+ delay = 50;
+ while (delay--) {
+ if (!(lan91cxx_read_phy(cpd, 0, PHY_CNTL_REG)
+ & PHY_CNTL_RST)) {
+ break;
+ }
+ HAL_DELAY_US(100000);
+ }
+
+ if (delay < 1) {
+ db_printf("smc91111:!PHY reset timed out\n");
+ goto smc_phy_configure_exit;
+ }
+
+ /* Read PHY Register 18, Status Output */
+ cpd->lastPhy18 = lan91cxx_read_phy(cpd, 0, PHY_INT_REG);
+
+ /* Enable PHY Interrupts (for register 18) */
+ /* Interrupts listed here are disabled */
+ lan91cxx_write_phy(cpd, 0, PHY_MASK_REG,
+ PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD
+ | PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+ PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+ /* Configure the Receive/Phy Control register */
+ put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
+
+ /* Copy our capabilities from PHY_STAT_REG to PHY_AD_REG */
+ my_phy_caps = lan91cxx_read_phy(cpd, phyaddr, PHY_STAT_REG);
+ my_ad_caps = PHY_AD_CSMA; /* I am CSMA capable */
+
+ if (my_phy_caps & PHY_STAT_CAP_T4)
+ my_ad_caps |= PHY_AD_T4;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXF)
+ my_ad_caps |= PHY_AD_TX_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TXH)
+ my_ad_caps |= PHY_AD_TX_HDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TF)
+ my_ad_caps |= PHY_AD_10_FDX;
+
+ if (my_phy_caps & PHY_STAT_CAP_TH)
+ my_ad_caps |= PHY_AD_10_HDX;
+
+ /* Disable capabilities not selected by our user */
+ if (cpd->config.ctl_rspeed != 100) {
+ my_ad_caps &= ~(PHY_AD_T4 | PHY_AD_TX_FDX | PHY_AD_TX_HDX);
+ }
+
+ if (!cpd->config.ctl_rfduplx) {
+ my_ad_caps &= ~(PHY_AD_TX_FDX | PHY_AD_10_FDX);
+ }
+
+ /* Update our Auto-Neg Advertisement Register */
+ lan91cxx_write_phy(cpd, 0, PHY_AD_REG, my_ad_caps);
+
+ db4_printf("smc91111:phy caps=%x\n", my_phy_caps);
+ db4_printf("smc91111:phy advertised caps=%x\n", my_ad_caps);
+
+ /* If the user requested no auto neg, then go set his request */
+ if (!(cpd->config.ctl_autoneg)) {
+ lan91cxx_phy_fixed(cpd);
+
+ goto smc_phy_configure_exit;
+ }
+
+ /* Restart auto-negotiation process in order to advertise my caps */
+ lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST);
+
+ /* wait for auto-negotiation to finish. */
+ /* give it ~5 seconds before giving up (no cable?) */
+ delay = 50;
+ while (!
+ ((status =
+ lan91cxx_read_phy(cpd, 0, LAN91CXX_PHY_STAT)) & 0x20)) {
+ if (--delay <= 0) {
+ printf("Timeout autonegotiation\n");
+ failed = 1;
+ break;
+ }
+
+ /* Restart auto-negotiation if remote fault */
+ if (status & PHY_STAT_REM_FLT) {
+ db_printf("smc91111:PHY remote fault detected\n");
+
+ /* Restart auto-negotiation */
+ db_printf("smc91111:PHY restarting auto-negotiation\n");
+ lan91cxx_write_phy(cpd, 0, PHY_CNTL_REG,
+ PHY_CNTL_ANEG_EN |
+ PHY_CNTL_ANEG_RST |
+ PHY_CNTL_SPEED | PHY_CNTL_DPLX);
+ }
+ HAL_DELAY_US(100000);
+ }
+
+ /* Fail if we detected an auto-negotiate remote fault */
+ if (status & PHY_STAT_REM_FLT) {
+ db_printf("smc91111:PHY remote fault detected\n");
+ failed = 1;
+ }
+
+ /* The smc_phy_interrupt() routine will be called to update lastPhy18 */
+
+ /* Set our sysctl parameters to match auto-negotiation results */
+ if (cpd->lastPhy18 & PHY_INT_SPDDET) {
+ db_printf("smc91111:PHY 100BaseT\n");
+ cpd->rpc_cur_mode |= LAN91CXX_RPCR_SPEED;
+ } else {
+ db_printf("smc91111:PHY 10BaseT\n");
+ cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_SPEED;
+ }
+
+ if (cpd->lastPhy18 & PHY_INT_DPLXDET) {
+ db_printf("smc91111:PHY Full Duplex\n");
+ cpd->rpc_cur_mode |= LAN91CXX_RPCR_DPLX;
+ } else {
+ db_printf("smc91111:PHY Half Duplex\n");
+ cpd->rpc_cur_mode &= ~LAN91CXX_RPCR_DPLX;
+ }
+
+ /* Re-Configure the Receive/Phy Control register */
+ put_reg(cpd, LAN91CXX_RPCR, cpd->rpc_cur_mode);
+
+ smc_phy_configure_exit:
+
+ /* Exit auto-negotiation */
+ cpd->autoneg_active = 0;
+}
+#endif
+
+static cyg_uint16
+lan91cxx_read_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,
+ cyg_uint8 phyreg)
+{
+ int i, mask, input_idx, clk_idx = 0;
+ cyg_uint16 mii_reg, value;
+ cyg_uint8 bits[64];
+
+ /* 32 consecutive ones on MDO to establish sync */
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+
+ /* Start code <01> */
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+
+ /* Read command <10> */
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+
+ /* Output the PHY address, msb first */
+ for (mask = 0x10; mask; mask >>= 1) {
+ if (phyaddr & mask)
+ bits[clk_idx++] =
+ LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ else
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ }
+
+ /* Output the phy register number, msb first */
+ for (mask = 0x10; mask; mask >>= 1) {
+ if (phyreg & mask)
+ bits[clk_idx++] =
+ LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ else
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ }
+
+ /* Tristate and turnaround (1 bit times) */
+ bits[clk_idx++] = 0;
+
+ /* Input starts at this bit time */
+ input_idx = clk_idx;
+
+ /* Will input 16 bits */
+ for (i = 0; i < 16; ++i)
+ bits[clk_idx++] = 0;
+
+ /* Final clock bit */
+ bits[clk_idx++] = 0;
+
+ /* Get the current MII register value */
+ mii_reg = get_reg(cpd, LAN91CXX_MGMT);
+
+ /* Turn off all MII Interface bits */
+ mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
+ LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
+ HAL_DELAY_US(50);
+
+ /* Clock all 64 cycles */
+ for (i = 0; i < sizeof(bits); ++i) {
+ /* Clock Low - output data */
+ put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
+ HAL_DELAY_US(50);
+
+ /* Clock Hi - input data */
+ put_reg(cpd, LAN91CXX_MGMT,
+ mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
+ HAL_DELAY_US(50);
+
+ bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;
+ }
+
+ /* Return to idle state */
+ put_reg(cpd, LAN91CXX_MGMT, mii_reg);
+ HAL_DELAY_US(50);
+
+ /* Recover input data */
+ for (value = 0, i = 0; i < 16; ++i) {
+ value <<= 1;
+ if (bits[input_idx++] & LAN91CXX_MGMT_MDI)
+ value |= 1;
+ }
+
+ db16_printf("phy_read : %d : %04x\n", phyreg, value);
+ return value;
+}
+
+static void
+lan91cxx_write_phy(struct lan91cxx_priv_data *cpd, cyg_uint8 phyaddr,
+ cyg_uint8 phyreg, cyg_uint16 value)
+{
+ int i, mask, clk_idx = 0;
+ cyg_uint16 mii_reg;
+ cyg_uint8 bits[65];
+
+ /* 32 consecutive ones on MDO to establish sync */
+ for (i = 0; i < 32; ++i)
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+
+ /* Start code <01> */
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+
+ /* Write command <01> */
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+
+ /* Output the PHY address, msb first */
+ for (mask = 0x10; mask; mask >>= 1) {
+ if (phyaddr & mask)
+ bits[clk_idx++] =
+ LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ else
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ }
+
+ /* Output the phy register number, msb first */
+ for (mask = 0x10; mask; mask >>= 1) {
+ if (phyreg & mask)
+ bits[clk_idx++] =
+ LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ else
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ }
+
+ /* Tristate and turnaround (2 bit times) */
+ bits[clk_idx++] = 0;
+ bits[clk_idx++] = 0;
+
+ /* Write out 16 bits of data, msb first */
+ for (mask = 0x8000; mask; mask >>= 1) {
+ if (value & mask)
+ bits[clk_idx++] =
+ LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MDO;
+ else
+ bits[clk_idx++] = LAN91CXX_MGMT_MDOE;
+ }
+
+ /* Final clock bit (tristate) */
+ bits[clk_idx++] = 0;
+
+ /* Get the current MII register value */
+ mii_reg = get_reg(cpd, LAN91CXX_MGMT);
+
+ /* Turn off all MII Interface bits */
+ mii_reg &= ~(LAN91CXX_MGMT_MDOE | LAN91CXX_MGMT_MCLK |
+ LAN91CXX_MGMT_MDI | LAN91CXX_MGMT_MDO);
+ HAL_DELAY_US(50);
+
+ /* Clock all cycles */
+ for (i = 0; i < sizeof(bits); ++i) {
+ /* Clock Low - output data */
+ put_reg(cpd, LAN91CXX_MGMT, mii_reg | bits[i]);
+ HAL_DELAY_US(50);
+
+ /* Clock Hi - input data */
+ put_reg(cpd, LAN91CXX_MGMT,
+ mii_reg | bits[i] | LAN91CXX_MGMT_MCLK);
+ HAL_DELAY_US(50);
+
+/* bits[i] |= get_reg(cpd, LAN91CXX_MGMT) & LAN91CXX_MGMT_MDI;*/
+ }
+
+ /* Return to idle state */
+ put_reg(cpd, LAN91CXX_MGMT, mii_reg);
+ HAL_DELAY_US(50);
+
+ db16_printf("phy_write: %d : %04x\n", phyreg, value);
+}
+
+#endif
diff --git a/c/src/libchip/network/smc91111.h b/c/src/libchip/network/smc91111.h
new file mode 100644
index 0000000000..0201acd3d6
--- /dev/null
+++ b/c/src/libchip/network/smc91111.h
@@ -0,0 +1,552 @@
+/*
+ * $Id$
+ */
+
+#ifndef _SMC91111_H_
+#define _SMC91111_H_
+
+#include <libchip/smc91111exp.h>
+
+
+#define LAN91CXX_TCR 0x00
+#define LAN91CXX_EPH_STATUS 0x01
+#define LAN91CXX_RCR 0x02
+#define LAN91CXX_COUNTER 0x03
+#define LAN91CXX_MIR 0x04
+#define LAN91CXX_MCR 0x05 /* Other than 91C111*/
+#define LAN91CXX_RPCR 0x05 /* 91C111 only*/
+#define LAN91CXX_RESERVED_0 0x06
+#define LAN91CXX_BS 0x07
+#define LAN91CXX_CONFIG 0x08
+#define LAN91CXX_BASE_REG 0x09
+#define LAN91CXX_IA01 0x0a
+#define LAN91CXX_IA23 0x0b
+#define LAN91CXX_IA45 0x0c
+#define LAN91CXX_GENERAL 0x0d /* 91C96 - was "RESERVED_1" for others*/
+#define LAN91CXX_CONTROL 0x0e
+#define LAN91CXX_BS2 0x0f
+#define LAN91CXX_MMU_COMMAND 0x10
+#define LAN91CXX_PNR 0x11
+#define LAN91CXX_FIFO_PORTS 0x12
+#define LAN91CXX_POINTER 0x13
+#define LAN91CXX_DATA_HIGH 0x14
+#define LAN91CXX_DATA 0x15
+#define LAN91CXX_INTERRUPT 0x16
+#define LAN91CXX_BS3 0x17
+#define LAN91CXX_MT01 0x18
+#define LAN91CXX_MT23 0x19
+#define LAN91CXX_MT45 0x1a
+#define LAN91CXX_MT67 0x1b
+#define LAN91CXX_MGMT 0x1c
+#define LAN91CXX_REVISION 0x1d
+#define LAN91CXX_ERCV 0x1e
+#define LAN91CXX_BS4 0x1f
+
+#define LAN91CXX_RCR_SOFT_RST 0x8000 /* soft reset*/
+#define LAN91CXX_RCR_FILT_CAR 0x4000 /* filter carrier*/
+#define LAN91CXX_RCR_ABORT_ENB 0x2000 /* abort on collision*/
+#define LAN91CXX_RCR_STRIP_CRC 0x0200 /* strip CRC*/
+#define LAN91CXX_RCR_RXEN 0x0100 /* enable RX*/
+#define LAN91CXX_RCR_ALMUL 0x0004 /* receive all muticasts*/
+#define LAN91CXX_RCR_PRMS 0x0002 /* promiscuous*/
+#define LAN91CXX_RCR_RX_ABORT 0x0001 /* set when abort due to long frame*/
+
+#define LAN91CXX_TCR_SWFDUP 0x8000 /* Switched Full Duplex mode*/
+#define LAN91CXX_TCR_ETEN_TYPE 0x4000 /* ETEN type (91C96) 0 <=> like a 91C94*/
+#define LAN91CXX_TCR_EPH_LOOP 0x2000 /* loopback mode*/
+#define LAN91CXX_TCR_STP_SQET 0x1000 /* Stop transmission on SQET error*/
+#define LAN91CXX_TCR_FDUPLX 0x0800 /* full duplex*/
+#define LAN91CXX_TCR_MON_CSN 0x0400 /* monitor carrier during tx (91C96)*/
+#define LAN91CXX_TCR_NOCRC 0x0100 /* does not append CRC to frames*/
+#define LAN91CXX_TCR_PAD_EN 0x0080 /* pads frames with 00 to min length*/
+#define LAN91CXX_TCR_FORCOL 0x0004 /* force collision*/
+#define LAN91CXX_TCR_LLOOP 0x0002 /* local loopback (91C96)*/
+#define LAN91CXX_TCR_TXENA 0x0001 /* enable*/
+
+#define LAN91CXX_POINTER_RCV 0x8000
+#define LAN91CXX_POINTER_AUTO_INCR 0x4000
+#define LAN91CXX_POINTER_READ 0x2000
+#define LAN91CXX_POINTER_ETEN 0x1000
+#define LAN91CXX_POINTER_NOT_EMPTY 0x0800
+
+
+#define LAN91CXX_INTERRUPT_TX_IDLE_M 0x8000 /* (91C96)*/
+#define LAN91CXX_INTERRUPT_ERCV_INT_M 0x4000
+#define LAN91CXX_INTERRUPT_EPH_INT_M 0x2000
+#define LAN91CXX_INTERRUPT_RX_OVRN_INT_M 0x1000
+#define LAN91CXX_INTERRUPT_ALLOC_INT_M 0x0800
+#define LAN91CXX_INTERRUPT_TX_EMPTY_INT_M 0x0400
+#define LAN91CXX_INTERRUPT_TX_INT_M 0x0200
+#define LAN91CXX_INTERRUPT_RCV_INT_M 0x0100
+#define LAN91CXX_INTERRUPT_TX_IDLE 0x0080 /* (91C96)*/
+#define LAN91CXX_INTERRUPT_ERCV_INT 0x0040 /* also ack*/
+#define LAN91CXX_INTERRUPT_EPH_INT 0x0020
+#define LAN91CXX_INTERRUPT_RX_OVRN_INT 0x0010 /* also ack*/
+#define LAN91CXX_INTERRUPT_ALLOC_INT 0x0008
+#define LAN91CXX_INTERRUPT_TX_EMPTY_INT 0x0004 /* also ack*/
+#define LAN91CXX_INTERRUPT_TX_INT 0x0002 /* also ack*/
+#define LAN91CXX_INTERRUPT_RCV_INT 0x0001
+
+#define LAN91CXX_INTERRUPT_TX_SET 0x0006 /* TX_EMPTY + TX*/
+#define LAN91CXX_INTERRUPT_TX_SET_ACK 0x0004 /* TX_EMPTY and not plain TX*/
+#define LAN91CXX_INTERRUPT_TX_FIFO_ACK 0x0002 /* TX alone*/
+#define LAN91CXX_INTERRUPT_TX_SET_M 0x0600 /* TX_EMPTY + TX*/
+
+#define LAN91CXX_CONTROL_RCV_BAD 0x4000
+#define LAN91CXX_CONTROL_AUTO_RELEASE 0x0800
+#define LAN91CXX_CONTROL_LE_ENABLE 0x0080
+#define LAN91CXX_CONTROL_CR_ENABLE 0x0040
+#define LAN91CXX_CONTROL_TE_ENABLE 0x0020
+
+/* These are for setting the MAC address in the 91C96 serial EEPROM*/
+#define LAN91CXX_CONTROL_EEPROM_SELECT 0x0004
+#define LAN91CXX_CONTROL_RELOAD 0x0002
+#define LAN91CXX_CONTROL_STORE 0x0001
+#define LAN91CXX_CONTROL_EEPROM_BUSY 0x0003
+#define LAN91CXX_ESA_EEPROM_OFFSET 0x0020
+
+#define LAN91CXX_STATUS_TX_UNRN 0x8000
+#define LAN91CXX_STATUS_LINK_OK 0x4000
+#define LAN91CXX_STATUS_CTR_ROL 0x1000
+#define LAN91CXX_STATUS_EXC_DEF 0x0800
+#define LAN91CXX_STATUS_LOST_CARR 0x0400
+#define LAN91CXX_STATUS_LATCOL 0x0200
+#define LAN91CXX_STATUS_WAKEUP 0x0100
+#define LAN91CXX_STATUS_TX_DEFR 0x0080
+#define LAN91CXX_STATUS_LTX_BRD 0x0040
+#define LAN91CXX_STATUS_SQET 0x0020
+#define LAN91CXX_STATUS_16COL 0x0010
+#define LAN91CXX_STATUS_LTX_MULT 0x0008
+#define LAN91CXX_STATUS_MUL_COL 0x0004
+#define LAN91CXX_STATUS_SNGL_COL 0x0002
+#define LAN91CXX_STATUS_TX_SUC 0x0001
+
+#define LAN91CXX_MMU_COMMAND_BUSY 0x0001
+
+#define LAN91CXX_MMU_noop 0x0000
+#define LAN91CXX_MMU_alloc_for_tx 0x0020
+#define LAN91CXX_MMU_reset_mmu 0x0040
+#define LAN91CXX_MMU_rem_rx_frame 0x0060
+#define LAN91CXX_MMU_rem_tx_frame 0x0070 /* (91C96) only when TX stopped*/
+#define LAN91CXX_MMU_remrel_rx_frame 0x0080
+#define LAN91CXX_MMU_rel_packet 0x00a0
+#define LAN91CXX_MMU_enq_packet 0x00c0
+#define LAN91CXX_MMU_reset_tx_fifo 0x00e0
+
+#define LAN91CXX_CONTROLBYTE_CRC 0x1000
+#define LAN91CXX_CONTROLBYTE_ODD 0x2000
+#define LAN91CXX_CONTROLBYTE_RX 0x4000
+
+#define LAN91CXX_RX_STATUS_ALIGNERR 0x8000
+#define LAN91CXX_RX_STATUS_BCAST 0x4000
+#define LAN91CXX_RX_STATUS_BADCRC 0x2000
+#define LAN91CXX_RX_STATUS_ODDFRM 0x1000
+#define LAN91CXX_RX_STATUS_TOOLONG 0x0800
+#define LAN91CXX_RX_STATUS_TOOSHORT 0x0400
+#define LAN91CXX_RX_STATUS_HASHVALMASK 0x007e /* MASK*/
+#define LAN91CXX_RX_STATUS_MCAST 0x0001
+#define LAN91CXX_RX_STATUS_BAD \
+ (LAN91CXX_RX_STATUS_ALIGNERR | \
+ LAN91CXX_RX_STATUS_BADCRC | \
+ LAN91CXX_RX_STATUS_TOOLONG | \
+ LAN91CXX_RX_STATUS_TOOSHORT)
+
+#define LAN91CXX_RX_STATUS_IS_ODD(__cpd,__stat) ((__stat) & LAN91CXX_RX_STATUS_ODDFRM)
+#define LAN91CXX_CONTROLBYTE_IS_ODD(__cpd,__val) ((__val) & LAN91CXX_CONTROLBYTE_ODD)
+
+/* Attribute memory registers in PCMCIA mode*/
+#define LAN91CXX_ECOR 0x8000
+#define LAN91CXX_ECOR_RESET (1<<7)
+#define LAN91CXX_ECOR_LEVIRQ (1<<6)
+#define LAN91CXX_ECOR_ATTWR (1<<2)
+#define LAN91CXX_ECOR_ENABLE (1<<0)
+
+#define LAN91CXX_ECSR 0x8002
+#define LAN91CXX_ECSR_IOIS8 (1<<5)
+#define LAN91CXX_ECSR_PWRDWN (1<<2)
+#define LAN91CXX_ECSR_INTR (1<<1)
+
+/* These are for manipulating the MII interface*/
+#define LAN91CXX_MGMT_MDO 0x0001
+#define LAN91CXX_MGMT_MDI 0x0002
+#define LAN91CXX_MGMT_MCLK 0x0004
+#define LAN91CXX_MGMT_MDOE 0x0008
+
+/* Internal PHY registers (91c111)*/
+#define LAN91CXX_PHY_CTRL 0
+#define LAN91CXX_PHY_STAT 1
+#define LAN91CXX_PHY_ID1 2
+#define LAN91CXX_PHY_ID2 3
+#define LAN91CXX_PHY_AUTO_AD 4
+#define LAN91CXX_PHY_AUTO_CAP 5
+#define LAN91CXX_PHY_CONFIG1 16
+#define LAN91CXX_PHY_CONFIG2 17
+#define LAN91CXX_PHY_STATUS_OUT 18
+#define LAN91CXX_PHY_MASK 19
+
+/* PHY control bits*/
+#define LAN91CXX_PHY_CTRL_COLTST (1 << 7)
+#define LAN91CXX_PHY_CTRL_DPLX (1 << 8)
+#define LAN91CXX_PHY_CTRL_ANEG_RST (1 << 9)
+#define LAN91CXX_PHY_CTRL_MII_DIS (1 << 10)
+#define LAN91CXX_PHY_CTRL_PDN (1 << 11)
+#define LAN91CXX_PHY_CTRL_ANEG_EN (1 << 12)
+#define LAN91CXX_PHY_CTRL_SPEED (1 << 13)
+#define LAN91CXX_PHY_CTRL_LPBK (1 << 14)
+#define LAN91CXX_PHY_CTRL_RST (1 << 15)
+
+// PHY Configuration Register 1
+#define PHY_CFG1_LNKDIS 0x8000 // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS 0x4000 // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN 0x2000 // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR 0x0400 // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS 0x0200 // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR 0x0100 // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE 0x0080 // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0 0x0040 // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT 2 // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK 0x003C
+#define PHY_CFG1_TRF_MASK 0x0003 // Transmitter Rise/Fall time
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG 0x11
+#define PHY_CFG2_APOLDIS 0x0020 // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS 0x0010 // 1=Jabber disabled
+#define PHY_CFG2_MREG 0x0008 // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO 0x0004 // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG 0x12 // Status Output (Interrupt Status)
+#define PHY_INT_INT 0x8000 // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL 0x4000 // 1=Link Not detected
+#define PHY_INT_LOSSSYNC 0x2000 // 1=Descrambler has lost sync
+#define PHY_INT_CWRD 0x1000 // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD 0x0800 // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD 0x0400 // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL 0x0200 // 1=Reverse Polarity detected
+#define PHY_INT_JAB 0x0100 // 1=Jabber detected
+#define PHY_INT_SPDDET 0x0080 // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET 0x0040 // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG 0x13 // Interrupt Mask
+
+#define LAN91CXX_RPCR_LEDA_LINK (0 << 2)
+#define LAN91CXX_RPCR_LEDA_TXRX (4 << 2)
+#define LAN91CXX_RPCR_LEDA_RX (6 << 2)
+#define LAN91CXX_RPCR_LEDA_TX (7 << 2)
+#define LAN91CXX_RPCR_LEDB_LINK (0 << 5)
+#define LAN91CXX_RPCR_LEDB_TXRX (4 << 5)
+#define LAN91CXX_RPCR_LEDB_RX (6 << 5)
+#define LAN91CXX_RPCR_LEDB_TX (7 << 5)
+#define LAN91CXX_RPCR_ANEG (1 << 11)
+#define LAN91CXX_RPCR_DPLX (1 << 12)
+#define LAN91CXX_RPCR_SPEED (1 << 13)
+
+// PHY Control Register
+#define PHY_CNTL_REG 0x00
+#define PHY_CNTL_RST 0x8000 // 1=PHY Reset
+#define PHY_CNTL_LPBK 0x4000 // 1=PHY Loopback
+#define PHY_CNTL_SPEED 0x2000 // 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN 0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN 0x0800 // 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS 0x0400 // 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST 0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX 0x0100 // 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST 0x0080 // 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG 0x01
+#define PHY_STAT_CAP_T4 0x8000 // 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF 0x4000 // 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH 0x2000 // 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF 0x1000 // 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH 0x0800 // 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR 0x0040 // 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK 0x0020 // 1=ANEG has completed
+#define PHY_STAT_REM_FLT 0x0010 // 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG 0x0008 // 1=Auto negotiate capable
+#define PHY_STAT_LINK 0x0004 // 1=valid link
+#define PHY_STAT_JAB 0x0002 // 1=10Mbps jabber condition
+#define PHY_STAT_EXREG 0x0001 // 1=extended registers implemented
+#define PHY_STAT_RESERVED 0x0780 // Reserved bits mask.
+
+// PHY Identifier Registers
+#define PHY_ID1_REG 0x02 // PHY Identifier 1
+#define PHY_ID2_REG 0x03 // PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG 0x04
+#define PHY_AD_NP 0x8000 // 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK 0x4000 // 1=got link code word from remote
+#define PHY_AD_RF 0x2000 // 1=advertise remote fault
+#define PHY_AD_T4 0x0200 // 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX 0x0100 // 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX 0x0080 // 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX 0x0040 // 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX 0x0020 // 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA 0x0001 // 1=PHY is capable of 802.3 CMSA
+
+
+static int debugflag_out = 0;
+
+#define dbc_printf(lvl,format, args...) do { \
+ if (!debugflag_out) { \
+ if (lvl & DEBUG) { \
+ char buf[1024]; \
+ sprintf(buf,format,##args); \
+ DEBUG_puts(buf); \
+ }} \
+} while(0)
+
+#define db64_printf(format, args...) dbc_printf(64,format,##args);
+#define db16_printf(format, args...) dbc_printf(16,format,##args);
+#define db9_printf(format, args...) dbc_printf(9,format,##args);
+#define db4_printf(format, args...) dbc_printf(4,format,##args);
+#define db2_printf(format, args...) dbc_printf(2,format,##args);
+#define db1_printf(format, args...) dbc_printf(1,format,##args);
+#define db_printf(format, args...) dbc_printf(0xffff,format,##args);
+
+#if DEBUG & 1
+#define DEBUG_FUNCTION() do { db_printf("# %s\n", __FUNCTION__); } while (0)
+#else
+#define DEBUG_FUNCTION() do {} while(0)
+#endif
+
+
+/* ------------------------------------------------------------------------*/
+
+struct smsc_lan91cxx_stats {
+ unsigned int tx_good ;
+ unsigned int tx_max_collisions ;
+ unsigned int tx_late_collisions ;
+ unsigned int tx_underrun ;
+ unsigned int tx_carrier_loss ;
+ unsigned int tx_deferred ;
+ unsigned int tx_sqetesterrors ;
+ unsigned int tx_single_collisions;
+ unsigned int tx_mult_collisions ;
+ unsigned int tx_total_collisions ;
+ unsigned int rx_good ;
+ unsigned int rx_crc_errors ;
+ unsigned int rx_align_errors ;
+ unsigned int rx_resource_errors ;
+ unsigned int rx_overrun_errors ;
+ unsigned int rx_collisions ;
+ unsigned int rx_short_frames ;
+ unsigned int rx_too_long_frames ;
+ unsigned int rx_symbol_errors ;
+ unsigned int interrupts ;
+ unsigned int rx_count ;
+ unsigned int rx_deliver ;
+ unsigned int rx_resource ;
+ unsigned int rx_restart ;
+ unsigned int tx_count ;
+ unsigned int tx_complete ;
+ unsigned int tx_dropped ;
+};
+#define INCR_STAT(c,n) (((c)->stats.n)++)
+
+struct lan91cxx_priv_data;
+
+typedef struct lan91cxx_priv_data {
+
+ /* frontend */
+ struct arpcom arpcom;
+ rtems_id rxDaemonTid;
+ rtems_id txDaemonTid;
+
+ scmv91111_configuration_t config;
+
+ /* backend */
+ int rpc_cur_mode;
+ int autoneg_active;
+ int phyaddr;
+ unsigned int lastPhy18;
+
+ int txbusy; /* A packet has been sent*/
+ unsigned long txkey; /* Used to ack when packet sent*/
+ unsigned short* base; /* Base I/O address of controller*/
+ /* (as it comes out of reset)*/
+ int interrupt; /* Interrupt vector used by controller*/
+ unsigned char enaddr[6]; /* Controller ESA*/
+ /* Function to configure the ESA - may fetch ESA from EPROM or */
+ /* RedBoot config option. Use of the 'config_enaddr()' function*/
+ /* is depreciated in favor of the 'provide_esa()' function and*/
+ /* 'hardwired_esa' boolean*/
+ void (*config_enaddr)(struct lan91cxx_priv_data* cpd);
+ int hardwired_esa;
+ int txpacket;
+ int rxpacket;
+ int within_send;
+ int c111_reva; /* true if this is a revA LAN91C111*/
+ struct smsc_lan91cxx_stats stats;
+} lan91cxx_priv_data;
+
+/* ------------------------------------------------------------------------*/
+
+#ifdef LAN91CXX_32BIT_RX
+typedef unsigned int rxd_t;
+#else
+typedef unsigned short rxd_t;
+#endif
+
+typedef struct _debug_regs_pair {
+ int reg; char *name; struct _debug_regs_pair *bits;
+} debug_regs_pair;
+
+static debug_regs_pair debug_regs[] = {
+ {LAN91CXX_TCR , "LAN91CXX_TCR" ,0},
+ {LAN91CXX_EPH_STATUS , "LAN91CXX_EPH_STATUS",0},
+ {LAN91CXX_RCR , "LAN91CXX_RCR" ,0},
+ {LAN91CXX_COUNTER , "LAN91CXX_COUNTER" ,0},
+ {LAN91CXX_MIR , "LAN91CXX_MIR" ,0},
+ {LAN91CXX_MCR , "LAN91CXX_MCR" ,0},
+ {LAN91CXX_RPCR , "LAN91CXX_RPCR" ,0},
+ {LAN91CXX_RESERVED_0 , "LAN91CXX_RESERVED_0",0},
+ {LAN91CXX_BS , "LAN91CXX_BS" ,0},
+ {LAN91CXX_CONFIG , "LAN91CXX_CONFIG" ,0},
+ {LAN91CXX_BASE_REG , "LAN91CXX_BASE_REG" ,0},
+ {LAN91CXX_IA01 , "LAN91CXX_IA01" ,0},
+ {LAN91CXX_IA23 , "LAN91CXX_IA23" ,0},
+ {LAN91CXX_IA45 , "LAN91CXX_IA45" ,0},
+ {LAN91CXX_GENERAL , "LAN91CXX_GENERAL" ,0},
+ {LAN91CXX_CONTROL , "LAN91CXX_CONTROL" ,0},
+ {LAN91CXX_BS2 , "LAN91CXX_BS2" ,0},
+ {LAN91CXX_MMU_COMMAND, "LAN91CXX_MMU_COMMAND",0},
+ {LAN91CXX_PNR , "LAN91CXX_PNR" ,0},
+ {LAN91CXX_FIFO_PORTS , "LAN91CXX_FIFO_PORTS" ,0},
+ {LAN91CXX_POINTER , "LAN91CXX_POINTER" ,0},
+ {LAN91CXX_DATA_HIGH , "LAN91CXX_DATA_HIGH" ,0},
+ {LAN91CXX_DATA , "LAN91CXX_DATA" ,0},
+ {LAN91CXX_INTERRUPT , "LAN91CXX_INTERRUPT" ,0},
+ {LAN91CXX_BS3 , "LAN91CXX_BS3" ,0},
+ {LAN91CXX_MT01 , "LAN91CXX_MT01" ,0},
+ {LAN91CXX_MT23 , "LAN91CXX_MT23" ,0},
+ {LAN91CXX_MT45 , "LAN91CXX_MT45" ,0},
+ {LAN91CXX_MT67 , "LAN91CXX_MT67" ,0},
+/*{LAN91CXX_MGMT , "LAN91CXX_MGMT" ,0}, */
+ {LAN91CXX_REVISION , "LAN91CXX_REVISION" ,0},
+ {LAN91CXX_ERCV , "LAN91CXX_ERCV" ,0},
+ {LAN91CXX_BS4 , "LAN91CXX_BS4" ,0},
+
+
+
+ {-1,0}
+};
+
+static char *dbg_prefix = "";
+
+#ifndef SMSC_PLATFORM_DEFINED_GET_REG
+static __inline__ unsigned short
+get_reg(struct lan91cxx_priv_data *cpd, int regno)
+{
+ unsigned short val; debug_regs_pair *dbg = debug_regs; int c;
+ uint32_t Irql;
+
+ /*rtems_interrupt_disable(Irql);*/
+
+ HAL_WRITE_UINT16(cpd->base+(LAN91CXX_BS), CYG_CPU_TO_LE16(regno>>3));
+ HAL_READ_UINT16(cpd->base+((regno&0x7)), val);
+ val = CYG_LE16_TO_CPU(val);
+
+ /*rtems_interrupt_enable(Irql);*/
+
+#ifdef DEBUG & 32
+ while ((c = dbg->reg) != -1) {
+ if (c == regno) {
+ db_printf("%sread reg [%d:%x] -> 0x%04x (%-20s)\n", dbg_prefix, regno>>3,(regno&0x7)*2, val, dbg->name);
+ break;
+ }
+ dbg++;
+ }
+#else
+ db2_printf("%sread reg %d:%x -> 0x%04x\n", dbg_prefix, regno>>3,(regno&0x7)*2, val);
+#endif
+
+ return val;
+}
+#endif /* SMSC_PLATFORM_DEFINED_GET_REG*/
+
+#ifndef SMSC_PLATFORM_DEFINED_PUT_REG
+static __inline__ void
+put_reg(struct lan91cxx_priv_data *cpd, int regno, unsigned short val)
+{
+ debug_regs_pair *dbg = debug_regs; int c;
+ uint32_t Irql;
+
+#ifdef DEBUG & 32
+ while ((c = dbg->reg) != -1) {
+ if (c == regno) {
+ db_printf("%swrite reg [%d:%x] <- 0x%04x (%-20s)\n", dbg_prefix, regno>>3, (regno&0x07)*2, val, dbg->name);
+ break;
+ }
+ dbg++;
+ }
+#else
+ db2_printf("%swrite reg %d:%x <- 0x%04x\n", dbg_prefix, regno>>3,(regno&0x7)*2, val);
+#endif
+
+ /*rtems_interrupt_disable(Irql);*/
+
+ HAL_WRITE_UINT16(cpd->base+(LAN91CXX_BS), CYG_CPU_TO_LE16(regno>>3));
+ HAL_WRITE_UINT16(cpd->base+((regno&0x7)), CYG_CPU_TO_LE16(val));
+
+ /*rtems_interrupt_enable(Irql);*/
+
+}
+#endif /* SMSC_PLATFORM_DEFINED_PUT_REG*/
+
+#ifndef SMSC_PLATFORM_DEFINED_PUT_DATA
+/* ------------------------------------------------------------------------*/
+/* Assumes bank2 has been selected*/
+static __inline__ void
+put_data(struct lan91cxx_priv_data *cpd, unsigned short val)
+{
+ db2_printf("%s[wdata] <- 0x%04x\n", dbg_prefix, val);
+
+ HAL_WRITE_UINT16(cpd->base+((LAN91CXX_DATA & 0x7)), val);
+
+}
+#endif /* SMSC_PLATFORM_DEFINED_PUT_DATA*/
+
+#ifndef SMSC_PLATFORM_DEFINED_GET_DATA
+/* Assumes bank2 has been selected*/
+static __inline__ rxd_t
+get_data(struct lan91cxx_priv_data *cpd)
+{
+ rxd_t val;
+
+#ifdef LAN91CXX_32BIT_RX
+ HAL_READ_UINT32(cpd->base+((LAN91CXX_DATA_HIGH & 0x7)), val);
+#else
+ HAL_READ_UINT16(cpd->base+((LAN91CXX_DATA & 0x7)), val);
+#endif
+
+ db2_printf("%s[rdata] -> 0x%08x\n", dbg_prefix, val);
+ return val;
+}
+#endif /* SMSC_PLATFORM_DEFINED_GET_DATA*/
+
+/* ------------------------------------------------------------------------*/
+/* Read the bank register (this one is bank-independent)*/
+#ifndef SMSC_PLATFORM_DEFINED_GET_BANKSEL
+static __inline__ unsigned short
+get_banksel(struct lan91cxx_priv_data *cpd)
+{
+ unsigned short val;
+
+ HAL_READ_UINT16(cpd->base+(LAN91CXX_BS), val);
+ val = CYG_LE16_TO_CPU(val);
+ db2_printf("read bank sel val 0x%04x\n", val);
+ return val;
+}
+#endif
+
+
+
+
+
+#endif /* _SMC_91111_H_ */
+
+
diff --git a/c/src/libchip/network/smc91111config.h b/c/src/libchip/network/smc91111config.h
new file mode 100644
index 0000000000..5c293e37fb
--- /dev/null
+++ b/c/src/libchip/network/smc91111config.h
@@ -0,0 +1,132 @@
+/*
+ * $Id$
+ */
+
+#ifndef _SMC91111_CONFIG_H_
+#define _SMC91111_CONFIG_H_
+
+/*
+ * RTEMS event used by interrupt handler to signal driver tasks.
+ * This must not be any of the events used by the network task synchronization.
+ */
+#define INTERRUPT_EVENT RTEMS_EVENT_1
+
+/*
+ * RTEMS event used to start transmit daemon.
+ * This must not be the same as INTERRUPT_EVENT.
+ */
+#define START_TRANSMIT_EVENT RTEMS_EVENT_2
+
+ /* event to send when tx buffers become available */
+#define SMC91111_TX_WAIT_EVENT RTEMS_EVENT_3
+
+
+/* Number of OCs supported by this driver*/
+#define NOCDRIVER 1
+
+/* Receive buffer size -- Allow for a full ethernet packet including CRC */
+#define RBUF_SIZE 1536
+
+#define ET_MINLEN 64 /* minimum message length */
+
+#if (MCLBYTES < RBUF_SIZE)
+# error "Driver must have MCLBYTES > RBUF_SIZE"
+#endif
+
+/* ----------------- cygdriver params ----------------- */
+
+#define LAN91CXX_32BIT_RX
+#define LAN91CXX_IS_LAN91C111
+
+/* ----------------- compat layer ----------------- */
+
+/* -------------------------------------------------------------------------
+ Define basic types for using integers in memory and structures;
+ depends on compiler defaults and CPU type. */
+
+typedef unsigned char cyg_uint8 ;
+typedef signed char cyg_int8 ;
+typedef unsigned short cyg_uint16 ;
+typedef signed short cyg_int16 ;
+typedef unsigned int cyg_uint32 ;
+typedef signed int cyg_int32 ;
+typedef unsigned int cyg_bool ;
+
+typedef cyg_uint32 CYG_WORD;
+typedef cyg_uint8 CYG_BYTE;
+typedef cyg_uint16 CYG_WORD16;
+typedef cyg_uint32 CYG_WORD32;
+
+#ifndef CYG_SWAP16
+# define CYG_SWAP16(_x_) \
+ ({ cyg_uint16 _x = (_x_); ((_x << 8) | (_x >> 8)); })
+#endif
+
+#ifndef CYG_SWAP32
+# define CYG_SWAP32(_x_) \
+ ({ cyg_uint32 _x = (_x_); \
+ ((_x << 24) | \
+ ((0x0000FF00UL & _x) << 8) | \
+ ((0x00FF0000UL & _x) >> 8) | \
+ (_x >> 24)); })
+#endif
+
+# define CYG_CPU_TO_BE16(_x_) (_x_)
+# define CYG_CPU_TO_BE32(_x_) (_x_)
+# define CYG_BE16_TO_CPU(_x_) (_x_)
+# define CYG_BE32_TO_CPU(_x_) (_x_)
+
+# define CYG_CPU_TO_LE16(_x_) CYG_SWAP16((_x_))
+# define CYG_CPU_TO_LE32(_x_) CYG_SWAP32((_x_))
+# define CYG_LE16_TO_CPU(_x_) CYG_SWAP16((_x_))
+# define CYG_LE32_TO_CPU(_x_) CYG_SWAP32((_x_))
+
+#define CYG_MACRO_START do {
+#define CYG_MACRO_END } while (0)
+#define HAL_IO_BARRIER() \
+ asm volatile ( "" : : : "memory" )
+
+#define HAL_READ_UINT8( _register_, _value_ ) \
+ CYG_MACRO_START \
+ ((_value_) = *((volatile CYG_BYTE *)(_register_))); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define HAL_WRITE_UINT8( _register_, _value_ ) \
+ CYG_MACRO_START \
+ (*((volatile CYG_BYTE *)(_register_)) = (_value_)); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define HAL_READ_UINT16( _register_, _value_ ) \
+ CYG_MACRO_START \
+ ((_value_) = *((volatile CYG_WORD16 *)(_register_))); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define HAL_WRITE_UINT16( _register_, _value_ ) \
+ CYG_MACRO_START \
+ (*((volatile CYG_WORD16 *)(_register_)) = (_value_)); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define HAL_READ_UINT32( _register_, _value_ ) \
+ CYG_MACRO_START \
+ ((_value_) = *((volatile CYG_WORD32 *)(_register_))); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define HAL_READ_UINT16( _register_, _value_ ) \
+ CYG_MACRO_START \
+ ((_value_) = *((volatile CYG_WORD16 *)(_register_))); \
+ HAL_IO_BARRIER (); \
+ CYG_MACRO_END
+
+#define CYG_ASSERT(c,p) do { if (!(c)) { while(1) { printf(p);} }; } while(0)
+
+#define HAL_DELAY_US(p) rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (p))
+
+
+#endif /* _SMC_91111_CONFIG_H_ */
+
+
diff --git a/c/src/libchip/network/smc91111exp.h b/c/src/libchip/network/smc91111exp.h
new file mode 100644
index 0000000000..72e41fa0d9
--- /dev/null
+++ b/c/src/libchip/network/smc91111exp.h
@@ -0,0 +1,19 @@
+/*
+ * $Id$
+ */
+
+#ifndef _SMC91111_EXP_H_
+#define _SMC91111_EXP_H_
+
+typedef struct scmv91111_configuration {
+ void *baseaddr;
+ unsigned int vector;
+ unsigned int pio;
+ unsigned int ctl_rspeed;
+ unsigned int ctl_rfduplx;
+ unsigned int ctl_autoneg;
+} scmv91111_configuration_t;
+
+#endif /* _SMC_91111_EXP_H_ */
+
+