]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_Demo_Rowley_ARM7/lwip-1.1.0/src/netif/ethernetif.c
Update the demo directory to use the version 8 type naming conventions.
[freertos] / FreeRTOS / Demo / lwIP_Demo_Rowley_ARM7 / lwip-1.1.0 / src / netif / ethernetif.c
1 /*\r
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
3  * All rights reserved.\r
4  *\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
7  *\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
15  *\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
25  * OF SUCH DAMAGE.\r
26  *\r
27  * This file is part of the lwIP TCP/IP stack.\r
28  *\r
29  * Author: Adam Dunkels <adam@sics.se>\r
30  *\r
31  */\r
32 \r
33 /* lwIP includes. */\r
34 #include <string.h>\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
42 \r
43 /* FreeRTOS includes. */\r
44 #include "FreeRTOS.h"\r
45 #include "SAM7_EMAC.h"\r
46 #include "Emac.h"\r
47 \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
52 #define IFNAME0 'e'\r
53 #define IFNAME1 'm'\r
54 \r
55 /* lwIP definitions. */\r
56 struct ethernetif\r
57 {\r
58         struct eth_addr *ethaddr;\r
59 };\r
60 static const struct eth_addr    ethbroadcast = { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };\r
61 static struct netif *xNetIf = NULL;\r
62 \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
67 \r
68 \r
69 /*-----------------------------------------------------------*/\r
70 \r
71 static void low_level_init( struct netif *netif )\r
72 {\r
73 unsigned portBASE_TYPE uxPriority;\r
74 \r
75         /* set MAC hardware address length */\r
76         netif->hwaddr_len = 6;\r
77 \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
85 \r
86         /* maximum transfer unit */\r
87         netif->mtu = netifMTU;\r
88 \r
89         /* broadcast capability */\r
90         netif->flags = NETIF_FLAG_BROADCAST;\r
91 \r
92         xNetIf = netif;\r
93 \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
102         {\r
103                 __asm( "NOP" );\r
104         }\r
105         vTaskPrioritySet( NULL, uxPriority );\r
106 \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
109 }\r
110 /*-----------------------------------------------------------*/\r
111 \r
112 /*\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
116  */\r
117 static err_t low_level_output( struct netif *netif, struct pbuf *p )\r
118 {\r
119 struct pbuf *q;\r
120 static SemaphoreHandle_t xTxSemaphore = NULL;\r
121 err_t xReturn = ERR_OK;\r
122 \r
123         /* Parameter not used. */\r
124         ( void ) netif;\r
125 \r
126         if( xTxSemaphore == NULL )\r
127         {\r
128                 vSemaphoreCreateBinary( xTxSemaphore );\r
129         }\r
130 \r
131         #if ETH_PAD_SIZE\r
132                 pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */\r
133         #endif\r
134 \r
135         /* Access to the EMAC is guarded using a semaphore. */\r
136         if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )\r
137         {\r
138                 for( q = p; q != NULL; q = q->next )\r
139                 {\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
143                         chain. */\r
144                         if( !lEMACSend( q->payload, q->len, ( q->next == NULL ) ) )\r
145                         {\r
146                                 xReturn = ~ERR_OK;\r
147                         }\r
148                 }\r
149 \r
150         xSemaphoreGive( xTxSemaphore );\r
151         }\r
152 \r
153 \r
154         #if ETH_PAD_SIZE\r
155                 pbuf_header( p, ETH_PAD_SIZE );     /* reclaim the padding word */\r
156         #endif\r
157 \r
158         #if LINK_STATS\r
159                 lwip_stats.link.xmit++;\r
160         #endif /* LINK_STATS */\r
161 \r
162     return xReturn;\r
163 }\r
164 /*-----------------------------------------------------------*/\r
165 \r
166 /*\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
169  */\r
170 static struct pbuf *low_level_input( struct netif *netif )\r
171 {\r
172 struct pbuf         *p = NULL, *q;\r
173 u16_t               len = 0;\r
174 static SemaphoreHandle_t xRxSemaphore = NULL;\r
175 \r
176         /* Parameter not used. */\r
177         ( void ) netif;\r
178 \r
179         if( xRxSemaphore == NULL )\r
180         {\r
181                 vSemaphoreCreateBinary( xRxSemaphore );\r
182         }\r
183 \r
184         /* Access to the emac is guarded using a semaphore. */\r
185         if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )\r
186         {\r
187                 /* Obtain the size of the packet. */\r
188                 len = ulEMACInputLength();\r
189 \r
190                 if( len )\r
191                 {\r
192                         #if ETH_PAD_SIZE\r
193                                 len += ETH_PAD_SIZE;    /* allow room for Ethernet padding */\r
194                         #endif\r
195 \r
196                         /* We allocate a pbuf chain of pbufs from the pool. */\r
197                         p = pbuf_alloc( PBUF_RAW, len, PBUF_POOL );\r
198 \r
199                         if( p != NULL )\r
200                         {\r
201                                 #if ETH_PAD_SIZE\r
202                                         pbuf_header( p, -ETH_PAD_SIZE );    /* drop the padding word */\r
203                                 #endif\r
204 \r
205                                 /* Let the driver know we are going to read a new packet. */\r
206                                 vEMACRead( NULL, 0, len );\r
207 \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
211                                 {\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
215                                 }\r
216 \r
217                                 #if ETH_PAD_SIZE\r
218                                         pbuf_header( p, ETH_PAD_SIZE );     /* reclaim the padding word */\r
219                                 #endif\r
220                                 #if LINK_STATS\r
221                                         lwip_stats.link.recv++;\r
222                                 #endif /* LINK_STATS */\r
223                         }\r
224                         else\r
225                         {\r
226                                 #if LINK_STATS\r
227                                         lwip_stats.link.memerr++;\r
228                                         lwip_stats.link.drop++;\r
229                                 #endif /* LINK_STATS */\r
230                         }\r
231                 }\r
232 \r
233                 xSemaphoreGive( xRxSemaphore );\r
234         }\r
235 \r
236         return p;\r
237 }\r
238 /*-----------------------------------------------------------*/\r
239 \r
240 /*\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
244  */\r
245 static err_t ethernetif_output( struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr )\r
246 {\r
247     /* resolve hardware address, then send (or queue) packet */\r
248     return etharp_output( netif, ipaddr, p );\r
249 }\r
250 /*-----------------------------------------------------------*/\r
251 \r
252 /*\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
256  */\r
257 static void ethernetif_input( void * pvParameters )\r
258 {\r
259 struct ethernetif   *ethernetif;\r
260 struct eth_hdr      *ethhdr;\r
261 struct pbuf         *p;\r
262 \r
263         ( void ) pvParameters;\r
264 \r
265         for( ;; )\r
266         {\r
267                 do\r
268                 {\r
269                         ethernetif = xNetIf->state;\r
270 \r
271                         /* move received packet into a new pbuf */\r
272                         p = low_level_input( xNetIf );\r
273 \r
274                         if( p == NULL )\r
275                         {\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
279                         }\r
280 \r
281                 } while( p == NULL );\r
282 \r
283                 /* points to packet payload, which starts with an Ethernet header */\r
284                 ethhdr = p->payload;\r
285 \r
286                 #if LINK_STATS\r
287                         lwip_stats.link.recv++;\r
288                 #endif /* LINK_STATS */\r
289 \r
290                 ethhdr = p->payload;\r
291 \r
292                 switch( htons( ethhdr->type ) )\r
293                 {\r
294                         /* IP packet? */\r
295                         case ETHTYPE_IP:\r
296                                 /* update ARP table */\r
297                                 etharp_ip_input( xNetIf, p );\r
298 \r
299                                 /* skip Ethernet header */\r
300                                 pbuf_header( p, (s16_t)-sizeof(struct eth_hdr) );\r
301 \r
302                                 /* pass to network layer */\r
303                                 xNetIf->input( p, xNetIf );\r
304                                 break;\r
305 \r
306                         case ETHTYPE_ARP:\r
307                                 /* pass p to ARP module */\r
308                                 etharp_arp_input( xNetIf, ethernetif->ethaddr, p );\r
309                                 break;\r
310 \r
311                         default:\r
312                                 pbuf_free( p );\r
313                                 p = NULL;\r
314                                 break;\r
315                 }\r
316         }\r
317 }\r
318 /*-----------------------------------------------------------*/\r
319 \r
320 static void arp_timer( void *arg )\r
321 {\r
322         ( void ) arg;\r
323 \r
324     etharp_tmr();\r
325     sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );\r
326 }\r
327 /*-----------------------------------------------------------*/\r
328 \r
329 err_t ethernetif_init( struct netif *netif )\r
330 {\r
331 struct ethernetif   *ethernetif;\r
332 \r
333         ethernetif = mem_malloc( sizeof(struct ethernetif) );\r
334 \r
335         if( ethernetif == NULL )\r
336         {\r
337                 LWIP_DEBUGF( NETIF_DEBUG, ("ethernetif_init: out of memory\n") );\r
338                 return ERR_MEM;\r
339         }\r
340 \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
346 \r
347         ethernetif->ethaddr = ( struct eth_addr * ) &( netif->hwaddr[0] );\r
348 \r
349         low_level_init( netif );\r
350         etharp_init();\r
351         sys_timeout( ARP_TMR_INTERVAL, arp_timer, NULL );\r
352 \r
353         return ERR_OK;\r
354 }\r