summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2004-03-14 01:28:08 +0000
committerChris Johns <chrisj@rtems.org>2004-03-14 01:28:08 +0000
commit00bf77454744fe75694db20ecc6902d2d403d961 (patch)
treec732bf8e7849385b50f9869781652c5c38362f64
parentThe CS8900 driver is documented in the cs8900.h header file. (diff)
downloadrtems-00bf77454744fe75694db20ecc6902d2d403d961.tar.bz2
Changes made to support the DIMMPC. This is a pc396 target with IO port
support. Minor formating clean up. Add documentation to the header file.
-rw-r--r--c/src/libchip/network/cs8900.c541
-rw-r--r--c/src/libchip/network/cs8900.h370
2 files changed, 607 insertions, 304 deletions
diff --git a/c/src/libchip/network/cs8900.c b/c/src/libchip/network/cs8900.c
index 341042d5ee..3e7d219cd3 100644
--- a/c/src/libchip/network/cs8900.c
+++ b/c/src/libchip/network/cs8900.c
@@ -1,91 +1,37 @@
/*
------------------------------------------------------------------------
- $Id$
+ cs8900.c,v 1.5 2002/11/13 15:34:39 joel Exp
------------------------------------------------------------------------
-
- My Right Boot, a boot ROM for embedded hardware.
-
+
Copyright Cybertec Pty Ltd, 2000
All rights reserved Cybertec Pty Ltd, 2000
-
+
+ Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
+ This project has been assisted by the Commonwealth Government
+ through the Australia Council, its arts funding and advisory body.
+
COPYRIGHT (c) 1989-1998.
On-Line Applications Research Corporation (OAR).
+ Copyright assigned to U.S. Government, 1994.
The license and distribution terms for this file may be
found in the file LICENSE in this distribution or at
- http://www.rtems.com/license/LICENSE.
+ http://www.OARcorp.com/rtems/license.html.
------------------------------------------------------------------------
- CS8900 net boot driver.
+ CS8900 RTEMS driver.
+ See the header file for details.
+
*/
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>
-/* #include <target.h>
- chris explain what this is to contain and provide a default one */
#include "cs8900.h"
-/***********************************************************
- ***********************************************************
- BEGIN SECTION OF DEFAULT DEFINES
- ***********************************************************
- ***********************************************************/
-
-/*
- * Number of devices supported by this driver
- */
-#ifndef CS8900_DEVICES
-#define CS8900_DEVICES 1
-#endif
-
-/*
- * This variable really should come from a per device configuration
- * table so the base can vary by adapter.
- */
-
-#ifndef CS8900_IO_BASE
-extern unsigned int bsp_cs8900_io_base;
-#define CS8900_IO_BASE bsp_cs8900_io_base
-#endif
-
-/*
- * This variable really should come from a per device configuration
- * table so the base can vary by adapter.
- */
-
-#ifndef CS8900_MEMORY_BASE
-extern unsigned int bsp_cs8900_memory_base;
-#define CS8900_MEMORY_BASE bsp_cs8900_memory_base
-#endif
-
-/*
- * This could go to a BSP provided callout.
- */
-#ifndef WATCHDOG_TOGGLE
-#define WATCHDOG_TOGGLE()
-#endif
-
-/*
- * This variable really should come from a per device configuration
- * table so the base can vary by adapter.
- *
- * chris this is probably not a good default --joel
- */
-
-#ifndef CS8900_RX_QUEUE_SIZE
-#define CS8900_RX_QUEUE_SIZE 1
-#endif
-
-/***********************************************************
- ***********************************************************
- END SECTION OF DEFAULT DEFINES
- ***********************************************************
- ***********************************************************/
-
/*
* We expect to be able to read a complete packet into an mbuf.
*/
@@ -104,93 +50,129 @@ extern unsigned int bsp_cs8900_memory_base;
#define CS8900_TX_WAIT_EVENT RTEMS_EVENT_3
/*
- * Our local data.
- */
-
-static cs8900_device cs8900[CS8900_DEVICES];
-
-/*
* IO Packet Page inteface.
*/
static inline unsigned short
-io_pp_get_reg_16 (int dev, unsigned short reg)
+io_pp_get_reg_16 (cs8900_device *cs, unsigned short reg)
{
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ rtems_interrupt_level level;
+ unsigned short data;
+ rtems_interrupt_disable (level);
+ cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
- return cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0);
+ data = cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0);
+ rtems_interrupt_enable (level);
+ return data;
}
static inline unsigned long
-io_pp_get_reg_32 (int dev, unsigned short reg)
+io_pp_get_reg_32 (cs8900_device *cs, unsigned short reg)
{
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ rtems_interrupt_level level;
+ unsigned long data;
+ rtems_interrupt_disable (level);
+ cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
- return ((cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0) << 16) |
- cs8900_io_get_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT1));
+ data = ((cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT0) << 16) |
+ cs8900_io_get_reg (cs, CS8900_IO_PP_DATA_PORT1));
+ rtems_interrupt_enable (level);
+ return data;
}
static inline void
-io_pp_set_reg_16 (int dev, unsigned short reg, unsigned short data)
+io_pp_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short data)
{
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ rtems_interrupt_level level;
+ rtems_interrupt_disable (level);
+ cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0, data);
+ cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data);
+ rtems_interrupt_enable (level);
}
static inline void
-io_pp_set_reg_32 (int dev, unsigned short reg, unsigned long data)
+io_pp_set_reg_32 (cs8900_device *cs, unsigned short reg, unsigned long data)
{
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PACKET_PAGE_PTR,
+ cs8900_io_set_reg (cs, CS8900_IO_PACKET_PAGE_PTR,
0x3000 | CS8900_PPP_AUTO_INCREMENT | reg);
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT0, data >> 16);
- cs8900_io_set_reg (dev, CS8900_IO_BASE + CS8900_IO_PP_DATA_PORT1, data);
+ cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT0, data >> 16);
+ cs8900_io_set_reg (cs, CS8900_IO_PP_DATA_PORT1, data);
}
static inline void
-io_pp_bit_set_reg_16 (int dev, unsigned short reg, unsigned short mask)
+io_pp_bit_set_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask)
{
- io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) | mask);
+ rtems_interrupt_level level;
+ rtems_interrupt_disable (level);
+ io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) | mask);
+ rtems_interrupt_enable (level);
}
static inline void
-io_pp_bit_clear_reg_16 (int dev, unsigned short reg, unsigned short mask)
+io_pp_bit_clear_reg_16 (cs8900_device *cs, unsigned short reg, unsigned short mask)
{
- io_pp_set_reg_16 (dev, reg, io_pp_get_reg_16 (dev, reg) & ~mask);
+ rtems_interrupt_level level;
+ rtems_interrupt_disable (level);
+ io_pp_set_reg_16 (cs, reg, io_pp_get_reg_16 (cs, reg) & ~mask);
+ rtems_interrupt_enable (level);
}
/*
* Memory Mapped Packet Page interface.
+ *
+ * If the BSP does not configure mem_base use the I/O register accesses.
*/
static inline unsigned short
-mem_pp_get_reg (int dev, unsigned short reg)
+mem_pp_get_reg (cs8900_device *cs, unsigned short reg)
{
- return cs8900_mem_get_reg (dev, CS8900_MEMORY_BASE + reg);
+ if (!cs->mem_base)
+ return io_pp_get_reg_16 (cs, reg);
+ return cs8900_mem_get_reg (cs, reg);
}
static inline void
-mem_pp_set_reg (int dev, unsigned short reg, unsigned short data)
+mem_pp_set_reg (cs8900_device *cs, unsigned short reg, unsigned short data)
{
- cs8900_mem_set_reg (dev, CS8900_MEMORY_BASE + reg, data);
+ if (!cs->mem_base)
+ io_pp_set_reg_16 (cs, reg, data);
+ else
+ cs8900_mem_set_reg (cs, reg, data);
}
static inline void
-mem_pp_bit_set_reg (int dev, unsigned short reg, unsigned short mask)
+mem_pp_bit_set_reg (cs8900_device *cs, unsigned short reg, unsigned short mask)
{
- mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) | mask);
+ if (!cs->mem_base)
+ io_pp_bit_set_reg_16 (cs, reg, mask);
+ else
+ {
+ rtems_interrupt_level level;
+ rtems_interrupt_disable (level);
+ mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) | mask);
+ rtems_interrupt_enable (level);
+ }
}
static inline void
-mem_pp_bit_clear_reg (int dev, unsigned short reg, unsigned short mask)
+mem_pp_bit_clear_reg (cs8900_device *cs, unsigned short reg, unsigned short mask)
{
- mem_pp_set_reg (dev, reg, mem_pp_get_reg (dev, reg) & ~mask);
+ if (!cs->mem_base)
+ io_pp_bit_clear_reg_16 (cs, reg, mask);
+ else
+ {
+ rtems_interrupt_level level;
+ rtems_interrupt_disable (level);
+ mem_pp_set_reg (cs, reg, mem_pp_get_reg (cs, reg) & ~mask);
+ rtems_interrupt_enable (level);
+ }
}
/*
* Trace defines and control structures.
*/
-
+
#define CS8900_T_INT (0)
#define CS8900_T_RX_OK (1)
#define CS8900_T_RX_DROPPED (2)
@@ -222,9 +204,9 @@ static inline void
cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var)
{
rtems_interrupt_level level;
-
+
rtems_interrupt_disable (level);
-
+
if (cs->trace_in < CS8900_TRACE_SIZE)
{
cs->trace_key[cs->trace_in] = key;
@@ -232,13 +214,35 @@ cs8900_trace (cs8900_device *cs, unsigned short key, unsigned long var)
cs->trace_time[cs->trace_in] = rtems_read_timer ();
cs->trace_in++;
}
-
+
rtems_interrupt_enable (level);
}
#else
#define cs8900_trace(c, k, v)
#endif
+void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address)
+{
+ unsigned short ma;
+
+ /*
+ * Only ever use IO calls for this function as it can be
+ * called before memory mode has been enabled.
+ */
+
+ ma = io_pp_get_reg_16 (cs, CS8900_PP_IA);
+ mac_address[0] = ma >> 8;
+ mac_address[1] = ma;
+
+ ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 2);
+ mac_address[2] = ma >> 8;
+ mac_address[3] = ma;
+
+ ma = io_pp_get_reg_16 (cs, CS8900_PP_IA + 4);
+ mac_address[4] = ma >> 8;
+ mac_address[5] = ma;
+}
+
/*
* Bring the chip online.
*/
@@ -248,23 +252,22 @@ cs8900_hardware_init (cs8900_device *cs)
{
unsigned long prod_id;
unsigned short status;
- int dev = cs->dev;
/*
* Do nothing while the device is calibrating and checking the EEPROM.
* We must wait 20msecs.
*/
-
- io_pp_bit_set_reg_16 (dev, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET);
+
+ io_pp_bit_set_reg_16 (cs, CS8900_PP_SelfCTL, CS8900_SELF_CTRL_RESET);
rtems_task_wake_after (TOD_MILLISECONDS_TO_TICKS (20));
-
- status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST);
+
+ status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST);
if (status == 0) {
printf("Reading status register again\n");
- status = io_pp_get_reg_16 (dev, CS8900_PP_SelfST);
+ status = io_pp_get_reg_16 (cs, CS8900_PP_SelfST);
}
-
+
if (((status & CS8900_SELF_STATUS_INITD) == 0) ||
((status & CS8900_SELF_STATUS_INITD) &&
(status & CS8900_SELF_STATUS_EEPROM_PRESENT) &&
@@ -273,23 +276,28 @@ cs8900_hardware_init (cs8900_device *cs)
printf ("CS8900: %s. Initialisation aborted.\n",
(status & CS8900_SELF_STATUS_INITD) ?
"EEPROM read/write failed to complete" :
- "Failed to complete to reset");
+ "Failed to complete to reset");
return;
}
-
+
+ /* Set the RX queue size if not set by the BSP. */
+
+ if (cs->rx_queue_size == 0)
+ cs->rx_queue_size = 10;
+
/* Probe the device for its ID */
- prod_id = io_pp_get_reg_32 (dev, CS8900_PP_PROD_ID);
+ prod_id = io_pp_get_reg_32 (cs, CS8900_PP_PROD_ID);
if ((prod_id >> 16) != CS8900_ESIA_ID)
{
- printf ("CS9800: Invalid EISA ID, read product code 0x%08lx\n", prod_id);
+ printf ("CS8900: Invalid EISA ID, read product code 0x%08lx\n", prod_id);
return;
}
if ((prod_id & 0x000000ff) != 0)
{
- printf ("CS9800: Unsupported product id, read product code 0x%08lx\n",
+ printf ("CS8900: Unsupported product id, read product code 0x%08lx\n",
prod_id);
return;
}
@@ -303,19 +311,22 @@ cs8900_hardware_init (cs8900_device *cs)
/*
* Switch to memory base accesses as they are faster. No indirect access.
*/
-
- io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE, CS8900_MEMORY_BASE);
- io_pp_set_reg_16 (dev, CS8900_PP_MEM_BASE + 2, (CS8900_MEMORY_BASE >> 16) & 0xf);
-
- io_pp_set_reg_16 (dev,
- CS8900_PP_BusCTL,
- CS8900_BUS_CTRL_RESET_RX_DMA |
- CS8900_BUS_CTRL_USE_SA |
- CS8900_BUS_CTRL_MEMORY_ENABLE);
- io_pp_set_reg_16 (dev,
- CS8900_PP_BusCTL,
- CS8900_BUS_CTRL_USE_SA |
- CS8900_BUS_CTRL_MEMORY_ENABLE);
+
+ if (cs->mem_base)
+ {
+ io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE, cs->mem_base);
+ io_pp_set_reg_16 (cs, CS8900_PP_MEM_BASE + 2, (cs->mem_base >> 16) & 0xf);
+
+ io_pp_set_reg_16 (cs,
+ CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_RESET_RX_DMA |
+ CS8900_BUS_CTRL_USE_SA |
+ CS8900_BUS_CTRL_MEMORY_ENABLE);
+ io_pp_set_reg_16 (cs,
+ CS8900_PP_BusCTL,
+ CS8900_BUS_CTRL_USE_SA |
+ CS8900_BUS_CTRL_MEMORY_ENABLE);
+ }
/*
* We are now in memory mapped mode.
@@ -327,21 +338,21 @@ cs8900_hardware_init (cs8900_device *cs)
* No auto detect support at the moment. Only 10BaseT.
*/
- mem_pp_set_reg (dev, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET);
-
+ mem_pp_set_reg (cs, CS8900_PP_LineCFG, CS8900_LINE_CTRL_10BASET);
+
/*
* Ask the user for the MAC address, the program into the device.
*/
#define MACO(o) cs->arpcom.ac_enaddr[o]
-
- mem_pp_set_reg (dev, CS8900_PP_IA,
+
+ mem_pp_set_reg (cs, CS8900_PP_IA,
(((unsigned int) MACO (1)) << 8) |
((unsigned int) MACO (0)));
- mem_pp_set_reg (dev, CS8900_PP_IA + 2,
+ mem_pp_set_reg (cs, CS8900_PP_IA + 2,
(((unsigned int) MACO (3)) << 8) |
((unsigned int) MACO (2)));
- mem_pp_set_reg (dev, CS8900_PP_IA + 4,
+ mem_pp_set_reg (cs, CS8900_PP_IA + 4,
(((unsigned int) MACO (5)) << 8) |
((unsigned int) MACO (4)));
@@ -349,7 +360,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Buffer configuration.
*/
- mem_pp_set_reg (dev, CS8900_PP_BufCFG,
+ mem_pp_set_reg (cs, CS8900_PP_BufCFG,
CS8900_BUFFER_CONFIG_RDY_FOR_TX |
CS8900_BUFFER_CONFIG_TX_UNDERRUN |
CS8900_BUFFER_CONFIG_TX_COL_OVF |
@@ -359,7 +370,7 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Receiver configuration.
*/
- mem_pp_set_reg (dev, CS8900_PP_RxCFG,
+ mem_pp_set_reg (cs, CS8900_PP_RxCFG,
CS8900_RX_CONFIG_RX_OK |
CS8900_RX_CONFIG_CRC_ERROR |
CS8900_RX_CONFIG_RUNT|
@@ -369,17 +380,17 @@ cs8900_hardware_init (cs8900_device *cs)
* Set the Receiver control.
*/
- mem_pp_set_reg (dev, CS8900_PP_RxCTL,
+ mem_pp_set_reg (cs, CS8900_PP_RxCTL,
CS8900_RX_CTRL_RX_OK |
CS8900_RX_CTRL_MULTICAST |
CS8900_RX_CTRL_INDIVIDUAL |
CS8900_RX_CTRL_BROADCAST);
-
+
/*
* Set the Transmitter configuration.
*/
- mem_pp_set_reg (dev, CS8900_PP_TxCFG,
+ mem_pp_set_reg (cs, CS8900_PP_TxCFG,
CS8900_TX_CONFIG_TX_OK |
CS8900_TX_CONFIG_OUT_OF_WINDOW |
CS8900_TX_CONFIG_JABBER |
@@ -389,15 +400,17 @@ cs8900_hardware_init (cs8900_device *cs)
* Attach the interrupt handler.
*/
- cs8900_attach_interrupt (dev, cs);
-
+ cs8900_attach_interrupt (cs);
+
/*
* Program the interrupt level we require then enable interrupts.
+ *
+ * Note, this will need to change to support other levels.
*/
- mem_pp_set_reg (dev, CS8900_PP_INT, 0);
+ mem_pp_set_reg (cs, CS8900_PP_INT, cs->irq_level & 3);
- mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+ mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_ENABLE_INT);
}
@@ -405,7 +418,6 @@ rtems_isr
cs8900_interrupt (rtems_vector_number v, void *csp)
{
cs8900_device *cs = csp;
- int dev = cs->dev;
unsigned short isq = 0;
struct mbuf *m;
unsigned char *p;
@@ -414,19 +426,17 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
while (1)
{
- isq = mem_pp_get_reg (dev, CS8900_PP_ISQ);
+ isq = mem_pp_get_reg (cs, CS8900_PP_ISQ);
cs8900_trace (cs, CS8900_T_INT, isq);
- WATCHDOG_TOGGLE ();
-
/*
* No more interrupts to service.
*/
if (isq == 0)
return;
-
+
switch (isq & 0x1f)
{
case 0x04:
@@ -447,10 +457,10 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
cs->rx_ready_tail = 0;
m->m_nextpkt = 0;
cs->rx_ready_len--;
-
+
p = mtod (m, unsigned char *);
-
- m->m_pkthdr.len = cs8900_get_data_block (dev, p);
+
+ m->m_pkthdr.len = cs8900_get_data_block (cs, p);
if (cs->rx_loaded_tail == 0)
cs->rx_loaded_head = m;
@@ -461,15 +471,15 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
if (cs->rx_loaded_len == 1)
{
- cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len);
+ cs8900_trace (cs, CS8900_T_RX_OK, cs->rx_loaded_len);
rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
}
}
else
{
++cs->eth_stats.rx_dropped;
-
- cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len);
+
+ cs8900_trace (cs, CS8900_T_RX_DROPPED, cs->rx_loaded_len);
if (cs->rx_loaded_len == 0)
rtems_event_send (cs->rx_task, CS8900_RX_OK_EVENT);
@@ -482,14 +492,14 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
if (isq & CS8900_RX_EVENT_RUNT)
++cs->eth_stats.rx_runt_errors;
-
+
if (isq & CS8900_RX_EVENT_EXTRA_DATA)
++cs->eth_stats.rx_oversize_errors;
}
break;
case 0x08:
-
+
/*
* TxEvent.
*/
@@ -502,17 +512,17 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
++cs->eth_stats.tx_ok;
cs->tx_active = 0;
-
+
rtems_event_send (cs->tx_task, CS8900_TX_OK_EVENT);
}
break;
case 0x0c:
-
+
/*
* BufEvent.
*/
-
+
if (isq & CS8900_BUFFER_EVENT_RDY_FOR_TX)
{
if (cs->tx_active)
@@ -534,36 +544,36 @@ cs8900_interrupt (rtems_vector_number v, void *csp)
break;
case 0x10:
-
+
/*
* RxMiss.
*/
-
+
cs->eth_stats.rx_missed_errors +=
- mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
+ mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6;
break;
case 0x12:
-
+
/*
* TxCol.
*/
cs->eth_stats.tx_collisions +=
- mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
+ mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6;
break;
default:
break;
}
}
-
+
}
int
-cs8900_link_active (int dev)
+cs8900_link_active (cs8900_device *cs)
{
- return ((mem_pp_get_reg (dev, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ?
+ return ((mem_pp_get_reg (cs, CS8900_PP_LineST) & CS8900_LINE_STATUS_LINK_OK) ?
1 : 0);
}
@@ -573,29 +583,29 @@ cs8900_rx_refill_queue (cs8900_device *cs)
struct ifnet *ifp = &cs->arpcom.ac_if;
struct mbuf *m;
rtems_interrupt_level level;
-
+
/*
* Hold a single queue of mbuf's at the interface. This
* will lower the latency of the driver.
*/
- while (cs->rx_ready_len < CS8900_RX_QUEUE_SIZE)
+ while (cs->rx_ready_len < cs->rx_queue_size)
{
MGETHDR (m, M_DONTWAIT, MT_DATA);
-
+
if (!m)
{
++cs->eth_stats.rx_no_mbufs;
- cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs);
+ cs8900_trace (cs, CS8900_T_NO_MBUF, cs->eth_stats.rx_no_mbufs);
return;
}
-
+
MCLGET (m, M_DONTWAIT);
-
+
if (!m->m_ext.ext_buf)
{
++cs->eth_stats.rx_no_clusters;
- cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters);
+ cs8900_trace (cs, CS8900_T_NO_CLUSTERS, cs->eth_stats.rx_no_clusters);
m_free (m);
return;
}
@@ -603,7 +613,7 @@ cs8900_rx_refill_queue (cs8900_device *cs)
m->m_nextpkt = 0;
rtems_interrupt_disable (level);
-
+
if (cs->rx_ready_tail == 0)
cs->rx_ready_head = m;
else
@@ -619,7 +629,6 @@ static void
cs8900_rx_task (void *arg)
{
cs8900_device *cs = arg;
- int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if;
rtems_event_set events;
struct mbuf *m;
@@ -630,21 +639,19 @@ cs8900_rx_task (void *arg)
/*
* Turn the receiver and transmitter on.
*/
-
- mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
+
+ mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG,
CS8900_LINE_CTRL_RX_ON |
CS8900_LINE_CTRL_TX_ON);
-
+
/*
* Start the software interrupt watchdog.
*/
-
- rtems_interrupt_disable (level);
- mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
+
+ mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
CS8900_BUFFER_CONFIG_SW_INT);
++cs->eth_stats.int_swint_req;
- rtems_interrupt_enable (level);
-
+
/*
* Loop reading packets.
*/
@@ -652,14 +659,14 @@ cs8900_rx_task (void *arg)
while (1)
{
cs8900_rx_refill_queue (cs);
-
+
sc = rtems_bsdnet_event_receive (CS8900_RX_OK_EVENT,
RTEMS_WAIT | RTEMS_EVENT_ANY,
TOD_MILLISECONDS_TO_TICKS (250),
&events);
cs8900_rx_refill_queue (cs);
-
+
if (sc == RTEMS_TIMEOUT)
{
/*
@@ -675,31 +682,29 @@ cs8900_rx_task (void *arg)
{
printf ("cs8900: int lockup, isq flush\n");
- mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
+ mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_ENABLE_INT);
-
- while (mem_pp_get_reg (dev, CS8900_PP_ISQ) != 0);
-
+
+ while (mem_pp_get_reg (cs, CS8900_PP_ISQ) != 0);
+
cs->eth_stats.int_swint_req = cs->eth_stats.int_swint_res = 0;
++cs->eth_stats.int_lockup;
-
- mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+
+ mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_ENABLE_INT);
}
-
- rtems_interrupt_disable (level);
- mem_pp_bit_set_reg (dev, CS8900_PP_BufCFG,
+
+ mem_pp_bit_set_reg (cs, CS8900_PP_BufCFG,
CS8900_BUFFER_CONFIG_SW_INT);
++cs->eth_stats.int_swint_req;
- rtems_interrupt_enable (level);
}
cs8900_trace (cs, CS8900_T_RX_BEGIN, cs->rx_loaded_len);
-
+
while (cs->rx_loaded_len)
{
rtems_interrupt_disable (level);
-
+
m = cs->rx_loaded_head;
if (m)
{
@@ -708,20 +713,20 @@ cs8900_rx_task (void *arg)
cs->rx_loaded_tail = 0;
m->m_nextpkt = 0;
cs->rx_loaded_len--;
-
+
rtems_interrupt_enable (level);
-
+
m->m_pkthdr.rcvif = ifp;
-
+
cs->eth_stats.rx_bytes += m->m_pkthdr.len;
-
+
m->m_len = m->m_pkthdr.len = m->m_pkthdr.len - sizeof (struct ether_header);
-
+
eh = mtod (m, struct ether_header *);
m->m_data += sizeof (struct ether_header);
-
+
++cs->eth_stats.rx_packets;
-
+
ether_input (ifp, eh, m);
}
else
@@ -737,7 +742,6 @@ static void
cs8900_tx_task (void *arg)
{
cs8900_device *cs = arg;
- int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if;
rtems_event_set events;
struct mbuf *m;
@@ -776,24 +780,24 @@ cs8900_tx_task (void *arg)
}
else
{
- if (cs8900_link_active (dev))
+ if (cs8900_link_active (cs))
{
int resending;
-
+
do
{
unsigned short buf_status;
resending = 0;
-
+
cs->tx_active = 1;
-
- mem_pp_set_reg (dev, CS8900_PP_TxCMD,
+
+ mem_pp_set_reg (cs, CS8900_PP_TxCMD,
CS8900_TX_CMD_STATUS_TX_START_ENTIRE |
CS8900_TX_CMD_STATUS_FORCE);
- mem_pp_set_reg (dev, CS8900_PP_TxLength, m->m_pkthdr.len);
-
- buf_status = mem_pp_get_reg (dev, CS8900_PP_BusST);
+ mem_pp_set_reg (cs, CS8900_PP_TxLength, m->m_pkthdr.len);
+
+ buf_status = mem_pp_get_reg (cs, CS8900_PP_BusST);
/*
* If the bid for memory in the device fails trash the
@@ -807,7 +811,7 @@ cs8900_tx_task (void *arg)
/*
* If the buffer is not read enable the interrupt and then wait.
*/
-
+
if ((buf_status & CS8900_BUS_STATUS_RDY_FOR_TX_NOW) == 0)
{
cs->eth_stats.tx_wait_for_rdy4tx++;
@@ -830,16 +834,16 @@ cs8900_tx_task (void *arg)
if (!resending)
{
- cs8900_tx_load (dev, m);
+ cs8900_tx_load (cs, m);
cs->eth_stats.tx_packets++;
cs->eth_stats.tx_bytes += m->m_pkthdr.len;
}
}
}
while (resending);
-
+
m_freem (m);
-
+
do
{
rtems_bsdnet_event_receive (CS8900_TX_OK_EVENT,
@@ -875,13 +879,11 @@ cs8900_start (struct ifnet *ifp)
static void
cs8900_stop (cs8900_device *cs)
{
- int dev = cs->dev;
-
- mem_pp_bit_clear_reg (dev, CS8900_PP_LineCFG,
+ mem_pp_bit_clear_reg (cs, CS8900_PP_LineCFG,
CS8900_LINE_CTRL_RX_ON |
CS8900_LINE_CTRL_TX_ON);
-
- mem_pp_bit_clear_reg (dev, CS8900_PP_BusCTL,
+
+ mem_pp_bit_clear_reg (cs, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_ENABLE_INT);
}
@@ -917,18 +919,17 @@ static const char *eth_statistics_labels[] =
static void
cs8900_stats (cs8900_device *cs)
{
- int dev = cs->dev;
int i;
int max_label = 0;
int len;
unsigned long *value = (unsigned long*) &cs->eth_stats.rx_packets;
cs->eth_stats.rx_missed_errors +=
- mem_pp_get_reg (dev, CS8900_PP_RxMISS) >> 6;
-
+ mem_pp_get_reg (cs, CS8900_PP_RxMISS) >> 6;
+
cs->eth_stats.tx_collisions +=
- mem_pp_get_reg (dev, CS8900_PP_TxCol) >> 6;
-
+ mem_pp_get_reg (cs, CS8900_PP_TxCol) >> 6;
+
printf ("Network Driver Stats for CS8900 :\n");
for (i = 0; i < (sizeof (eth_statistics_labels) / sizeof (const char *)); i++)
@@ -943,16 +944,16 @@ cs8900_stats (cs8900_device *cs)
printf ("%*s - %10u %*s - %10u\n",
max_label, "rx ready len", cs->rx_ready_len,
max_label, "rx loaded len", cs->rx_loaded_len);
-
+
for (i = 0;
i < (sizeof (eth_statistics_labels) / sizeof (const char *));
i++)
{
printf ("%*s - %10lu",
max_label, eth_statistics_labels[i], value[i]);
-
+
i++;
-
+
if (i < (sizeof (eth_statistics_labels) / sizeof (const char *)))
printf (" %*s - %10lu",
max_label, eth_statistics_labels[i], value[i]);
@@ -960,11 +961,11 @@ cs8900_stats (cs8900_device *cs)
}
#if CS8900_TRACE
-
+
for (i = 0; i < cs->trace_in; i++)
{
printf ("%8ld.%03ld ", cs->trace_time[i] / 1000, cs->trace_time[i] % 1000);
-
+
if (cs->trace_key[i] < sizeof (cs8900_trace_labels) / sizeof (char*))
printf ("%s : ", cs8900_trace_labels[cs->trace_key[i]]);
else
@@ -1002,15 +1003,15 @@ cs8900_stats (cs8900_device *cs)
case 0x1f:
printf ("tx request");
break;
-
+
case 0x1e:
printf ("tx wait 4 tx");
break;
-
+
case 0x1d:
printf ("tx already active");
break;
-
+
default:
printf ("unknown event");
break;
@@ -1019,12 +1020,12 @@ cs8900_stats (cs8900_device *cs)
}
else
printf ("0x%08lx", cs->trace_var[i]);
-
+
printf ("\n");
}
cs->trace_in = 0;
-
+
#endif
}
@@ -1032,7 +1033,6 @@ static void
cs8900_init (void *arg)
{
cs8900_device *cs = arg;
- int dev = cs->dev;
struct ifnet *ifp = &cs->arpcom.ac_if;
if (cs->rx_task == 0)
@@ -1041,13 +1041,13 @@ cs8900_init (void *arg)
/*
* Set up the hardware.
*/
-
+
cs8900_hardware_init (cs);
/*
* Start driver task. We have only one task.
*/
-
+
cs->rx_task = rtems_bsdnet_newproc ("CSr0", 4096, cs8900_rx_task, cs);
cs->tx_task = rtems_bsdnet_newproc ("CSt0", 4096, cs8900_tx_task, cs);
}
@@ -1059,22 +1059,22 @@ cs8900_init (void *arg)
if (ifp->if_flags & IFF_PROMISC)
else
#endif
-
+
/*
* Tell the world that we're running.
*/
-
+
ifp->if_flags |= IFF_RUNNING;
/*
- * Set the Line Control to bring the receive and transmitter online.
+ * Set the Line Control to bring the receive and transmitter online.
*/
- mem_pp_bit_set_reg (dev, CS8900_PP_LineCFG,
+ mem_pp_bit_set_reg (cs, CS8900_PP_LineCFG,
CS8900_LINE_CTRL_RX_ON |
CS8900_LINE_CTRL_TX_ON);
- mem_pp_bit_set_reg (dev, CS8900_PP_BusCTL,
+ mem_pp_bit_set_reg (cs, CS8900_PP_BusCTL,
CS8900_BUS_CTRL_ENABLE_INT);
}
@@ -1088,26 +1088,26 @@ cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
{
case SIOCGIFADDR:
case SIOCSIFADDR:
-
+
error = ether_ioctl (ifp, cmd, data);
break;
case SIOCSIFFLAGS:
-
+
switch (ifp->if_flags & (IFF_UP | IFF_RUNNING))
{
case IFF_RUNNING:
-
+
cs8900_stop (cs);
break;
case IFF_UP:
-
+
cs8900_init (cs);
break;
case IFF_UP | IFF_RUNNING:
-
+
cs8900_stop (cs);
cs8900_init (cs);
break;
@@ -1118,7 +1118,7 @@ cs8900_ioctl (struct ifnet *ifp, int cmd, caddr_t data)
break;
case SIO_RTEMS_SHOW_STATS:
-
+
cs8900_stats (cs);
break;
@@ -1144,21 +1144,11 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
/*
* Parse driver name
*/
-
+
if ((unit = rtems_bsdnet_parse_driver_name (config, &name)) < 0)
return 0;
-
- /*
- * Is driver free?
- */
-
- if (unit >= CS8900_DEVICES)
- {
- printf ("Bad CS8900 unit number for device `%s'.\n", config->name);
- return 0;
- }
-
- cs = &cs8900[unit];
+
+ cs = config->drv_ctrl;
cs->dev = unit;
ifp = &cs->arpcom.ac_if;
@@ -1173,23 +1163,23 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
/*
* Process options
*/
-
+
if (config->hardware_address)
memcpy (cs->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
else
- cs8900_get_mac_addr (unit, cs->arpcom.ac_enaddr);
-
+ cs8900_get_mac_addr (cs, cs->arpcom.ac_enaddr);
+
if (config->mtu)
mtu = config->mtu;
else
mtu = ETHERMTU;
-
+
cs->accept_bcast = !config->ignore_broadcast;
-
+
/*
* Set up network interface values.
*/
-
+
ifp->if_softc = cs;
ifp->if_unit = unit;
ifp->if_name = name;
@@ -1199,14 +1189,14 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
ifp->if_start = cs8900_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 to the stack.
*/
-
+
if_attach (ifp);
ether_ifattach (ifp);
}
@@ -1219,9 +1209,8 @@ cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching)
}
cs8900_stop (cs);
- cs8900_detach_interrupt (unit);
+ cs8900_detach_interrupt (cs);
}
-
+
return 1;
-
}
diff --git a/c/src/libchip/network/cs8900.h b/c/src/libchip/network/cs8900.h
index 00082a557f..036b6d6ced 100644
--- a/c/src/libchip/network/cs8900.h
+++ b/c/src/libchip/network/cs8900.h
@@ -1,23 +1,148 @@
/*
------------------------------------------------------------------------
- $Id$
+ cs8900.h,v 1.3 2002/09/07 23:09:47 joel Exp
------------------------------------------------------------------------
- My Right Boot, a boot ROM for embedded hardware.
-
Copyright Cybertec Pty Ltd, 2000
All rights reserved Cybertec Pty Ltd, 2000
+ Port to the DIMM PC copyright (c) 2004 Angelo Fraietta
+ This project has been assisted by the Commonwealth Government
+ through the Australia Council, its arts funding and advisory body.
+
COPYRIGHT (c) 1989-1998.
On-Line Applications Research Corporation (OAR).
The license and distribution terms for this file may be
found in the file LICENSE in this distribution or at
- http://www.rtems.com/license/LICENSE.
+ http://www.OARcorp.com/rtems/license.html.
------------------------------------------------------------------------
- CS8900 net boot driver.
+ CS8900 RTEMS driver.
+
+ This is a generic driver that requires a BSP backend. The BSP backend
+ provides the glue to the specific bus for the target hardware. It has
+ been tested with Coldfire processors, and the PC. These targets have
+ completely different bus, byte order and interrupt structures.
+
+ An example BSP backend is provided in the pci386 BSP.
+
+ The BSP provides the following functions:
+
+ cs8900_io_set_reg
+ cs8900_io_get_reg
+ cs8900_mem_set_reg
+ cs8900_mem_get_reg
+ cs8900_put_data_block
+ cs8900_get_data_block
+ cs8900_tx_load
+ cs8900_attach_interrupt
+ cs8900_detach_interrupt
+
+ The header file provides documentation for these functions. There
+ are four types of functions.
+
+ The I/O set/get functions access the CS8900 I/O registers via the
+ I/O Mode. For example on a PC with an ISA bus you would use the
+ IA32 in/out port instructions. The cs8900_device structure passed
+ to these functions provide these functions with the I/O base
+ address. The BSP must provide these functions.
+
+ The Memory set/get functions access the CS8900 internal registers
+ and frame buffers directly from a 4K byte block of host memory.
+ Memory mode provides a faster access to the CS8900. The cs8900_device
+ structure passed to these functions provides the memory base
+ address. The BSP needs to provide these functions but they do not
+ need to be implemented if the mem_base field is set to 0. The
+ driver will use I/O mode only.
+
+ The Block transfer functions are used to read or write a block
+ of memory from the CS8900. This saves the driver making a number
+ of small calls. The BSP driver must know if I/O or Memory mode
+ can be used.
+
+ The final group of functions is to handle interrupts. The BSP
+ must take care of save and restoring any interrupt state
+ information.
+
+ The BSP declares a 'cs8900_device' structure for each device being
+ attached to the networking stack. It also creates a
+ 'struct rtems_bsdnet_ifconfig' which is used to attach the interface
+ to the networking stack. The following code declares the BSD config:
+
+ static cs8900_device cs8900;
+
+ static struct rtems_bsdnet_ifconfig cs8900_ifconfig =
+ {
+ "cs0",
+ cs8900_driver_attach,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ };
+
+ The device linked to the BSD config structure with:
+
+ cs8900_ifconfig.drv_ctrl = &cs8900;
+
+ If you have a specific hardware address you should point the BSD
+ config structure to that address. If you do not the driver will read
+ the MAC address from the CS8900. This assumes the CS8900 has read
+ the address from an external EEPROM or has been setup by a BIOS or
+ boot monitor. For EEPROM less you need to supply the MAC address.
+
+ Set the I/O and Memory base addresses. If the Memory base address
+ is 0 the driver will use I/O mode only. A typical initialisation
+ looks like:
+
+ printf ("RTEMS BSD Network initialisation.\n");
+ rtems_bsdnet_initialize_network ();
+
+ #define ETHERNET_IO_BASE 0x300
+ #define ETHERNET_MEM_BASE 0
+ #define ETHERNET_IRQ_LEVEL 0
+
+ cs8900_device *cs = &cs8900;
+
+ memset (cs, 0, sizeof (cs8900_device));
+
+ cs->dev = 0;
+ cs->io_base = ETHERNET_IO_BASE;
+ cs->mem_base = ETHERNET_MEM_BASE;
+ cs->irq_level = ETHERNET_IRQ_LEVEL;
+ cs->rx_queue_size = 30;
+
+ cs8900_ifconfig.drv_ctrl = &cs8900;
+
+ printf ("CS8900 initialisation\n");
+
+ rtems_bsdnet_attach (&cs8900_ifconfig);
+
+ flags = IFF_UP;
+ if (rtems_bsdnet_ifconfig (cs8900_ifconfig.name,
+ SIOCSIFFLAGS,
+ &flags) < 0)
+ {
+ printf ("error: can't bring up %s: %s\n",
+ cs8900_ifconfig.name, strerror (errno));
+ return;
+ }
+
+ rtems_bsdnet_do_bootp_and_rootfs ();
+
+ The IRQ level is the one documented in the CS8900 datasheet and below
+ in the CS8900 device structure. You need to map your target IRQ to the
+ CS8900 in the BSP driver.
*/
@@ -328,6 +453,12 @@
#define CS8900_TRACE_SIZE (400)
/*
+ * The default receive queue size. If the BSP sets this field to
+ * 0 this default is used.
+ */
+#define CS8900_RX_QUEUE_SIZE (30)
+
+/*
* Stats, more for debugging than anything else.
*/
@@ -381,6 +512,32 @@ typedef struct
int dev;
/*
+ * Memory base addresses. Making mem_base 0 forces the
+ * driver to perform only I/O space accesses.
+ */
+
+ unsigned long io_base;
+ unsigned long mem_base;
+
+ /*
+ * The IRQ level as defined in the datasheet for the CS8900.
+ *
+ * ISA BUS Pin Value
+ * IRQ10 INTRQ0 0
+ * IRQ11 INTRQ1 1
+ * IRQ12 INTRQ2 2
+ * IRQ5 INTRQ3 3
+ */
+
+ int irq_level;
+
+ /*
+ * The MAC address.
+ */
+
+ unsigned char mac_address[6];
+
+ /*
* The bsdnet information structure.
*/
@@ -399,6 +556,7 @@ typedef struct
/*
* The queues. FIXME : these should be changed to be mbuf lists.
*/
+
struct mbuf *rx_ready_head;
struct mbuf *rx_ready_tail;
int rx_ready_len;
@@ -407,6 +565,13 @@ typedef struct
struct mbuf *rx_loaded_tail;
int rx_loaded_len;
+ /*
+ * Number of mbufs queued for the interrupt handler to
+ * loop reading.
+ */
+
+ int rx_queue_size;
+
#if CS8900_TRACE
unsigned short trace_key[CS8900_TRACE_SIZE];
unsigned long trace_var[CS8900_TRACE_SIZE];
@@ -414,7 +579,7 @@ typedef struct
int trace_in;
#endif
- /*
+ /**
* Standard(!) ethernet statistics
*/
@@ -423,27 +588,176 @@ typedef struct
} cs8900_device;
/*
- * Link is active, and RX count.
- */
-
-int cs8900_link_active (int dev);
-int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config,
- int attaching);
-rtems_isr cs8900_interrupt (rtems_vector_number v, void *cs);
-
-/*
- * Functions Users Provide to implement the driver.
- */
-
-void cs8900_attach_interrupt (int dev, cs8900_device *cs);
-void cs8900_detach_interrupt (int dev);
-void cs8900_get_mac_addr (int dev, unsigned char *mac_address);
-void cs8900_io_set_reg (int dev, unsigned short reg, unsigned short data);
-unsigned short cs8900_io_get_reg (int dev, unsigned short reg);
-void cs8900_mem_set_reg (int dev, unsigned long reg, unsigned short data);
-unsigned short cs8900_mem_get_reg (int dev, unsigned long reg);
-void cs8900_put_data_block (int dev, int len, unsigned char *data);
-unsigned short cs8900_get_data_block (int dev, unsigned char *data);
-void cs8900_tx_load (int dev, struct mbuf *m);
+ * Link active returns the state of the PHY.
+ *
+ * @param cs Pointer to the device structure.
+ */
+
+int cs8900_link_active (cs8900_device *cs);
+
+/**
+ * The RTEMS network stack driver attach function that is loaded into the
+ * the rtems_bsdnet_ifconfig struct. The network stack will call this
+ * function when attaching the driver. The BSP must load the 'drv_ctrl'
+ * field of the structure before calling the 'rtems_bsdnet_attach'
+ * function.
+ *
+ * @param config The RTEMS BSD config structure.
+ *
+ * @param attaching True is the stack is attaching the interface.
+ *
+ * @retval int Set to 1 if the device has attached.
+ */
+
+int cs8900_driver_attach (struct rtems_bsdnet_ifconfig *config,
+ int attaching);
+
+/**
+ * The BSP specific interrupt wrapper calls this function when a device
+ * interrupt occurs.
+ *
+ * @param v The RTEMS vector number that generated the interrupt.
+ *
+ * @param cs Pointer to the device structure passed to the interrupt
+ * catch function provided by the BSP.
+ *
+ * @retval rtems_isr The standard ISR return type.
+ */
+
+rtems_isr cs8900_interrupt (rtems_vector_number v, void *cs);
+
+/**
+ * Get the MAC address for the interface.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param mac_address Pointer to the memory to load the MAC address. This
+ * is a 6 byte buffer so do not exceeed the bounds.
+ */
+
+void cs8900_get_mac_addr (cs8900_device *cs, unsigned char *mac_address);
+
+/**
+ * Catch the device interrupt. When the interrupt is called call the
+ * function 'cs8900_interrupt'.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ */
+
+void cs8900_attach_interrupt (cs8900_device *cs);
+
+/**
+ * Detach the device interrupt.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ */
+
+void cs8900_detach_interrupt (cs8900_device *cs);
+
+/**
+ * Write to an IO space register.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param reg Register offset from the IO base.
+ *
+ * @param data The data to be written to the register.
+ */
+
+void cs8900_io_set_reg (cs8900_device *cs,
+ unsigned short reg, unsigned short data);
+
+/**
+ * Read an IO space register.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param reg Register offset from the IO base.
+ *
+ * @retval unsigned short The register data.
+ */
+
+unsigned short cs8900_io_get_reg (cs8900_device *cs, unsigned short reg);
+
+/**
+ * Write to a memory space register. Will only be called is the mem_base
+ * field of the 'cs' struct is not 0.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param reg Register offset from the memory base.
+ *
+ * @param data The data to be written to the register.
+ */
+
+void cs8900_mem_set_reg (cs8900_device *cs,
+ unsigned long reg, unsigned short data);
+
+/**
+ * Read a memory space register. Will only be called is the mem_base
+ * field of the 'cs' struct is not 0.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param reg Register offset from the IO base.
+ *
+ * @retval unsigned short The register data.
+ */
+
+unsigned short cs8900_mem_get_reg (cs8900_device *cs, unsigned long reg);
+
+/**
+ * Write a block of data to the interface. The BSP codes if this is an IO or
+ * memory space write.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param len The length of data to write.
+ *
+ * @param data Pointer to the data to be written.
+ */
+
+void cs8900_put_data_block (cs8900_device *cs, int len, unsigned char *data);
+
+/**
+ * Read a block of data from the interface. The BSP codes if this is an IO or
+ * memory space write. The read must not be longer than the MTU size.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param data Pointer to the buffer where the data is to be written.
+ *
+ * @retval unsigned short The number of bytes read from the device.
+ */
+
+unsigned short cs8900_get_data_block (cs8900_device *cs, unsigned char *data);
+
+/**
+ * Load a mbuf chain to the device ready for tranmission.
+ *
+ * BSP to provide this function.
+ *
+ * @param cs Pointer to the device structure.
+ *
+ * @param m Pointer to the head of an mbuf chain.
+ */
+
+void cs8900_tx_load (cs8900_device *cs, struct mbuf *m);
#endif