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
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
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
47 #include "netif/etharp.h"
\r
48 #include "91x_enet.h"
\r
50 // Standard library include
\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
60 /* The time to block waiting for input. */
\r
61 #define emacBLOCK_TIME_WAITING_FOR_INPUT ( ( portTickType ) 100 )
\r
63 /* Interrupt status bit definition. */
\r
64 #define DMI_RX_CURRENT_DONE 0x8000
\r
66 extern u8 TxBuff[1520];
\r
68 static u8_t s_rxBuff[1520];
\r
70 /* The semaphore used by the ISR to wake the lwIP task. */
\r
71 static xSemaphoreHandle s_xSemaphore = NULL;
\r
74 struct eth_addr *ethaddr;
\r
75 /* Add whatever per-interface state that is needed here. */
\r
78 static struct netif *s_pxNetIf = NULL;
\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
87 static void low_level_init(struct netif *netif)
\r
89 /* set MAC hardware address length */
\r
90 netif->hwaddr_len = 6;
\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
100 /* maximum transfer unit */
\r
101 netif->mtu = netifMTU;
\r
103 /* broadcast capability */
\r
104 netif->flags = NETIF_FLAG_BROADCAST;
\r
108 if( s_xSemaphore == NULL )
\r
110 vSemaphoreCreateBinary( s_xSemaphore );
\r
111 xSemaphoreTake( s_xSemaphore, 0);
\r
114 /* Do whatever else is needed to initialize interface. */
\r
115 /* Initialise the MAC. */
\r
116 ENET_InitClocksGPIO();
\r
120 portENTER_CRITICAL();
\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
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
131 portEXIT_CRITICAL();
\r
133 /* Create the task that handles the EMAC. */
\r
134 xTaskCreate( ethernetif_input, ( signed portCHAR * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );
\r
139 * low_level_output():
\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
147 static err_t low_level_output(struct netif *netif, struct pbuf *p)
\r
149 static xSemaphoreHandle xTxSemaphore = NULL;
\r
153 if( xTxSemaphore == NULL )
\r
155 vSemaphoreCreateBinary( xTxSemaphore );
\r
160 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
\r
164 /* Access to the EMAC is guarded using a semaphore. */
\r
165 if( xSemaphoreTake( xTxSemaphore, netifGUARD_BLOCK_TIME ) )
\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
171 memcpy(&TxBuff[l], (u8_t*)q->payload, q->len);
\r
178 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
\r
182 lwip_stats.link.xmit++;
\r
183 #endif /* LINK_STATS */
\r
185 xSemaphoreGive( xTxSemaphore );
\r
192 * low_level_input():
\r
194 * Should allocate a pbuf and transfer the bytes of the incoming
\r
195 * packet from the interface into the pbuf.
\r
199 static struct pbuf *
\r
200 low_level_input(struct netif *netif)
\r
202 static xSemaphoreHandle xRxSemaphore = NULL;
\r
203 struct pbuf *p, *q;
\r
209 if( xRxSemaphore == NULL )
\r
211 vSemaphoreCreateBinary( xRxSemaphore );
\r
214 /* Access to the emac is guarded using a semaphore. */
\r
215 if( xSemaphoreTake( xRxSemaphore, netifGUARD_BLOCK_TIME ) )
\r
217 /* Obtain the size of the packet and put it into the "len"
\r
219 len = ENET_HandleRxPkt(s_rxBuff);
\r
224 len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
\r
227 /* We allocate a pbuf chain of pbufs from the pool. */
\r
228 p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
\r
233 pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
\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
242 memcpy((u8_t*)q->payload, &s_rxBuff[l], q->len);
\r
248 pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
\r
252 lwip_stats.link.recv++;
\r
253 #endif /* LINK_STATS */
\r
256 lwip_stats.link.memerr++;
\r
257 lwip_stats.link.drop++;
\r
258 #endif /* LINK_STATS */
\r
262 xSemaphoreGive( xRxSemaphore );
\r
269 * ethernetif_output():
\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
277 static err_t ethernetif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
\r
280 /* resolve hardware address, then send (or queue) packet */
\r
281 return etharp_output(netif, ipaddr, p);
\r
286 * ethernetif_input():
\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
295 static void ethernetif_input( void * pvParameters )
\r
297 struct ethernetif *ethernetif;
\r
298 struct eth_hdr *ethhdr;
\r
305 ethernetif = s_pxNetIf->state;
\r
307 /* move received packet into a new pbuf */
\r
308 p = low_level_input( s_pxNetIf );
\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
317 } while( p == NULL );
\r
319 /* points to packet payload, which starts with an Ethernet header */
\r
320 ethhdr = p->payload;
\r
323 lwip_stats.link.recv++;
\r
324 #endif /* LINK_STATS */
\r
326 ethhdr = p->payload;
\r
328 switch (htons(ethhdr->type))
\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
341 /* pass p to ARP module */
\r
342 etharp_arp_input(s_pxNetIf, ethernetif->ethaddr, p);
\r
354 arp_timer(void *arg)
\r
357 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
\r
361 * ethernetif_init():
\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
370 ethernetif_init(struct netif *netif)
\r
372 struct ethernetif *ethernetif;
\r
374 ethernetif = mem_malloc(sizeof(struct ethernetif));
\r
376 if (ethernetif == NULL)
\r
378 LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
\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
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
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
404 ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);
\r
406 low_level_init(netif);
\r
410 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
\r
414 /*-----------------------------------------------------------*/
\r
416 void ENET_IRQHandler(void)
\r
418 portBASE_TYPE xSwitchRequired;
\r
420 /* Give the semaphore in case the lwIP task needs waking. */
\r
421 xSwitchRequired = xSemaphoreGiveFromISR( s_xSemaphore, pdFALSE );
\r
423 /* Clear the interrupt. */
\r
424 ENET_DMA->ISR = DMI_RX_CURRENT_DONE;
\r
426 /* Switch tasks if necessary. */
\r
427 portEND_SWITCHING_ISR( xSwitchRequired );
\r
429 /*-----------------------------------------------------------*/
\r
431 void vEMACWaitForInput( void )
\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