]> git.sur5r.net Git - freertos/blob - Demo/ARM9_STR91X_IAR/lwip/netif/ethernetif.c
Remove unnecessary use of portLONG, portCHAR and portSHORT.
[freertos] / Demo / ARM9_STR91X_IAR / lwip / 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 /*\r
34  * This file is a skeleton for developing Ethernet network interface\r
35  * drivers for lwIP. Add code to the low_level functions and do a\r
36  * search-and-replace for the word "ethernetif" to replace it with\r
37  * something that better describes your network interface.\r
38  */\r
39 \r
40 #include "lwip/opt.h"\r
41 #include "lwip/def.h"\r
42 #include "lwip/mem.h"\r
43 #include "lwip/pbuf.h"\r
44 #include "lwip/sys.h"\r
45 #include <lwip/stats.h>\r
46 \r
47 #include "netif/etharp.h"\r
48 #include "91x_enet.h"\r
49 \r
50 // Standard library include\r
51 #include <string.h>\r
52 \r
53 #define netifMTU                                ( 1500 )\r
54 #define netifINTERFACE_TASK_STACK_SIZE          ( 350 )\r
55 #define netifINTERFACE_TASK_PRIORITY            ( configMAX_PRIORITIES - 1 )\r
56 #define netifGUARD_BLOCK_TIME                   ( 250 )\r
57 #define IFNAME0 'e'\r
58 #define IFNAME1 'm'\r
59 \r
60 /* The time to block waiting for input. */\r
61 #define emacBLOCK_TIME_WAITING_FOR_INPUT        ( ( portTickType ) 100 )\r
62 \r
63 /* Interrupt status bit definition. */\r
64 #define DMI_RX_CURRENT_DONE 0x8000\r
65 \r
66 extern u8 TxBuff[1520];\r
67 \r
68 static u8_t s_rxBuff[1520];\r
69 \r
70 /* The semaphore used by the ISR to wake the lwIP task. */\r
71 static xSemaphoreHandle s_xSemaphore = NULL;\r
72 \r
73 struct ethernetif {\r
74   struct eth_addr *ethaddr;\r
75   /* Add whatever per-interface state that is needed here. */\r
76 };\r
77 \r
78 static struct netif *s_pxNetIf = NULL;\r
79 \r
80 /* Forward declarations. */\r
81 static err_t ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr);\r
82 static void ethernetif_input( void * pvParameters );\r
83 static void vEMACWaitForInput( void );\r
84 \r
85 \r
86 \r
87 static void low_level_init(struct netif *netif)\r
88 {\r
89   /* set MAC hardware address length */\r
90   netif->hwaddr_len = 6;\r
91 \r
92   /* set MAC hardware address */\r
93   netif->hwaddr[0] = MAC_ADDR0;\r
94   netif->hwaddr[1] = MAC_ADDR1;\r
95   netif->hwaddr[2] = MAC_ADDR2;\r
96   netif->hwaddr[3] = MAC_ADDR3;\r
97   netif->hwaddr[4] = MAC_ADDR4;\r
98   netif->hwaddr[5] = MAC_ADDR5;\r
99 \r
100   /* maximum transfer unit */\r
101   netif->mtu = netifMTU;\r
102 \r
103   /* broadcast capability */\r
104   netif->flags = NETIF_FLAG_BROADCAST;\r
105 \r
106   s_pxNetIf = netif;\r
107 \r
108   if( s_xSemaphore == NULL )\r
109   {\r
110       vSemaphoreCreateBinary( s_xSemaphore );\r
111       xSemaphoreTake( s_xSemaphore,  0);\r
112   }\r
113 \r
114   /* Do whatever else is needed to initialize interface. */\r
115   /* Initialise the MAC. */\r
116   ENET_InitClocksGPIO();\r
117   ENET_Init();\r
118   ENET_Start();\r
119         \r
120   portENTER_CRITICAL();\r
121   {\r
122       /*set MAC physical*/\r
123       ENET_MAC->MAH = (MAC_ADDR5<<8) + MAC_ADDR4;\r
124       ENET_MAC->MAL = (MAC_ADDR3<<24) + (MAC_ADDR2<<16) + (MAC_ADDR1<<8) + MAC_ADDR0;\r
125         \r
126       VIC_Config( ENET_ITLine, VIC_IRQ, 1 );\r
127       VIC_ITCmd( ENET_ITLine, ENABLE ); \r
128       ENET_DMA->ISR = DMI_RX_CURRENT_DONE;\r
129       ENET_DMA->IER = DMI_RX_CURRENT_DONE;\r
130   }\r
131   portEXIT_CRITICAL();\r
132 \r
133   /* Create the task that handles the EMAC. */\r
134   xTaskCreate( ethernetif_input, ( signed char * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );\r
135 }       \r
136 \r
137 \r
138 /*\r
139  * low_level_output():\r
140  *\r
141  * Should do the actual transmission of the packet. The packet is\r
142  * contained in the pbuf that is passed to the function. This pbuf\r
143  * might be chained.\r
144  *\r
145  */\r
146 \r
147 static err_t low_level_output(struct netif *netif, struct pbuf *p)\r
148 {\r
149   static xSemaphoreHandle xTxSemaphore = NULL;\r
150   struct pbuf *q;\r
151   u32_t l = 0;\r
152 \r
153   if( xTxSemaphore == NULL )\r
154   {\r
155       vSemaphoreCreateBinary( xTxSemaphore );\r
156   }\r
157 \r
158 \r
159 #if ETH_PAD_SIZE\r
160   pbuf_header(p, -ETH_PAD_SIZE);                        /* drop the padding word */\r
161 #endif\r
162 \r
163 \r
164   /* Access to the EMAC is guarded using a semaphore. */\r
165   if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )\r
166   {\r
167       for(q = p; q != NULL; q = q->next) {\r
168         /* Send the data from the pbuf to the interface, one pbuf at a\r
169            time. The size of the data in each pbuf is kept in the ->len\r
170            variable. */\r
171         memcpy(&TxBuff[l], (u8_t*)q->payload, q->len);\r
172         l += q->len;\r
173       }\r
174 \r
175       ENET_TxPkt(0, l);\r
176 \r
177       #if ETH_PAD_SIZE\r
178         pbuf_header(p, ETH_PAD_SIZE);                   /* reclaim the padding word */\r
179       #endif\r
180 \r
181       #if LINK_STATS\r
182         lwip_stats.link.xmit++;\r
183       #endif /* LINK_STATS */\r
184 \r
185       xSemaphoreGive( xTxSemaphore );\r
186   }\r
187 \r
188   return ERR_OK;\r
189 }\r
190 \r
191 /*\r
192  * low_level_input():\r
193  *\r
194  * Should allocate a pbuf and transfer the bytes of the incoming\r
195  * packet from the interface into the pbuf.\r
196  *\r
197  */\r
198 \r
199 static struct pbuf *\r
200 low_level_input(struct netif *netif)\r
201 {\r
202   static xSemaphoreHandle xRxSemaphore = NULL;\r
203   struct pbuf *p, *q;\r
204   u16_t len, l;\r
205 \r
206   l = 0;\r
207   p = NULL;\r
208 \r
209   if( xRxSemaphore == NULL )\r
210   {\r
211     vSemaphoreCreateBinary( xRxSemaphore );\r
212   }\r
213 \r
214   /* Access to the emac is guarded using a semaphore. */\r
215   if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )\r
216   {\r
217         /* Obtain the size of the packet and put it into the "len"\r
218            variable. */\r
219         len = ENET_HandleRxPkt(s_rxBuff);\r
220 \r
221         if(len)\r
222         {\r
223               #if ETH_PAD_SIZE\r
224                 len += ETH_PAD_SIZE;                                            /* allow room for Ethernet padding */\r
225               #endif\r
226 \r
227                 /* We allocate a pbuf chain of pbufs from the pool. */\r
228                 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);\r
229 \r
230                 if (p != NULL) {\r
231 \r
232               #if ETH_PAD_SIZE\r
233                   pbuf_header(p, -ETH_PAD_SIZE);                        /* drop the padding word */\r
234               #endif\r
235 \r
236                   /* We iterate over the pbuf chain until we have read the entire\r
237                    * packet into the pbuf. */\r
238                   for(q = p; q != NULL; q = q->next) {\r
239                     /* Read enough bytes to fill this pbuf in the chain. The\r
240                      * available data in the pbuf is given by the q->len\r
241                      * variable. */\r
242                     memcpy((u8_t*)q->payload, &s_rxBuff[l], q->len);\r
243                     l = l + q->len;\r
244                   }\r
245 \r
246 \r
247               #if ETH_PAD_SIZE\r
248                   pbuf_header(p, ETH_PAD_SIZE);                 /* reclaim the padding word */\r
249               #endif\r
250 \r
251               #if LINK_STATS\r
252                   lwip_stats.link.recv++;\r
253               #endif /* LINK_STATS */\r
254                 } else {\r
255               #if LINK_STATS\r
256                   lwip_stats.link.memerr++;\r
257                   lwip_stats.link.drop++;\r
258               #endif /* LINK_STATS */\r
259                 } /* End else */\r
260         } /* End if */\r
261 \r
262        xSemaphoreGive( xRxSemaphore );\r
263   }\r
264 \r
265   return p;\r
266 }\r
267 \r
268 /*\r
269  * ethernetif_output():\r
270  *\r
271  * This function is called by the TCP/IP stack when an IP packet\r
272  * should be sent. It calls the function called low_level_output() to\r
273  * do the actual transmission of the packet.\r
274  *\r
275  */\r
276 \r
277 static err_t ethernetif_output(struct netif *netif, struct pbuf *p,  struct ip_addr *ipaddr)\r
278 {\r
279 \r
280  /* resolve hardware address, then send (or queue) packet */\r
281   return etharp_output(netif, ipaddr, p);\r
282 \r
283 }\r
284 \r
285 /*\r
286  * ethernetif_input():\r
287  *\r
288  * This function should be called when a packet is ready to be read\r
289  * from the interface. It uses the function low_level_input() that\r
290  * should handle the actual reception of bytes from the network\r
291  * interface.\r
292  *\r
293  */\r
294 \r
295 static void ethernetif_input( void * pvParameters )\r
296 {\r
297   struct ethernetif *ethernetif;\r
298   struct eth_hdr *ethhdr;\r
299   struct pbuf *p;\r
300 \r
301         for( ;; )\r
302         {\r
303                 do\r
304                 {\r
305                         ethernetif = s_pxNetIf->state;\r
306                         \r
307                         /* move received packet into a new pbuf */\r
308                         p = low_level_input( s_pxNetIf );\r
309                         \r
310                         if( p == NULL )\r
311                         {\r
312                                 /* No packet could be read.  Wait a for an interrupt to tell us\r
313                                 there is more data available. */\r
314                                 vEMACWaitForInput();\r
315                         }\r
316                 \r
317                 } while( p == NULL );\r
318 \r
319                 /* points to packet payload, which starts with an Ethernet header */\r
320                 ethhdr = p->payload;\r
321 \r
322                 #if LINK_STATS\r
323                         lwip_stats.link.recv++;\r
324                 #endif /* LINK_STATS */\r
325 \r
326                 ethhdr = p->payload;\r
327 \r
328                 switch (htons(ethhdr->type))\r
329                 {\r
330                         /* IP packet? */\r
331                         case ETHTYPE_IP:\r
332                                 /* update ARP table */\r
333                                 etharp_ip_input(s_pxNetIf, p);\r
334                                 /* skip Ethernet header */\r
335                                 pbuf_header(p, (s16_t)-sizeof(struct eth_hdr));\r
336                                 /* pass to network layer */\r
337                                 s_pxNetIf->input(p, s_pxNetIf);\r
338                                 break;\r
339                 \r
340                         case ETHTYPE_ARP:\r
341                                   /* pass p to ARP module  */\r
342                                   etharp_arp_input(s_pxNetIf, ethernetif->ethaddr, p);\r
343                                   break;\r
344                                 \r
345                         default:\r
346                                   pbuf_free(p);\r
347                                   p = NULL;\r
348                                   break;\r
349                 }\r
350         }\r
351 }\r
352 \r
353 static void\r
354 arp_timer(void *arg)\r
355 {\r
356   etharp_tmr();\r
357   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
358 }\r
359 \r
360 /*\r
361  * ethernetif_init():\r
362  *\r
363  * Should be called at the beginning of the program to set up the\r
364  * network interface. It calls the function low_level_init() to do the\r
365  * actual setup of the hardware.\r
366  *\r
367  */\r
368 \r
369 err_t\r
370 ethernetif_init(struct netif *netif)\r
371 {\r
372   struct ethernetif *ethernetif;\r
373 \r
374   ethernetif = mem_malloc(sizeof(struct ethernetif));\r
375 \r
376   if (ethernetif == NULL)\r
377   {\r
378         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));\r
379         return ERR_MEM;\r
380   }\r
381 \r
382 #if LWIP_SNMP\r
383         /* ifType ethernetCsmacd(6) @see RFC1213 */\r
384         netif->link_type = 6;\r
385         /* your link speed here */\r
386         netif->link_speed = ;\r
387         netif->ts = 0;\r
388         netif->ifinoctets = 0;\r
389         netif->ifinucastpkts = 0;\r
390         netif->ifinnucastpkts = 0;\r
391         netif->ifindiscards = 0;\r
392         netif->ifoutoctets = 0;\r
393         netif->ifoutucastpkts = 0;\r
394         netif->ifoutnucastpkts = 0;\r
395         netif->ifoutdiscards = 0;\r
396 #endif\r
397         \r
398   netif->state = ethernetif;\r
399   netif->name[0] = IFNAME0;\r
400   netif->name[1] = IFNAME1;\r
401   netif->output = ethernetif_output;\r
402   netif->linkoutput = low_level_output;\r
403 \r
404   ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);\r
405 \r
406   low_level_init(netif);\r
407 \r
408   etharp_init();\r
409 \r
410   sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
411 \r
412   return ERR_OK;\r
413 }\r
414 /*-----------------------------------------------------------*/\r
415 \r
416 void ENET_IRQHandler(void)\r
417 {\r
418 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;\r
419 \r
420         /* Give the semaphore in case the lwIP task needs waking. */\r
421         xSemaphoreGiveFromISR( s_xSemaphore, &xHigherPriorityTaskWoken );\r
422         \r
423         /* Clear the interrupt. */\r
424         ENET_DMA->ISR = DMI_RX_CURRENT_DONE;\r
425         \r
426         /* Switch tasks if necessary. */        \r
427         portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );\r
428 }\r
429 /*-----------------------------------------------------------*/\r
430 \r
431 void vEMACWaitForInput( void )\r
432 {\r
433         /* Just wait until we are signled from an ISR that data is available, or\r
434         we simply time out. */\r
435         xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );\r
436 }\r