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