2 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
\r
3 * All rights reserved.
\r
5 * Redistribution and use in source and binary forms, with or without modification,
\r
6 * are permitted provided that the following conditions are met:
\r
8 * 1. Redistributions of source code must retain the above copyright notice,
\r
9 * this list of conditions and the following disclaimer.
\r
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
\r
11 * this list of conditions and the following disclaimer in the documentation
\r
12 * and/or other materials provided with the distribution.
\r
13 * 3. The name of the author may not be used to endorse or promote products
\r
14 * derived from this software without specific prior written permission.
\r
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
\r
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
\r
19 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
\r
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
\r
21 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
\r
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
\r
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
\r
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
\r
27 * This file is part of the lwIP TCP/IP stack.
\r
29 * Author: Adam Dunkels <adam@sics.se>
\r
33 /* lwIP includes. */
\r
35 #include "lwip/opt.h"
\r
36 #include "lwip/def.h"
\r
37 #include "lwip/mem.h"
\r
38 #include "lwip/pbuf.h"
\r
39 #include "lwip/sys.h"
\r
40 #include <lwip/stats.h>
\r
41 #include "netif/etharp.h"
\r
43 /* FreeRTOS includes. */
\r
44 #include "FreeRTOS.h"
\r
45 #include "SAM7_EMAC.h"
\r
48 #define netifMTU ( 1500 )
\r
49 #define netifINTERFACE_TASK_STACK_SIZE ( 350 )
\r
50 #define netifINTERFACE_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
\r
51 #define netifGUARD_BLOCK_TIME ( 250 )
\r
55 /* lwIP definitions. */
\r
58 struct eth_addr *ethaddr;
\r
60 static const struct eth_addr ethbroadcast = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
\r
61 static struct netif *xNetIf = NULL;
\r
63 /* Forward declarations. */
\r
64 static void ethernetif_input( void * );
\r
65 static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr );
\r
66 err_t ethernetif_init( struct netif *netif );
\r
69 /*-----------------------------------------------------------*/
\r
71 static void low_level_init( struct netif *netif )
\r
73 unsigned portBASE_TYPE uxPriority;
\r
75 /* set MAC hardware address length */
\r
76 netif->hwaddr_len = 6;
\r
78 /* set MAC hardware address */
\r
79 netif->hwaddr[0] = emacETHADDR0;
\r
80 netif->hwaddr[1] = emacETHADDR1;
\r
81 netif->hwaddr[2] = emacETHADDR2;
\r
82 netif->hwaddr[3] = emacETHADDR3;
\r
83 netif->hwaddr[4] = emacETHADDR4;
\r
84 netif->hwaddr[5] = emacETHADDR5;
\r
86 /* maximum transfer unit */
\r
87 netif->mtu = netifMTU;
\r
89 /* broadcast capability */
\r
90 netif->flags = NETIF_FLAG_BROADCAST;
\r
94 /* Initialise the EMAC. This routine contains code that polls status bits.
\r
95 If the Ethernet cable is not plugged in then this can take a considerable
\r
96 time. To prevent this starving lower priority tasks of processing time we
\r
97 lower our priority prior to the call, then raise it back again once the
\r
98 initialisation is complete. */
\r
99 uxPriority = uxTaskPriorityGet( NULL );
\r
100 vTaskPrioritySet( NULL, tskIDLE_PRIORITY );
\r
101 while( xEMACInit() == NULL )
\r
105 vTaskPrioritySet( NULL, uxPriority );
\r
107 /* Create the task that handles the EMAC. */
\r
108 xTaskCreate( ethernetif_input, "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );
\r
110 /*-----------------------------------------------------------*/
\r
113 * low_level_output(): Should do the actual transmission of the packet. The
\r
114 * packet is contained in the pbuf that is passed to the function. This pbuf
\r
115 * might be chained.
\r
117 static err_t low_level_output( struct netif *netif, struct pbuf *p )
\r
120 static SemaphoreHandle_t xTxSemaphore = NULL;
\r
121 err_t xReturn = ERR_OK;
\r
123 /* Parameter not used. */
\r
126 if( xTxSemaphore == NULL )
\r
128 vSemaphoreCreateBinary( xTxSemaphore );
\r
132 pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */
\r
135 /* Access to the EMAC is guarded using a semaphore. */
\r
136 if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )
\r
138 for( q = p; q != NULL; q = q->next )
\r
140 /* Send the data from the pbuf to the interface, one pbuf at a
\r
141 time. The size of the data in each pbuf is kept in the ->len
\r
142 variable. if q->next == NULL then this is the last pbuf in the
\r
144 if( !lEMACSend( q->payload, q->len, ( q->next == NULL ) ) )
\r
150 xSemaphoreGive( xTxSemaphore );
\r
155 pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */
\r
159 lwip_stats.link.xmit++;
\r
160 #endif /* LINK_STATS */
\r
164 /*-----------------------------------------------------------*/
\r
167 * low_level_input(): Should allocate a pbuf and transfer the bytes of the
\r
168 * incoming packet from the interface into the pbuf.
\r
170 static struct pbuf *low_level_input( struct netif *netif )
\r
172 struct pbuf *p = NULL, *q;
\r
174 static SemaphoreHandle_t xRxSemaphore = NULL;
\r
176 /* Parameter not used. */
\r
179 if( xRxSemaphore == NULL )
\r
181 vSemaphoreCreateBinary( xRxSemaphore );
\r
184 /* Access to the emac is guarded using a semaphore. */
\r
185 if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )
\r
187 /* Obtain the size of the packet. */
\r
188 len = ulEMACInputLength();
\r
193 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
\r
196 /* We allocate a pbuf chain of pbufs from the pool. */
\r
197 p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );
\r
202 pbuf_header( p, -ETH_PAD_SIZE ); /* drop the padding word */
\r
205 /* Let the driver know we are going to read a new packet. */
\r
206 vEMACRead( NULL, 0, len );
\r
208 /* We iterate over the pbuf chain until we have read the entire
\r
209 packet into the pbuf. */
\r
210 for( q = p; q != NULL; q = q->next )
\r
212 /* Read enough bytes to fill this pbuf in the chain. The
\r
213 available data in the pbuf is given by the q->len variable. */
\r
214 vEMACRead( q->payload, q->len, len );
\r
218 pbuf_header( p, ETH_PAD_SIZE ); /* reclaim the padding word */
\r
221 lwip_stats.link.recv++;
\r
222 #endif /* LINK_STATS */
\r
227 lwip_stats.link.memerr++;
\r
228 lwip_stats.link.drop++;
\r
229 #endif /* LINK_STATS */
\r
233 xSemaphoreGive( xRxSemaphore );
\r
238 /*-----------------------------------------------------------*/
\r
241 * ethernetif_output(): This function is called by the TCP/IP stack when an
\r
242 * IP packet should be sent. It calls the function called low_level_output()
\r
243 * to do the actual transmission of the packet.
\r
245 static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr )
\r
247 /* resolve hardware address, then send (or queue) packet */
\r
248 return etharp_output( netif, ipaddr, p );
\r
250 /*-----------------------------------------------------------*/
\r
253 * ethernetif_input(): This function should be called when a packet is ready to
\r
254 * be read from the interface. It uses the function low_level_input() that
\r
255 * should handle the actual reception of bytes from the network interface.
\r
257 static void ethernetif_input( void * pvParameters )
\r
259 struct ethernetif *ethernetif;
\r
260 struct eth_hdr *ethhdr;
\r
263 ( void ) pvParameters;
\r
269 ethernetif = xNetIf->state;
\r
271 /* move received packet into a new pbuf */
\r
272 p = low_level_input( xNetIf );
\r
276 /* No packet could be read. Wait a for an interrupt to tell us
\r
277 there is more data available. */
\r
278 vEMACWaitForInput();
\r
281 } while( p == NULL );
\r
283 /* points to packet payload, which starts with an Ethernet header */
\r
284 ethhdr = p->payload;
\r
287 lwip_stats.link.recv++;
\r
288 #endif /* LINK_STATS */
\r
290 ethhdr = p->payload;
\r
292 switch( htons( ethhdr->type ) )
\r
296 /* update ARP table */
\r
297 etharp_ip_input( xNetIf, p );
\r
299 /* skip Ethernet header */
\r
300 pbuf_header( p, (s16_t)-sizeof(struct eth_hdr) );
\r
302 /* pass to network layer */
\r
303 xNetIf->input( p, xNetIf );
\r
307 /* pass p to ARP module */
\r
308 etharp_arp_input( xNetIf, ethernetif->ethaddr, p );
\r
318 /*-----------------------------------------------------------*/
\r
320 static void arp_timer( void *arg )
\r
325 sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
\r
327 /*-----------------------------------------------------------*/
\r
329 err_t ethernetif_init( struct netif *netif )
\r
331 struct ethernetif *ethernetif;
\r
333 ethernetif = mem_malloc( sizeof(struct ethernetif) );
\r
335 if( ethernetif == NULL )
\r
337 LWIP_DEBUGF( NETIF_DEBUG, ("ethernetif_init: out of memory\n") );
\r
341 netif->state = ethernetif;
\r
342 netif->name[0] = IFNAME0;
\r
343 netif->name[1] = IFNAME1;
\r
344 netif->output = ethernetif_output;
\r
345 netif->linkoutput = low_level_output;
\r
347 ethernetif->ethaddr = ( struct eth_addr * ) &( netif->hwaddr[0] );
\r
349 low_level_init( netif );
\r
351 sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );
\r