1 /*
2 ** File: dp.c Version 1.01, Oct. 17, 2007
3 ** Original: eth.c Version 1.00, Jan. 14, 1997
4 **
5 ** Author: Giovanni Falzoni <gfalzoni@inwind.it>
6 **
7 ** This file contains the ethernet device driver main task.
8 ** It has to be integrated with the board specific drivers.
9 ** It is a rewriting of Minix 2.0.0 ethernet driver (dp8390.c)
10 ** to remove bord specific code. It should operate (I hope)
11 ** with any board driver.
12 */
13
14 #include <minix/drivers.h>
15 #include <minix/netdriver.h>
16 #include <minix/endpoint.h>
17 #include <sys/mman.h>
18 #include <assert.h>
19
20 #include "dp.h"
21
22 /*
23 ** Local data
24 */
25 static dpeth_t de_state;
26
27 typedef struct dp_conf { /* Configuration description structure */
28 port_t dpc_port;
29 int dpc_irq;
30 phys_bytes dpc_mem;
31 } dp_conf_t;
32
33 /* Device default configuration */
34 #define DP_CONF_NR 3
35 static dp_conf_t dp_conf[DP_CONF_NR] = {
36 /* I/O port, IRQ, Buff addr, Env. var */
37 { 0x300, 5, 0xC8000, },
38 { 0x280, 10, 0xCC000, },
39 { 0x000, 0, 0x00000, },
40 };
41
42 static int do_init(unsigned int instance, netdriver_addr_t *addr,
43 uint32_t *caps, unsigned int *ticks);
44 static void do_stop(void);
45 static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
46 unsigned int mcast_count);
47 static int do_send(struct netdriver_data *data, size_t size);
48 static ssize_t do_recv(struct netdriver_data *data, size_t max);
49 static void do_intr(unsigned int mask);
50 static void do_tick(void);
51 static void do_other(const message *m_ptr, int ipc_status);
52
53 static const struct netdriver dp_table = {
54 .ndr_name = "dpe",
55 .ndr_init = do_init,
56 .ndr_stop = do_stop,
57 .ndr_set_mode = do_set_mode,
58 .ndr_recv = do_recv,
59 .ndr_send = do_send,
60 .ndr_intr = do_intr,
61 .ndr_tick = do_tick,
62 .ndr_other = do_other
63 };
64
65 /*
66 ** Name: update_conf
67 ** Function: Gets the default settings from 'dp_conf' table and
68 ** modifies them from the environment.
69 */
update_conf(dpeth_t * dep,const dp_conf_t * dcp,unsigned int instance)70 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp,
71 unsigned int instance)
72 {
73 static char dpc_fmt[] = "x:d:x";
74 char ec_key[16];
75 long val;
76
77 strlcpy(ec_key, "DPETH0", sizeof(ec_key));
78 ec_key[5] += instance;
79
80 val = dcp->dpc_port; /* Get I/O port address */
81 env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL);
82 dep->de_base_port = val;
83
84 val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
85 env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
86 dep->de_irq = val;
87
88 val = dcp->dpc_mem; /* Get shared memory address */
89 env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
90 dep->de_linmem = val;
91 }
92
93 /*
94 ** Name: do_dump
95 ** Function: Displays statistics on screen (SFx key from console)
96 */
do_dump(void)97 static void do_dump(void)
98 {
99 dpeth_t *dep;
100
101 dep = &de_state;
102
103 printf("\n\n");
104
105 printf("%s statistics:\t\t", netdriver_name());
106
107 /* Network interface status */
108 printf("Status: 0x%04x\n\n", dep->de_flags);
109
110 (*dep->de_dumpstatsf)(dep);
111
112 /* Transmitted/received bytes */
113 printf("Tx bytes:%10ld\t", dep->bytes_Tx);
114 printf("Rx bytes:%10ld\n", dep->bytes_Rx);
115 }
116
117 /*
118 ** Name: do_first_init
119 ** Function: Init action to setup task
120 */
do_first_init(dpeth_t * dep,const dp_conf_t * dcp)121 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
122 {
123
124 dep->de_linmem = 0xFFFF0000; /* FIXME: this overrides update_conf, why? */
125
126 /* Device specific initialization */
127 (*dep->de_initf)(dep);
128
129 /* Map memory if requested */
130 if (dep->de_linmem != 0) {
131 assert(dep->de_ramsize > 0);
132 dep->de_locmem =
133 vm_map_phys(SELF, (void *)dep->de_linmem, dep->de_ramsize);
134 if (dep->de_locmem == MAP_FAILED)
135 panic("unable to map memory");
136 }
137
138 /* Set the interrupt handler policy. Request interrupts not to be reenabled
139 * automatically. Return the IRQ line number when an interrupt occurs.
140 */
141 dep->de_hook = dep->de_irq;
142 if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
143 panic("unable to set IRQ policy");
144 sys_irqenable(&dep->de_hook);
145 }
146
147 /*
148 ** Name: do_init
149 ** Function: Checks for hardware presence.
150 ** Initialize hardware and data structures.
151 ** Return status and ethernet address.
152 */
do_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)153 static int do_init(unsigned int instance, netdriver_addr_t *addr,
154 uint32_t *caps, unsigned int *ticks)
155 {
156 dpeth_t *dep;
157 dp_conf_t *dcp;
158 int confnr, fkeys, sfkeys;
159
160 dep = &de_state;
161
162 /* Pick a default configuration for this instance. */
163 confnr = MIN(instance, DP_CONF_NR-1);
164
165 dcp = &dp_conf[confnr];
166
167 update_conf(dep, dcp, instance);
168
169 if (!el1_probe(dep) && /* Probe for 3c501 */
170 !wdeth_probe(dep) && /* Probe for WD80x3 */
171 !ne_probe(dep) && /* Probe for NEx000 */
172 !el2_probe(dep) && /* Probe for 3c503 */
173 !el3_probe(dep)) { /* Probe for 3c509 */
174 printf("%s: warning no ethernet card found at 0x%04X\n",
175 netdriver_name(), dep->de_base_port);
176 return ENXIO;
177 }
178
179 do_first_init(dep, dcp);
180
181 /* Request function key for debug dumps */
182 fkeys = sfkeys = 0; bit_set(sfkeys, 7);
183 if (fkey_map(&fkeys, &sfkeys) != OK)
184 printf("%s: couldn't bind Shift+F7 key (%d)\n",
185 netdriver_name(), errno);
186
187 memcpy(addr, dep->de_address.na_addr, sizeof(*addr));
188 *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST; /* ..is this even accurate? */
189 *ticks = sys_hz(); /* update statistics once a second */
190 return OK;
191 }
192
193 /*
194 ** Name: de_set_mode
195 ** Function: Sets packet receipt mode.
196 */
do_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)197 static void do_set_mode(unsigned int mode,
198 const netdriver_addr_t * mcast_list __unused,
199 unsigned int mcast_count __unused)
200 {
201 dpeth_t *dep;
202
203 dep = &de_state;
204
205 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
206 if (mode & NDEV_MODE_PROMISC)
207 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
208 if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
209 dep->de_flags |= DEF_MULTI;
210 if (mode & NDEV_MODE_BCAST)
211 dep->de_flags |= DEF_BROAD;
212 (*dep->de_flagsf)(dep);
213 }
214
215 /*
216 ** Name: do_send
217 ** Function: Send a packet, if possible.
218 */
do_send(struct netdriver_data * data,size_t size)219 static int do_send(struct netdriver_data *data, size_t size)
220 {
221 dpeth_t *dep;
222
223 dep = &de_state;
224
225 return (*dep->de_sendf)(dep, data, size);
226 }
227
228 /*
229 ** Name: do_recv
230 ** Function: Receive a packet, if possible.
231 */
do_recv(struct netdriver_data * data,size_t max)232 static ssize_t do_recv(struct netdriver_data *data, size_t max)
233 {
234 dpeth_t *dep;
235
236 dep = &de_state;
237
238 return (*dep->de_recvf)(dep, data, max);
239 }
240
241 /*
242 ** Name: do_stop
243 ** Function: Stops network interface.
244 */
do_stop(void)245 static void do_stop(void)
246 {
247 dpeth_t *dep;
248
249 dep = &de_state;
250
251 /* Stop device */
252 (dep->de_stopf)(dep);
253 }
254
255 /*
256 ** Name: do_intr
257 ** Function; Handles interrupts.
258 */
do_intr(unsigned int __unused mask)259 static void do_intr(unsigned int __unused mask)
260 {
261 dpeth_t *dep;
262
263 dep = &de_state;
264
265 /* If device is enabled and interrupt pending */
266 (*dep->de_interruptf)(dep);
267 sys_irqenable(&dep->de_hook);
268 }
269
270 /*
271 ** Name: do_tick
272 ** Function: perform regular processing.
273 */
do_tick(void)274 static void do_tick(void)
275 {
276 dpeth_t *dep;
277
278 dep = &de_state;
279
280 if (dep->de_getstatsf != NULL)
281 (*dep->de_getstatsf)(dep);
282 }
283
284 /*
285 ** Name: do_other
286 ** Function: Processes miscellaneous messages.
287 */
do_other(const message * m_ptr,int ipc_status)288 static void do_other(const message *m_ptr, int ipc_status)
289 {
290
291 if (is_ipc_notify(ipc_status) && m_ptr->m_source == TTY_PROC_NR)
292 do_dump();
293 }
294
295 /*
296 ** Name: main
297 ** Function: Main entry for dp task
298 */
main(int argc,char ** argv)299 int main(int argc, char **argv)
300 {
301
302 env_setargs(argc, argv);
303
304 netdriver_task(&dp_table);
305
306 return 0;
307 }
308