changeset 1471:bdce752faff6

* include/eth_drv.h: * src/lwip/eth_drv.c: Update to support more than one device and be in sync with current lwip code.
author asl
date Sat, 17 Jan 2004 14:14:41 +0000
parents dc5a2e82613e
children 800f60b742b3
files packages/io/eth/current/ChangeLog packages/io/eth/current/include/eth_drv.h packages/io/eth/current/src/lwip/eth_drv.c
diffstat 3 files changed, 230 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/packages/io/eth/current/ChangeLog
+++ b/packages/io/eth/current/ChangeLog
@@ -1,3 +1,9 @@
+2004-01-09  Jani Monoses <jani@iv.ro>
+
+	* include/eth_drv.h:
+	* src/lwip/eth_drv.c: Update to support more than one device and
+	be in sync with current lwip code.
+	
 2004-01-05  Gary Thomas  <gary@mlbassoc.com>
 
 	* src/net/eth_drv.c: Names of FLASH config types changed.
--- a/packages/io/eth/current/include/eth_drv.h
+++ b/packages/io/eth/current/include/eth_drv.h
@@ -85,6 +85,9 @@
 #else // !CYGPKG_NET
 #include <cyg/hal/drv_api.h>
 #endif
+#ifdef CYGPKG_NET_LWIP
+#include "lwip/netif.h"
+#endif
 
 struct eth_drv_sg {
     CYG_ADDRESS  buf;
@@ -143,12 +146,18 @@ struct eth_hwr_funs {
     struct eth_drv_funs *eth_drv, *eth_drv_old;
 };
 
-#ifndef CYGPKG_NET
+#ifdef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
 struct arpcom {
     unsigned char esa[6];
 };
 #endif
 
+#ifdef CYGPKG_NET_LWIP
+struct arpcom {
+    struct netif ac_if;
+};
+#endif
+
 struct eth_drv_sc {
     struct eth_hwr_funs *funs;
     void                *driver_private;
--- a/packages/io/eth/current/src/lwip/eth_drv.c
+++ b/packages/io/eth/current/src/lwip/eth_drv.c
@@ -46,10 +46,6 @@
 // Purpose:      Hardware independent ethernet driver
 // Description:  Based on the standalone driver for RedBoot.
 //               
-//      TODO:
-//              support more than 1 lowlevel device
-//              play nice with RedBoot too
-//
 //####DESCRIPTIONEND####
 //
 //==========================================================================
@@ -69,9 +65,14 @@
 #include <cyg/hal/hal_tables.h>
 #include <cyg/kernel/kapi.h>
 
-// Define table boundaries
-CYG_HAL_TABLE_BEGIN( __NETDEVTAB__, netdev );
-CYG_HAL_TABLE_END( __NETDEVTAB_END__, netdev );
+#include "lwip/opt.h"
+#include "lwip/ip.h"
+#include "lwip/mem.h"
+#include "lwip/pbuf.h"
+#include "lwip/sys.h"
+
+#include "netif/etharp.h"
+
 
 // Interfaces exported to drivers
 
@@ -79,103 +80,113 @@ static void eth_drv_init(struct eth_drv_
 static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);
 static void eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRWORD key, int status);
 
-struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};
+struct eth_drv_funs eth_drv_funs = { eth_drv_init, eth_drv_recv, eth_drv_tx_done };
 
-struct eth_drv_sc *__local_enet_sc;
+#ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG 
+int cyg_io_eth_net_debug = CYGDBG_IO_ETH_DRIVERS_DEBUG_VERBOSITY;
+#endif
+
+extern void lwip_dsr_stuff(void);
+extern void lwip_set_addr(struct netif *);
 
-//this is where lwIP keeps hw address
-unsigned char *lwip_hw_addr; 
+//DSR called from the low level driver.Signals the input_thread
+void
+eth_drv_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
+{
+  struct eth_drv_sc *sc = (struct eth_drv_sc *) data;
+  sc->state |= ETH_DRV_NEEDS_DELIVERY;
+  lwip_dsr_stuff();	
+}
 
-cyg_sem_t delivery;
+err_t ecosif_init(struct netif *netif);
 
-//lwIP callback to pass received data to
-typedef void (*lwip_input_t)(char *,int);
-static lwip_input_t lwip_input;
-void input_thread(void * arg)
+// This function is called during system initialization to register a
+// network interface with the system.
+static void
+eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
 {
-	struct eth_drv_sc * sc;
-	//sc = (struct eth_drv_sc *)arg;
-	sc = __local_enet_sc;
-	for(;;) {
-	cyg_semaphore_wait(&delivery);
-	(sc->funs->deliver)(sc);
-	}	
+  struct netif *netif = &sc->sc_arpcom.ac_if;
+  
+  netif->state = sc;
+  ecosif_init(netif);
+  
+  // enaddr == 0 -> hardware init was incomplete (no ESA)
+  if (enaddr != 0) {
+    // Set up hardware address
+    memcpy(netif->hwaddr, enaddr, ETHER_ADDR_LEN);
+    // Perform any hardware initialization
+    (sc->funs->start) (sc, (unsigned char *) &netif->hwaddr, 0);
+  }
+#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
+// Set up interfaces so debug environment can share this device
+    {
+        void *dbg = CYGACC_CALL_IF_DBG_DATA();
+        if (!dbg) {
+            CYGACC_CALL_IF_DBG_DATA_SET((void *)sc);
+        }
+    }
+#endif
 
 }
 
-void
-eth_drv_dsr(cyg_vector_t vector,
-            cyg_ucount32 count,
-            cyg_addrword_t data)
-{
-	//  struct eth_drv_sc *sc = (struct eth_drv_sc *)data;
-	//  sc->state |= ETH_DRV_NEEDS_DELIVERY;
-	cyg_semaphore_post(&delivery);
-}
-
-
+//
+// Control whether any special locking needs to take place if we intend to
+// cooperate with a ROM monitor (e.g. RedBoot) using this hardware.  
+//
+#if defined(CYGSEM_HAL_USE_ROM_MONITOR) && \
+    defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) && \
+   !defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)
 
-//Called from lwIP init code to init the hw devices
-//and pass the lwip input callback address 
-void init_hw_drivers(unsigned char *hw_addr,lwip_input_t input)
-{
-    cyg_netdevtab_entry_t *t;
-    
-    lwip_hw_addr = hw_addr;
-    lwip_input	 = input;
-	
-// Initialize all network devices
-    for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
-        if (t->init(t)) {
-            t->status = CYG_NETDEVTAB_STATUS_AVAIL;
-        } else {
-            // What to do if device init fails?
-            t->status = 0;  // Device not [currently] available
-        }
-    }
-}
+// Indicate that special locking precautions are warranted.
+#define _LOCK_WITH_ROM_MONITOR
 
-//
-// This function is called during system initialization to register a
-// network interface with the system.
-//
-static void
-eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
-{
-    // enaddr == 0 -> hardware init was incomplete (no ESA)
-    if (enaddr != 0) {
-        // Set up hardware address
-        memcpy(&sc->sc_arpcom.esa, enaddr, ETHER_ADDR_LEN);
-        memcpy(lwip_hw_addr, enaddr, ETHER_ADDR_LEN);
-        __local_enet_sc = sc;
-    	// Perform any hardware initialization
-    	(sc->funs->start)(sc, (unsigned char *)&sc->sc_arpcom.esa, 0);
-    }
-    cyg_semaphore_init(&delivery,0);
-}
+// This defines the [well known] channel that RedBoot will use when it is
+// using the network hardware for the debug channel.
+#define RedBoot_TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
+
+#endif
 
 //
 // Send a packet of data to the hardware
 //
-cyg_sem_t  packet_sent;
 
-void
-eth_drv_write(char *eth_hdr, char *buf, int len)
+static void
+eth_drv_send(struct netif *netif, struct pbuf *p)
 {
-    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
-    struct eth_drv_sc *sc = __local_enet_sc;
-    int sg_len = 1;
+  struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
+  struct eth_drv_sc *sc = netif->state;
+  int sg_len = 0;
+  struct pbuf *q;
+
+#ifdef _LOCK_WITH_ROM_MONITOR
+    bool need_lock = false;
+    int debug_chan;
+#endif
+
+  while (!(sc->funs->can_send) (sc)); 
 
-    while (!(sc->funs->can_send)(sc)) {
-  	cyg_thread_delay(1);
-    }
-   
-    sg_list[0].buf = (CYG_ADDRESS)buf;
-    sg_list[0].len = len;
-//    cyg_semaphore_init(&packet_sent,0);
-    (sc->funs->send)(sc, sg_list, sg_len, len, (CYG_ADDRWORD)&packet_sent);
-    
-//    cyg_semaphore_wait(&packet_sent);
+  for (q = p; q != NULL; q = q->next) {
+    sg_list[sg_len].buf = (CYG_ADDRESS) q->payload;
+    sg_list[sg_len++].len = q->len;
+  }
+#ifdef _LOCK_WITH_ROM_MONITOR
+  debug_chan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
+  if (debug_chan == RedBoot_TCP_CHANNEL) {
+    need_lock = true;
+    cyg_drv_dsr_lock();
+  }
+#endif // _LOCK_WITH_ROM_MONITOR
+
+  (sc->funs->send) (sc, sg_list, sg_len, p->tot_len,
+		    (CYG_ADDRWORD) p);
+
+#ifdef _LOCK_WITH_ROM_MONITOR
+  // Unlock the driver & hardware.  It can once again be safely shared.
+  if (need_lock) {
+    cyg_drv_dsr_unlock();
+  }
+#endif // _LOCK_WITH_ROM_MONITOR
+
 }
 
 //
@@ -186,14 +197,15 @@ static void
 eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRWORD key, int status)
 {
 #if 0	
-    CYGARC_HAL_SAVE_GP();
-    if (key == (CYG_ADDRWORD)&packet_sent) {
-//	cyg_semaphore_post((cyg_sem_t *)&packet_sent);
-    }
-    CYGARC_HAL_RESTORE_GP();
-#endif    
+  struct pbuf *p = (struct pbuf *)key;
+  struct netif *netif = &sc->sc_arpcom.ac_if;
+
+  CYGARC_HAL_SAVE_GP();
+  CYGARC_HAL_RESTORE_GP();
+#endif  
 }
 
+static void ecosif_input(struct netif *netif, struct pbuf* pbuf);
 
 #define MAX_ETH_MSG 1540
 //
@@ -204,23 +216,117 @@ eth_drv_tx_done(struct eth_drv_sc *sc, C
 static void
 eth_drv_recv(struct eth_drv_sc *sc, int total_len)
 {
-    struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
-    int               sg_len = 0;
-    unsigned char buf[MAX_ETH_MSG];
-    CYGARC_HAL_SAVE_GP();
+  struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
+  struct netif *netif = &sc->sc_arpcom.ac_if;
+
+  struct pbuf *p, *q;
+
+  int sg_len = 0;
+  CYGARC_HAL_SAVE_GP();
+
+  if ((total_len > MAX_ETH_MSG) || (total_len < 0)) {
+    total_len = MAX_ETH_MSG;
+  }
 
-    if ((total_len > MAX_ETH_MSG) || (total_len < 0)) {        
-        total_len = MAX_ETH_MSG;
-    }
+  p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
+
+  if (p == NULL) {
+    LWIP_DEBUGF(0, ("ecosif_input: low_level_input returned NULL\n"));
+    return;
+  }
 
-    sg_list[0].buf = (CYG_ADDRESS)buf;
-    sg_list[0].len = total_len;
-    sg_len = 1;
-
-    (sc->funs->recv)(sc, sg_list, sg_len);
-    (lwip_input)((char*)sg_list[0].buf,total_len);		
-    CYGARC_HAL_RESTORE_GP();
+  for (q = p; q != NULL; q = q->next) {
+    sg_list[sg_len].buf = (CYG_ADDRESS) q->payload;
+    sg_list[sg_len++].len = q->len;
+  }
+  (sc->funs->recv) (sc, sg_list, sg_len);
+  ecosif_input(netif, p);
+  CYGARC_HAL_RESTORE_GP();
 }
 
 
-// EOF src/lwip/eth_drv.c
+#define IFNAME0 'e'
+#define IFNAME1 't'
+
+
+
+//
+// low_level_output():
+//
+// Should do the actual transmission of the packet. The packet is
+// contained in the pbuf that is passed to the function. This pbuf
+// might be chained.We pass the data down to the eCos hw independent 
+// ethernet driver
+//
+
+static err_t
+low_level_output(struct netif *netif, struct pbuf *p)
+{
+  eth_drv_send(netif, p);
+  return ERR_OK;
+}
+
+//
+// ecosif_output():
+//
+// This function is called by the TCP/IP stack when an IP packet
+// should be sent. It calls the function called low_level_output() to
+// do the actual transmission of the packet.
+//
+//
+static err_t
+ecosif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
+{
+
+  p = etharp_output(netif, ipaddr, p);
+  if (p) {
+    low_level_output(netif, p);
+    p = NULL;
+  }
+  return ERR_OK;
+}
+
+
+
+//
+// ecosif_input():
+// This function is called when the eCos hw independent driver
+// has some data to pass up to lwIP.It does it through ecosif_input.
+//
+static void
+ecosif_input(struct netif *netif, struct pbuf *p)
+{
+  struct eth_hdr *ethhdr;
+  
+  ethhdr = p->payload;
+
+  switch (htons(ethhdr->type)) {
+  case ETHTYPE_IP:
+    LWIP_DEBUGF(0, ("ecosif_input: IP packet\n"));
+    etharp_ip_input(netif, p);
+    pbuf_header(p, -14);
+    netif->input(p, netif);
+    break;
+  case ETHTYPE_ARP:
+    LWIP_DEBUGF(0, ("ecosif_input: ARP packet\n"));
+    etharp_arp_input(netif, (struct eth_addr *) &netif->hwaddr, p);
+    break;
+  default:
+    pbuf_free(p);
+    break;
+  }
+
+}
+
+err_t
+ecosif_init(struct netif *netif)
+{
+  netif->name[0] = IFNAME0;
+  netif->name[1] = IFNAME1;
+  netif->hwaddr_len = 6;
+  netif->output = ecosif_output;
+  netif->linkoutput = low_level_output;
+  netif->mtu = 1500;
+  lwip_set_addr(netif);
+  return ERR_OK;
+}