comparison packages/redboot/current/src/net/eth_drv.c @ 115:6ed91473a1cd ecos-sw-2000-08-21

Merge from eCos master repository on 2000-08-21-22:40:54-BST
author jlarmour
date Fri, 25 Aug 2000 17:32:38 +0000
parents
children
comparison
equal deleted inserted replaced
114:5ad2b71d525e 115:6ed91473a1cd
1 //==========================================================================
2 //
3 // eth_drv.c
4 //
5 // Stand-alone hardware independent networking support for RedBoot
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //==========================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s): gthomas
35 // Contributors: gthomas
36 // Date: 2000-07-14
37 // Purpose:
38 // Description:
39 //
40 // This code is part of RedBoot (tm).
41 //
42 //####DESCRIPTIONEND####
43 //
44 //==========================================================================
45
46 #include <pkgconf/system.h>
47 #include <cyg/infra/cyg_type.h>
48 #include <cyg/hal/hal_arch.h>
49 #include <cyg/infra/diag.h>
50 #include <cyg/hal/drv_api.h>
51 #include <eth_drv.h>
52 #include <netdev.h>
53
54 // High-level ethernet driver
55
56 // Interfaces exported to drivers
57
58 static void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr);
59 static void eth_drv_recv(struct eth_drv_sc *sc, int total_len);
60 static void eth_drv_tx_done(struct eth_drv_sc *sc, unsigned long key, int status);
61
62 struct eth_drv_funs eth_drv_funs = {eth_drv_init, eth_drv_recv, eth_drv_tx_done};
63
64 int net_debug; // FIXME
65
66 unsigned char __local_enet_addr[ETHER_ADDR_LEN+2];
67 struct eth_drv_sc *__local_enet_sc;
68
69 //
70 // Buffer 'get' support. The problem is that this function only gets
71 // called when some data is required, but packets may arrive on the device
72 // at any time. More particularly, on some devices when data arrive, all
73 // of that data needs to be consumed immediately or be lost. This process
74 // is driven by interrupts, which in the stand-along case are simulated by
75 // calling the "poll" interface.
76 //
77 // Thus there will be a pool of buffers, some free and some full, to try
78 // and manage this.
79 //
80
81 #define MAX_ETH_MSG 1540
82 #define NUM_ETH_MSG 16
83
84 struct eth_msg {
85 struct eth_msg *next, *prev;
86 int len; // Actual number of bytes in message
87 unsigned char data[MAX_ETH_MSG];
88 };
89
90 struct eth_msg_hdr {
91 struct eth_msg *first, *last;
92 };
93
94 static struct eth_msg_hdr eth_msg_free, eth_msg_full;
95 static struct eth_msg eth_msgs[NUM_ETH_MSG];
96
97 // Simple queue management functions
98
99 static void
100 eth_drv_msg_put(struct eth_msg_hdr *hdr, struct eth_msg *msg)
101 {
102 if (hdr->first != (struct eth_msg *)hdr) {
103 // Something already in queue
104 hdr->last->next = msg;
105 msg->prev = hdr->last;
106 msg->next = (struct eth_msg *)hdr;
107 hdr->last = msg;
108 } else {
109 hdr->first = hdr->last = msg;
110 msg->next = msg->prev = (struct eth_msg *)hdr;
111 }
112 }
113
114 static struct eth_msg *
115 eth_drv_msg_get(struct eth_msg_hdr *hdr)
116 {
117 struct eth_msg *msg;
118 if (hdr->first != (struct eth_msg *)hdr) {
119 msg = hdr->first;
120 hdr->first = msg->next;
121 msg->next->prev = (struct eth_msg *)hdr;
122 } else {
123 msg = (struct eth_msg *)NULL;
124 }
125 return msg;
126 }
127
128 static void
129 eth_drv_buffers_init(void)
130 {
131 int i;
132 struct eth_msg *msg = eth_msgs;
133
134 eth_msg_full.first = eth_msg_full.last = (struct eth_msg *)&eth_msg_full;
135 eth_msg_free.first = eth_msg_free.last = (struct eth_msg *)&eth_msg_free;
136 for (i = 0; i < NUM_ETH_MSG; i++, msg++) {
137 eth_drv_msg_put(&eth_msg_free, msg);
138 }
139 }
140
141 //
142 // This function is called during system initialization to register a
143 // network interface with the system.
144 //
145 static void
146 eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
147 {
148 // Set up hardware address
149 memcpy(&sc->sc_arpcom.esa, enaddr, ETHER_ADDR_LEN);
150 memcpy(__local_enet_addr, enaddr, ETHER_ADDR_LEN);
151 __local_enet_sc = sc;
152 eth_drv_start(sc);
153 }
154
155 //
156 // This [internal] function will be called to stop activity on an interface.
157 //
158 static void
159 eth_drv_stop(struct eth_drv_sc *sc)
160 {
161 (sc->funs->stop)(sc);
162 }
163
164 //
165 // This [internal] function will be called to start activity on an interface.
166 //
167 static void
168 eth_drv_start(struct eth_drv_sc *sc)
169 {
170 // Perform any hardware initialization
171 (sc->funs->start)(sc, (unsigned char *)&sc->sc_arpcom.esa, 0);
172 }
173
174 //
175 // Send a packet of data to the hardware
176 //
177 void
178 eth_drv_write(char *eth_hdr, char *buf, int len)
179 {
180 struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
181 struct eth_drv_sc *sc = __local_enet_sc;
182 int sent = 0;
183 int sg_len = 2;
184
185 sg_list[0].buf = eth_hdr;
186 sg_list[0].len = 14; // FIXME
187 sg_list[1].buf = buf;
188 sg_list[1].len = len;
189 (sc->funs->send)(sc, sg_list, sg_len, len+14, (unsigned long)&sent);
190 if (net_debug) {
191 printf("Ethernet send:\n");
192 dump_buf(eth_hdr, 14);
193 dump_buf(buf, len);
194 }
195 while (!sent) {
196 (sc->funs->poll)(sc);
197 }
198 }
199
200 //
201 // This function is called from the hardware driver when an output operation
202 // has completed - i.e. the packet has been sent.
203 //
204 static void
205 eth_drv_tx_done(struct eth_drv_sc *sc, unsigned long key, int status)
206 {
207 *(int *)key = 1;
208 }
209
210 //
211 // Receive one packet of data from the hardware, if available
212 //
213 int
214 eth_drv_read(char *eth_hdr, char *buf, int len)
215 {
216 struct eth_drv_sc *sc = __local_enet_sc;
217 struct eth_msg *msg;
218
219 (sc->funs->poll)(sc); // Give the driver a chance to fetch packets
220 msg = eth_drv_msg_get(&eth_msg_full);
221 if (msg) {
222 memcpy(eth_hdr, msg->data, 14);
223 memcpy(buf, &msg->data[14], msg->len-14);
224 eth_drv_msg_put(&eth_msg_free, msg);
225 return msg->len;
226 } else {
227 return 0; // No packets available
228 }
229 }
230
231 //
232 // This function is called from a hardware driver to indicate that an input
233 // packet has arrived. The routine will set up appropriate network resources
234 // to hold the data and call back into the driver to retrieve the data.
235 //
236 static void
237 eth_drv_recv(struct eth_drv_sc *sc, int total_len)
238 {
239 struct eth_drv_sg sg_list[MAX_ETH_DRV_SG];
240 int sg_len = 0;
241 struct eth_msg *msg;
242 static unsigned char no_pkt[MAX_ETH_MSG];
243 unsigned char *buf;
244
245 msg = eth_drv_msg_get(&eth_msg_free);
246 if (msg) {
247 buf = msg->data;
248 } else {
249 printf("%s: packet of %d bytes dropped\n", __FUNCTION__, total_len);
250 buf = &no_pkt[0];
251 }
252 sg_list[0].buf = buf;
253 sg_list[0].len = total_len;
254 sg_len = 1;
255 (sc->funs->recv)(sc, sg_list, sg_len);
256 if (net_debug) {
257 printf("Ethernet recv:\n");
258 dump_buf(buf, 14);
259 dump_buf(buf+14, total_len-14);
260 }
261 if (msg) {
262 msg->len = total_len;
263 eth_drv_msg_put(&eth_msg_full, msg);
264 } else {
265 dump_buf(sg_list[0].buf, sg_list[0].len);
266 }
267 }
268
269 //
270 // Network initialization
271 //
272 int
273 net_init(void)
274 {
275 cyg_netdevtab_entry_t *t;
276
277 // Make sure the recv buffers are set up
278 eth_drv_buffers_init();
279 __pktbuf_init();
280 // Initialize all network devices
281 for (t = &__NETDEVTAB__[0]; t != &__NETDEVTAB_END__; t++) {
282 if (t->init(t)) {
283 t->status = CYG_NETDEVTAB_STATUS_AVAIL;
284 } else {
285 // What to do if device init fails?
286 t->status = 0; // Device not [currently] available
287 }
288 }
289 if (!__local_enet_sc) {
290 printf("No network interfaces found\n");
291 return -1;
292 }
293 return 0;
294 }