1 |
27 |
unneback |
This file provides a simple description of how to write a low-level,
|
2 |
|
|
hardware dependent ethernet driver.
|
3 |
|
|
|
4 |
|
|
The basic idea is that there is a high-level driver (which is only
|
5 |
|
|
code/functions) that is part of the stack. There will be one or more
|
6 |
|
|
low-level driver tied to the actual network hardware. Each of these
|
7 |
|
|
drivers contains one or more driver instances. The principal idea is
|
8 |
|
|
that the low-level drivers know nothing of the details of the stack that
|
9 |
|
|
will be using them. Thus, the same driver can be used by the eCos
|
10 |
|
|
supported TCP/IP stack, or any other, with no changes.
|
11 |
|
|
|
12 |
|
|
A driver instance is contained within a "struct eth_drv_sc".
|
13 |
|
|
|
14 |
|
|
struct eth_hwr_funs {
|
15 |
|
|
// Initialize hardware (including startup)
|
16 |
|
|
void (*start)(struct eth_drv_sc *sc,
|
17 |
|
|
unsigned char *enaddr);
|
18 |
|
|
// Shut down hardware
|
19 |
|
|
void (*stop)(struct eth_drv_sc *sc);
|
20 |
|
|
// Control interface
|
21 |
|
|
int (*control)(struct eth_drv_sc *sc,
|
22 |
|
|
unsigned long cmd,
|
23 |
|
|
void *data,
|
24 |
|
|
int len);
|
25 |
|
|
// Query interface - can a packet be sent?
|
26 |
|
|
int (*can_send)(struct eth_drv_sc *sc);
|
27 |
|
|
// Send a packet of data
|
28 |
|
|
void (*send)(struct eth_drv_sc *sc,
|
29 |
|
|
struct eth_drv_sg *sg_list,
|
30 |
|
|
int sg_len,
|
31 |
|
|
int total_len,
|
32 |
|
|
unsigned long key);
|
33 |
|
|
// Receive [unload] a packet of data
|
34 |
|
|
void (*recv)(struct eth_drv_sc *sc,
|
35 |
|
|
struct eth_drv_sg *sg_list,
|
36 |
|
|
int sg_len);
|
37 |
|
|
// Deliver data to/from device from/to stack memory space
|
38 |
|
|
// (moves lots of memcpy()s out of DSRs into thread)
|
39 |
|
|
void (*deliver)(struct eth_drv_sc *sc);
|
40 |
|
|
// Poll for interrupts/device service
|
41 |
|
|
void (*poll)(struct eth_drv_sc *sc);
|
42 |
|
|
// Get interrupt information from hardware driver
|
43 |
|
|
int (*int_vector)(struct eth_drv_sc *sc);
|
44 |
|
|
// Logical driver interface
|
45 |
|
|
struct eth_drv_funs *eth_drv, *eth_drv_old;
|
46 |
|
|
};
|
47 |
|
|
|
48 |
|
|
struct eth_drv_sc {
|
49 |
|
|
struct eth_hwr_funs *funs;
|
50 |
|
|
void *driver_private;
|
51 |
|
|
const char *dev_name;
|
52 |
|
|
struct arpcom sc_arpcom; /* ethernet common */
|
53 |
|
|
};
|
54 |
|
|
|
55 |
|
|
You create one of these instances using the "ETH_DRV_SC()" macro which
|
56 |
|
|
sets up the structure, including the prototypes for the functions, etc.
|
57 |
|
|
By doing things this way, if the internal design of the ethernet drivers
|
58 |
|
|
changes (e.g. we need to add a new low-level implementation function),
|
59 |
|
|
existing drivers will no longer compile until updated. This is much
|
60 |
|
|
better than to have all of the definitions in the low-level drivers
|
61 |
|
|
themselves and have them be [quietly] broken if the interfaces change.
|
62 |
|
|
|
63 |
|
|
The "magic" which gets the drivers started [and indeed, linked] is
|
64 |
|
|
similar to what is used for the I/O subsystem. [Note: I may try and
|
65 |
|
|
make it part of the I/O subsystem later.] This is done using the
|
66 |
|
|
"NETDEVTAB_ENTRY()" macro, which defines an initialization function
|
67 |
|
|
and the basic data structures for the low-level driver.
|
68 |
|
|
|
69 |
|
|
typedef struct cyg_netdevtab_entry {
|
70 |
|
|
const char *name;
|
71 |
|
|
bool (*init)(struct cyg_netdevtab_entry *tab);
|
72 |
|
|
void *device_instance;
|
73 |
|
|
unsigned long status;
|
74 |
|
|
} cyg_netdevtab_entry_t;
|
75 |
|
|
|
76 |
|
|
The "device_instance" entry here would point to the "struct
|
77 |
|
|
eth_drv_sc" entry previously defined. This allows the network driver
|
78 |
|
|
setup to work with any class of driver, not just ethernet drivers. In
|
79 |
|
|
the future, there will surely be serial PPP drivers, etc. These will
|
80 |
|
|
use the "NETDEVTAB" setup to create the basic driver, but they will
|
81 |
|
|
most likely be built on top of other high-level device driver layers.
|
82 |
|
|
|
83 |
|
|
So, the bottom line is that a hardware driver will have a template
|
84 |
|
|
(boilerplate) which looks like this:
|
85 |
|
|
|
86 |
|
|
#include
|
87 |
|
|
#include
|
88 |
|
|
#include
|
89 |
|
|
#include
|
90 |
|
|
#include
|
91 |
|
|
#include
|
92 |
|
|
|
93 |
|
|
ETH_DRV_SC(DRV_sc,
|
94 |
|
|
0, // No driver specific data needed
|
95 |
|
|
"eth0", // Name for this interface
|
96 |
|
|
HRDWR_start,
|
97 |
|
|
HRDWR_stop,
|
98 |
|
|
HRDWR_control,
|
99 |
|
|
HRDWR_can_send
|
100 |
|
|
HRDWR_send,
|
101 |
|
|
HRDWR_recv);
|
102 |
|
|
|
103 |
|
|
NETDEVTAB_ENTRY(DRV_netdev,
|
104 |
|
|
"DRV",
|
105 |
|
|
DRV_HRDWR_init,
|
106 |
|
|
&DRV_sc);
|
107 |
|
|
|
108 |
|
|
This, along with the referenced functions, completely define the driver.
|
109 |
|
|
Extensibility note: if one needed the same low-level driver to handle
|
110 |
|
|
multiple similar hardware interfaces, you would need multiple invocations
|
111 |
|
|
of the "ETH_DRV_SC()/NETDEVTAB_ENTRY()" macros. You would add a pointer
|
112 |
|
|
to some instance specific data, e.g. containing base addresses, interrupt
|
113 |
|
|
numbers, etc, where the "0, // No driver specific data" is currently.
|
114 |
|
|
|
115 |
|
|
Now a quick waltz through the functions. This discussion will use the
|
116 |
|
|
generic names from above.
|
117 |
|
|
|
118 |
|
|
static bool DRV_HDWR_init(struct cyg_netdevtab_entry *tab)
|
119 |
|
|
==========================================================
|
120 |
|
|
|
121 |
|
|
This function is called as part of system initialization. Its primary
|
122 |
|
|
function is to decide if the hardware [as indicated via
|
123 |
|
|
tab->device_instance] is working and if the interface needs to be made
|
124 |
|
|
available in the system. If this is the case, this function needs to
|
125 |
|
|
finish with a call to the ethernet driver function:
|
126 |
|
|
|
127 |
|
|
eth_drv_init((struct eth_drv_sc *)tab->device_instance,
|
128 |
|
|
unsigned char *enaddr);
|
129 |
|
|
|
130 |
|
|
where 'enaddr' is a pointer to the ethernet station address for this
|
131 |
|
|
unit. Note: the ethernet station address is supposed to be a
|
132 |
|
|
world-unique, 48 bit address for this particular ethernet interface.
|
133 |
|
|
Typically it is provided by the board/hardware manufacturer in ROM.
|
134 |
|
|
|
135 |
|
|
In many packages it is possible for the ESA to be set from RedBoot,
|
136 |
|
|
(perhaps from 'fconfig' data), hard-coded from CDL, or from an EPROM.
|
137 |
|
|
A driver should choose a run-time specified ESA (e.g. from RedBoot)
|
138 |
|
|
preferentially, otherwise (in order) it should use a CDL specified
|
139 |
|
|
ESA if one has been set, otherwise an EPROM set ESA, or otherwise
|
140 |
|
|
fail. See the cl/cs8900a eth driver for an example.
|
141 |
|
|
|
142 |
|
|
static void
|
143 |
|
|
HRDWR_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
|
144 |
|
|
====================================================================
|
145 |
|
|
|
146 |
|
|
This function is called, perhaps much later than system initialization
|
147 |
|
|
time, when the system (an application) is ready for the interface to
|
148 |
|
|
become active. The purpose of this function is to set up the hardware
|
149 |
|
|
interface to start accepting packets from the network and be able to
|
150 |
|
|
send packets out. Note: this function will be called whenever the
|
151 |
|
|
up/down state of the logical interface changes, e.g. when the IP address
|
152 |
|
|
changes. This may occur more than one time, so this function needs to
|
153 |
|
|
be prepared for that case.
|
154 |
|
|
|
155 |
|
|
FUTURE: the "flags" field (currently unused) may be used to tell the
|
156 |
|
|
function how to start up, e.g. whether interrupts will be used,
|
157 |
|
|
selection of "promiscuous" mode etc.
|
158 |
|
|
|
159 |
|
|
static void HRDWR_stop(struct eth_drv_sc *sc)
|
160 |
|
|
=============================================
|
161 |
|
|
|
162 |
|
|
This function is the inverse of "start". It should shut down the
|
163 |
|
|
hardware and keep it from interacting with the physical network.
|
164 |
|
|
|
165 |
|
|
static int
|
166 |
|
|
HRDWR_control(struct eth_drv_sc *sc, unsigned long key, void *data, int len)
|
167 |
|
|
============================================================================
|
168 |
|
|
|
169 |
|
|
This function is used to perform low-level "control" operations on the
|
170 |
|
|
interface. These operations would be initiated via 'ioctl()' in the BSD
|
171 |
|
|
stack, and would be anything that would require the hardware setup to
|
172 |
|
|
possibly change (i.e. cannot be performed totally by the
|
173 |
|
|
platform-independent layers).
|
174 |
|
|
|
175 |
|
|
Current operations:
|
176 |
|
|
|
177 |
|
|
ETH_DRV_SET_MAC_ADDRESS:
|
178 |
|
|
This function sets the ethernet station address (ESA or MAC) for the
|
179 |
|
|
device. Normally this address is kept in non-volatile memory and is
|
180 |
|
|
unique in the world. This function must at least set the interface to
|
181 |
|
|
use the new address. It may also update the NVM as appropriate.
|
182 |
|
|
|
183 |
|
|
This function should return zero if the specified operation was
|
184 |
|
|
completed successfully. It should return non-zero if the operation
|
185 |
|
|
could not be performed, for any reason.
|
186 |
|
|
|
187 |
|
|
static int HRDWR_can_send(struct eth_drv_sc *sc)
|
188 |
|
|
================================================
|
189 |
|
|
|
190 |
|
|
This function is called to determine if it is possible to start the
|
191 |
|
|
transmission of a packet on the interface. Some interfaces will allow
|
192 |
|
|
multiple packets to be "queued" and this function allows for the highest
|
193 |
|
|
possible utilization of that mode.
|
194 |
|
|
|
195 |
|
|
Return the number of packets which could be accepted at this time, zero
|
196 |
|
|
implies that the interface is saturated/busy.
|
197 |
|
|
|
198 |
|
|
static void
|
199 |
|
|
HRDWR_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
|
200 |
|
|
int total_len, unsigned long key)
|
201 |
|
|
=========================================================================
|
202 |
|
|
|
203 |
|
|
This function is used to send a packet of data to the network. It is
|
204 |
|
|
the responsibility of this function to somehow hand the data over to the
|
205 |
|
|
hardware interface. This will most likely require copying, but just the
|
206 |
|
|
address/length values could be used by smart hardware.
|
207 |
|
|
|
208 |
|
|
NOTE: All data in/out of the driver is specified via a "scatter-gather"
|
209 |
|
|
list. This is just an array of address/length pairs which describe
|
210 |
|
|
sections of data to move (in the order given by the array).
|
211 |
|
|
|
212 |
|
|
Once the data has been successfully sent by the interface (or if an
|
213 |
|
|
error occurs), the driver should call 'eth_drv_tx_done()' using the
|
214 |
|
|
specified 'key'. Only then will the upper layers release the resources
|
215 |
|
|
for that packet and start another transmission.
|
216 |
|
|
|
217 |
|
|
FUTURE: This function may be extended so that the data need not be
|
218 |
|
|
copied by having the function return a "disposition" code (done, send
|
219 |
|
|
pending, etc). At this point, you should move the data to some "safe"
|
220 |
|
|
location before returning.
|
221 |
|
|
|
222 |
|
|
static void
|
223 |
|
|
HRDWR_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
|
224 |
|
|
=========================================================================
|
225 |
|
|
|
226 |
|
|
This function is actually a call back, only invoked after the
|
227 |
|
|
upper-level function
|
228 |
|
|
eth_drv_recv(struct eth_drv_sc *sc, int total_len)
|
229 |
|
|
has been called. This upper level function is called by the hardware
|
230 |
|
|
driver when it knows that a packet of data is available on the
|
231 |
|
|
interface. The 'eth_drv_recv()' function then arranges network buffers
|
232 |
|
|
and structures for the data and then calls "HRDWR_recv()" to actually
|
233 |
|
|
move the data from the interface.
|
234 |
|
|
|
235 |
|
|
static void
|
236 |
|
|
HRDWR_deliver(struct eth_drv_sc *sc)
|
237 |
|
|
=========================================================================
|
238 |
|
|
|
239 |
|
|
This function is actually a call back, and notifies the driver that delivery
|
240 |
|
|
is happening. This allows it to actually do the copy of packet data to/from
|
241 |
|
|
the hardware from/to the packet buffer. And once that's done, then do things
|
242 |
|
|
like unmask its interrupts, and free any relevant resources so it can process
|
243 |
|
|
further packets.
|
244 |
|
|
|
245 |
|
|
In general it will be called from the user thread responsible for delivering
|
246 |
|
|
network packets.
|
247 |
|
|
|
248 |
|
|
static void
|
249 |
|
|
HRDWR_poll(struct eth_drv_sc *sc)
|
250 |
|
|
=========================================================================
|
251 |
|
|
|
252 |
|
|
This function is used when in a non-interrupt driven system, e.g. when
|
253 |
|
|
interrupts are completely disabled. This allows the driver time to check
|
254 |
|
|
whether anything needs doing either for transmission, or to check if
|
255 |
|
|
anything has been received, or if any other processing needs doing..
|
256 |
|
|
|
257 |
|
|
static int
|
258 |
|
|
HRDWR_int_vector(struct eth_drv_sc *sc)
|
259 |
|
|
=========================================================================
|
260 |
|
|
|
261 |
|
|
This function returns the interrupt vector number used for RX interrupts.
|
262 |
|
|
This is so the common GDB stubs infrastructure can detect when to check
|
263 |
|
|
for incoming ctrl-c's when doing debugging over ethernet.
|
264 |
|
|
|
265 |
|
|
Upper layer functions - called by drivers
|
266 |
|
|
=========================================
|
267 |
|
|
|
268 |
|
|
These functions are defined by the upper layers (machine independent) of
|
269 |
|
|
the networking driver support. They are present to hide the interfaces
|
270 |
|
|
to the actual networking stack so that the hardware drivers may possibly
|
271 |
|
|
be used by any network stack implementation.
|
272 |
|
|
|
273 |
|
|
These functions require a pointer to a "struct eth_drv_sc" table which
|
274 |
|
|
describes the interface at a logical level. It is assumed that the
|
275 |
|
|
driver [lowest level hardware support] will keep track of this pointer
|
276 |
|
|
so it may be passed "up" as appropriate.
|
277 |
|
|
|
278 |
|
|
struct eth_drv_sc {
|
279 |
|
|
struct eth_drv_funs *funs; // Pointer to hardware functions (see above)
|
280 |
|
|
void *driver_private; // Device specific data
|
281 |
|
|
const char *dev_name;
|
282 |
|
|
struct arpcom sc_arpcom; // ethernet common
|
283 |
|
|
};
|
284 |
|
|
|
285 |
|
|
This structure is created, one per logical interface, via ETH_DRV_SC macro.
|
286 |
|
|
|
287 |
|
|
void eth_drv_init(struct eth_drv_sc *sc, unsigned char *enaddr)
|
288 |
|
|
===============================================================
|
289 |
|
|
|
290 |
|
|
This function establishes the device at initialization time. The
|
291 |
|
|
hardware should be totally intialized (not "started") when this function
|
292 |
|
|
is called.
|
293 |
|
|
|
294 |
|
|
void eth_drv_tx_done(struct eth_drv_sc *sc, unsigned long key, int status)
|
295 |
|
|
==========================================================================
|
296 |
|
|
|
297 |
|
|
This function is called when a packet completes transmission on the
|
298 |
|
|
interface. The 'key' value must be one of the keys provided to
|
299 |
|
|
"HRDWR_send()" above. The value 'status' should be non-zero (currently
|
300 |
|
|
undefined) to indicate that an error occurred during the transmission.
|
301 |
|
|
|
302 |
|
|
void eth_drv_recv(struct eth_drv_sc *sc, int len)
|
303 |
|
|
=================================================
|
304 |
|
|
|
305 |
|
|
This function is called to indicate that a packet of length 'len' has
|
306 |
|
|
arrived at the interface. The callback "HRDWR_recv()" function
|
307 |
|
|
described above will be used to actually unload the data from the
|
308 |
|
|
interface into buffers used by the machine independent layers.
|
309 |
|
|
|
310 |
|
|
|
311 |
|
|
|
312 |
|
|
Calling graph for Transmit and Receive
|
313 |
|
|
--------------------------------------
|
314 |
|
|
|
315 |
|
|
It may be worth clarifying further the flow of control in the transmit
|
316 |
|
|
and receive cases, where the hardware driver does use interrupts and so
|
317 |
|
|
DSRs to tell the "foreground" when something asynchronous has occurred.
|
318 |
|
|
|
319 |
|
|
Transmit:
|
320 |
|
|
Foreground task calls into network stack to send a packet (or the
|
321 |
|
|
stack decides to send a packet in response to incoming traffic).
|
322 |
|
|
The driver calls the HRDWR_can_send() function in the hardware driver.
|
323 |
|
|
HRDWR_can_send() returns the number of available "slots" in which it
|
324 |
|
|
can store a pending transmit packet.
|
325 |
|
|
If it cannot send at this time, the packet is queued outside the
|
326 |
|
|
hardware driver for later; in this case, the hardware is already busy
|
327 |
|
|
transmitting, so expect an interrupt as described below for completion
|
328 |
|
|
of the packet currently outgoing.
|
329 |
|
|
If it can send right now, HRDWR_send() is called.
|
330 |
|
|
HRDWR_send() copies the data into special hardware buffers, or
|
331 |
|
|
instructs the hardware to "send that".
|
332 |
|
|
It also remembers the key that is associated with this tx request.
|
333 |
|
|
these calls return.
|
334 |
|
|
...
|
335 |
|
|
|
336 |
|
|
Asynchronously, the hardware makes an interrupt to say "transmit is
|
337 |
|
|
done"; the ISR quietens the interrupt source in the hardware and
|
338 |
|
|
requests that the associated DSR be run.
|
339 |
|
|
The DSR realizes that a transmit request has completed, and calls
|
340 |
|
|
eth_drv_tx_done() with the same key that it remembered for this tx.
|
341 |
|
|
eth_drv_tx_done() uses the key to find the resources associated with
|
342 |
|
|
this transmit request; thus the stack knows that the transmit has
|
343 |
|
|
completed and its resources can be freed.
|
344 |
|
|
eth_drv_tx_done() also enquires whether HRDWR_can_send() now says
|
345 |
|
|
"yes, we can send" and if so, dequeues a further transmit request
|
346 |
|
|
which may have been queued as described above. If so:
|
347 |
|
|
HRDWR_send() copies the data into the hardware buffers, or
|
348 |
|
|
instructs the hardware to "send that" and remembers the new key.
|
349 |
|
|
these calls return to the DSR and thus to the foreground.
|
350 |
|
|
...
|
351 |
|
|
|
352 |
|
|
|
353 |
|
|
Receive:
|
354 |
|
|
...
|
355 |
|
|
|
356 |
|
|
Asynchronously, the hardware makes an interrupt to say "there is ready
|
357 |
|
|
data in a receive buffer"; the ISR quietens the interrupt source in
|
358 |
|
|
the hardware and requests that the associated DSR be run.
|
359 |
|
|
The DSR realizes that there is data ready and calls eth_drv_recv()
|
360 |
|
|
with the length of the data that is available.
|
361 |
|
|
eth_drv_recv() prepares a set of scatter-gather buffers that can
|
362 |
|
|
accommodate that data.
|
363 |
|
|
It then calls back into the hardware driver routine HRDWR_recv().
|
364 |
|
|
HRDWR_recv() must copy the data from the hardware's buffers into
|
365 |
|
|
the scatter-gather buffers provided, and return.
|
366 |
|
|
eth_drv_recv() sends the new packet up the network stack and returns.
|
367 |
|
|
Back in the DSR now, the driver cleans the receive buffer and returns
|
368 |
|
|
it to the hardware's control, available to receive another packet from
|
369 |
|
|
the network.
|
370 |
|
|
The DSR returns to the foreground.
|
371 |
|
|
...
|
372 |
|
|
|
373 |
|
|
|