]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/io/eth/v2_0/src/lwip/eth_drv.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / io / eth / v2_0 / src / lwip / eth_drv.c
1 //==========================================================================
2 //
3 //      src/lwip/eth_drv.c
4 //
5 //      Hardware independent ethernet driver for lwIP
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    Jani Monoses <jani@iv.ro>
44 // Contributors: 
45 // Date:         2002-04-05
46 // Purpose:      Hardware independent ethernet driver
47 // Description:  Based on the standalone driver for RedBoot.
48 //               
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53 #include <pkgconf/system.h>
54 #include <pkgconf/io_eth_drivers.h>
55
56 #include <cyg/infra/cyg_type.h>
57 #include <cyg/hal/hal_arch.h>
58 #include <cyg/infra/diag.h>
59 #include <cyg/hal/drv_api.h>
60 #include <cyg/hal/hal_if.h>
61 #include <cyg/io/eth/eth_drv.h>
62 #include <cyg/io/eth/netdev.h>
63 #include <string.h>
64
65 #include <cyg/hal/hal_tables.h>
66 #include <cyg/kernel/kapi.h>
67
68 #include "lwip/opt.h"
69 #include "lwip/ip.h"
70 #include "lwip/mem.h"
71 #include "lwip/pbuf.h"
72 #include "lwip/sys.h"
73
74 #include "netif/etharp.h"
75
76
77 // Interfaces exported to drivers
78
79 static void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr);
80 static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);
81 static void eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRWORD key, int status);
82
83 struct eth_drv_funs eth_drv_funs = { eth_drv_init, eth_drv_recv, eth_drv_tx_done };
84
85 #ifdef CYGDBG_IO_ETH_DRIVERS_DEBUG 
86 int cyg_io_eth_net_debug = CYGDBG_IO_ETH_DRIVERS_DEBUG_VERBOSITY;
87 #endif
88
89 extern void lwip_dsr_stuff(void);
90 extern void lwip_set_addr(struct netif *);
91 extern void lwip_dhcp_init(struct netif *);
92
93 //DSR called from the low level driver.Signals the input_thread
94 void
95 eth_drv_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
96 {
97   struct eth_drv_sc *sc = (struct eth_drv_sc *) data;
98   sc->state |= ETH_DRV_NEEDS_DELIVERY;
99   lwip_dsr_stuff();     
100 }
101
102 err_t ecosif_init(struct netif *netif);
103
104 // This function is called during system initialization to register a
105 // network interface with the system.
106 static void
107 eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
108 {
109   struct netif *netif = &sc->sc_arpcom.ac_if;
110   
111   netif->state = sc;
112   ecosif_init(netif);
113   
114   // enaddr == 0 -> hardware init was incomplete (no ESA)
115   if (enaddr != 0) {
116     // Set up hardware address
117     memcpy(netif->hwaddr, enaddr, ETHER_ADDR_LEN);
118     // Perform any hardware initialization
119     (sc->funs->start) (sc, (unsigned char *) &netif->hwaddr, 0);
120   }
121 #ifdef CYGSEM_HAL_VIRTUAL_VECTOR_DIAG
122 // Set up interfaces so debug environment can share this device
123     {
124         void *dbg = CYGACC_CALL_IF_DBG_DATA();
125         if (!dbg) {
126             CYGACC_CALL_IF_DBG_DATA_SET((void *)sc);
127         }
128     }
129 #endif
130     //
131     // we call this after the driver was started successfully
132     //
133     lwip_dhcp_init(netif);
134 }
135
136 //
137 // Control whether any special locking needs to take place if we intend to
138 // cooperate with a ROM monitor (e.g. RedBoot) using this hardware.  
139 //
140 #if defined(CYGSEM_HAL_USE_ROM_MONITOR) && \
141     defined(CYGSEM_HAL_VIRTUAL_VECTOR_DIAG) && \
142    !defined(CYGSEM_HAL_VIRTUAL_VECTOR_CLAIM_COMMS)
143
144 // Indicate that special locking precautions are warranted.
145 #define _LOCK_WITH_ROM_MONITOR
146
147 // This defines the [well known] channel that RedBoot will use when it is
148 // using the network hardware for the debug channel.
149 #define RedBoot_TCP_CHANNEL CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS
150
151 #endif
152
153 //
154 // Send a packet of data to the hardware
155 //
156
157 static void
158 eth_drv_send(struct netif *netif, struct pbuf *p)
159 {
160   struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
161   struct eth_drv_sc *sc = netif->state;
162   int sg_len = 0;
163   struct pbuf *q;
164
165 #ifdef _LOCK_WITH_ROM_MONITOR
166     bool need_lock = false;
167     int debug_chan;
168 #endif
169
170   while (!(sc->funs->can_send) (sc)); 
171
172   for (q = p; q != NULL; q = q->next) {
173     sg_list[sg_len].buf = (CYG_ADDRESS) q->payload;
174     sg_list[sg_len++].len = q->len;
175   }
176 #ifdef _LOCK_WITH_ROM_MONITOR
177   debug_chan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
178   if (debug_chan == RedBoot_TCP_CHANNEL) {
179     need_lock = true;
180     cyg_drv_dsr_lock();
181   }
182 #endif // _LOCK_WITH_ROM_MONITOR
183
184   (sc->funs->send) (sc, sg_list, sg_len, p->tot_len,
185                     (CYG_ADDRWORD) p);
186
187 #ifdef _LOCK_WITH_ROM_MONITOR
188   // Unlock the driver & hardware.  It can once again be safely shared.
189   if (need_lock) {
190     cyg_drv_dsr_unlock();
191   }
192 #endif // _LOCK_WITH_ROM_MONITOR
193
194 }
195
196 //
197 // This function is called from the hardware driver when an output operation
198 // has completed - i.e. the packet has been sent.
199 //
200 static void
201 eth_drv_tx_done(struct eth_drv_sc *sc, CYG_ADDRWORD key, int status)
202 {
203 #if 0   
204   struct pbuf *p = (struct pbuf *)key;
205   struct netif *netif = &sc->sc_arpcom.ac_if;
206
207   CYGARC_HAL_SAVE_GP();
208   CYGARC_HAL_RESTORE_GP();
209 #endif  
210 }
211
212 static void ecosif_input(struct netif *netif, struct pbuf* pbuf);
213
214 #define MAX_ETH_MSG 1540
215 //
216 // This function is called from a hardware driver to indicate that an input
217 // packet has arrived.  The routine will set up appropriate network resources
218 // to hold the data and call back into the driver to retrieve the data.
219 //
220 static void
221 eth_drv_recv(struct eth_drv_sc *sc, int total_len)
222 {
223   struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
224   struct netif *netif = &sc->sc_arpcom.ac_if;
225
226   struct pbuf *p, *q;
227
228   int sg_len = 0;
229   CYGARC_HAL_SAVE_GP();
230
231   if ((total_len > MAX_ETH_MSG) || (total_len < 0)) {
232     total_len = MAX_ETH_MSG;
233   }
234
235   p = pbuf_alloc(PBUF_RAW, total_len, PBUF_POOL);
236
237   if (p == NULL) {
238     LWIP_DEBUGF(0, ("ecosif_input: low_level_input returned NULL\n"));
239     return;
240   }
241
242   for (q = p; q != NULL; q = q->next) {
243     sg_list[sg_len].buf = (CYG_ADDRESS) q->payload;
244     sg_list[sg_len++].len = q->len;
245   }
246   (sc->funs->recv) (sc, sg_list, sg_len);
247   ecosif_input(netif, p);
248   CYGARC_HAL_RESTORE_GP();
249 }
250
251
252 #define IFNAME0 'e'
253 #define IFNAME1 't'
254
255
256
257 //
258 // low_level_output():
259 //
260 // Should do the actual transmission of the packet. The packet is
261 // contained in the pbuf that is passed to the function. This pbuf
262 // might be chained.We pass the data down to the eCos hw independent 
263 // ethernet driver
264 //
265
266 static err_t
267 low_level_output(struct netif *netif, struct pbuf *p)
268 {
269   eth_drv_send(netif, p);
270   return ERR_OK;
271 }
272
273 //
274 // ecosif_output():
275 //
276 // This function is called by the TCP/IP stack when an IP packet
277 // should be sent. It calls the function called low_level_output() to
278 // do the actual transmission of the packet.
279 //
280 //
281 static err_t
282 ecosif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)
283 {
284   // resolve hardware address, then send (or queue) packet
285   return etharp_output(netif, ipaddr, p);
286 }
287
288
289
290 //
291 // ecosif_input():
292 // This function is called when the eCos hw independent driver
293 // has some data to pass up to lwIP.It does it through ecosif_input.
294 //
295 static void
296 ecosif_input(struct netif *netif, struct pbuf *p)
297 {
298   struct eth_hdr *ethhdr;
299   
300   ethhdr = p->payload;
301
302   switch (htons(ethhdr->type)) {
303   case ETHTYPE_IP:
304     LWIP_DEBUGF(0, ("ecosif_input: IP packet\n"));
305     etharp_ip_input(netif, p);
306     pbuf_header(p, -14);
307     netif->input(p, netif);
308     break;
309   case ETHTYPE_ARP:
310     LWIP_DEBUGF(0, ("ecosif_input: ARP packet\n"));
311     etharp_arp_input(netif, (struct eth_addr *) &netif->hwaddr, p);
312     break;
313   default:
314     pbuf_free(p);
315     break;
316   }
317
318 }
319
320 err_t
321 ecosif_init(struct netif *netif)
322 {
323   netif->name[0] = IFNAME0;
324   netif->name[1] = IFNAME1;
325   netif->hwaddr_len = 6;
326   netif->output = ecosif_output;
327   netif->linkoutput = low_level_output;
328   netif->mtu = 1500;
329   lwip_set_addr(netif);
330   return ERR_OK;
331 }