Mercurial > ecos
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; +}
