custom message type for VM_INFO
[minix3.git] / drivers / dpeth / dp.c
blob9ed770fcdf898c45c90d867152da45b8a9fc1175
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.
14 #include <minix/drivers.h>
15 #include <minix/netdriver.h>
16 #include <minix/endpoint.h>
17 #include <minix/ds.h>
18 #include <net/gen/ether.h>
19 #include <net/gen/eth_io.h>
21 #include "dp.h"
24 ** Local data
26 static dpeth_t de_state;
27 static int de_instance;
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;
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, },
44 static char CopyErrMsg[] = "unable to read/write user data";
45 static char RecvErrMsg[] = "netdriver_receive failed";
46 static char SendErrMsg[] = "send failed";
47 static char SizeErrMsg[] = "illegal packet size";
48 static char TypeErrMsg[] = "illegal message type";
49 static char DevName[] = "eth#?";
52 ** Name: void reply(dpeth_t *dep, int err, int m_type)
53 ** Function: Fills a reply message and sends it.
55 static void reply(dpeth_t * dep)
57 message reply;
58 int r, flags;
60 flags = DL_NOFLAGS;
61 if (dep->de_flags & DEF_ACK_SEND) flags |= DL_PACK_SEND;
62 if (dep->de_flags & DEF_ACK_RECV) flags |= DL_PACK_RECV;
64 reply.m_type = DL_TASK_REPLY;
65 reply.m_netdrv_net_dl_task.flags = flags;
66 reply.m_netdrv_net_dl_task.count = dep->de_read_s;
68 DEBUG(printf("\t reply %d (%lx)\n", reply.m_type,
69 reply.m_netdrv_net_dl_task.flags));
71 if ((r = ipc_send(dep->de_client, &reply)) != OK)
72 panic(SendErrMsg, r);
74 dep->de_read_s = 0;
75 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
77 return;
81 ** Name: void dp_confaddr(dpeth_t *dep)
82 ** Function: Checks environment for a User defined ethernet address.
84 static void dp_confaddr(dpeth_t * dep)
86 static char ea_fmt[] = "x:x:x:x:x:x";
87 char ea_key[16];
88 int ix;
89 long val;
91 strlcpy(ea_key, "DPETH0_EA", sizeof(ea_key));
92 ea_key[5] += de_instance;
94 for (ix = 0; ix < SA_ADDR_LEN; ix++) {
95 val = dep->de_address.ea_addr[ix];
96 if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
97 break;
98 dep->de_address.ea_addr[ix] = val;
101 if (ix != 0 && ix != SA_ADDR_LEN)
102 /* It's all or nothing, force a panic */
103 env_parse(ea_key, "?", 0, &val, 0L, 0L);
104 return;
108 ** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
109 ** Function: Gets the default settings from 'dp_conf' table and
110 ** modifies them from the environment.
112 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp)
114 static char dpc_fmt[] = "x:d:x";
115 char ec_key[16];
116 long val;
118 strlcpy(ec_key, "DPETH0", sizeof(ec_key));
119 ec_key[5] += de_instance;
121 dep->de_mode = DEM_SINK;
122 val = dcp->dpc_port; /* Get I/O port address */
123 switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
124 case EP_OFF: dep->de_mode = DEM_DISABLED; break;
125 case EP_ON:
126 case EP_SET: dep->de_mode = DEM_ENABLED; break;
128 dep->de_base_port = val;
130 val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
131 env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
132 dep->de_irq = val;
134 val = dcp->dpc_mem; /* Get shared memory address */
135 env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
136 dep->de_linmem = val;
138 return;
142 ** Name: void do_dump(message *mp)
143 ** Function: Displays statistics on screen (SFx key from console)
145 static void do_dump(const message *mp)
147 dpeth_t *dep;
149 dep = &de_state;
151 printf("\n\n");
153 if (dep->de_mode == DEM_DISABLED) return;
155 printf("%s statistics:\t\t", dep->de_name);
157 /* Network interface status */
158 printf("Status: 0x%04x (%d)\n\n", dep->de_flags, dep->de_int_pending);
160 (*dep->de_dumpstatsf) (dep);
162 /* Transmitted/received bytes */
163 printf("Tx bytes:%10ld\t", dep->bytes_Tx);
164 printf("Rx bytes:%10ld\n", dep->bytes_Rx);
166 /* Transmitted/received packets */
167 printf("Tx OK: %8ld\t", dep->de_stat.ets_packetT);
168 printf("Rx OK: %8ld\n", dep->de_stat.ets_packetR);
170 /* Transmit/receive errors */
171 printf("Tx Err: %8ld\t", dep->de_stat.ets_sendErr);
172 printf("Rx Err: %8ld\n", dep->de_stat.ets_recvErr);
174 /* Transmit unnerruns/receive overrruns */
175 printf("Tx Und: %8ld\t", dep->de_stat.ets_fifoUnder);
176 printf("Rx Ovr: %8ld\n", dep->de_stat.ets_fifoOver);
178 /* Transmit collisions/receive CRC errors */
179 printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision);
180 printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr);
182 return;
186 ** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
187 ** Function: Copies data from user area.
189 static void get_userdata_s(int user_proc, cp_grant_id_t grant,
190 vir_bytes offset, int count, void *loc_addr)
192 int rc;
193 vir_bytes len;
195 len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
196 if ((rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len)) != OK)
197 panic(CopyErrMsg, rc);
198 return;
202 ** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
203 ** Function: Init action to setup task
205 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
208 dep->de_linmem = 0xFFFF0000;
210 /* Make sure statisics are cleared */
211 memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t));
213 /* Device specific initialization */
214 (*dep->de_initf) (dep);
216 /* Set the interrupt handler policy. Request interrupts not to be reenabled
217 * automatically. Return the IRQ line number when an interrupt occurs.
219 dep->de_hook = dep->de_irq;
220 if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
221 panic("unable to set IRQ policy");
222 dep->de_int_pending = FALSE;
223 sys_irqenable(&dep->de_hook);
225 return;
229 ** Name: void do_init(message *mp)
230 ** Function: Checks for hardware presence.
231 ** Provides initialization of hardware and data structures
233 static void do_init(const message * mp)
235 dpeth_t *dep;
236 dp_conf_t *dcp;
237 message reply_mess;
238 int r, confnr;
240 dep = &de_state;
242 /* Pick a default configuration for this instance. */
243 confnr = MIN(de_instance, DP_CONF_NR-1);
245 dcp = &dp_conf[confnr];
246 strlcpy(dep->de_name, DevName, sizeof(dep->de_name));
247 dep->de_name[4] = '0' + de_instance;
249 if (dep->de_mode == DEM_DISABLED) {
251 update_conf(dep, dcp); /* First time thru */
252 if (dep->de_mode == DEM_ENABLED &&
253 !el1_probe(dep) && /* Probe for 3c501 */
254 !wdeth_probe(dep) && /* Probe for WD80x3 */
255 !ne_probe(dep) && /* Probe for NEx000 */
256 !el2_probe(dep) && /* Probe for 3c503 */
257 !el3_probe(dep)) { /* Probe for 3c509 */
258 printf("%s: warning no ethernet card found at 0x%04X\n",
259 dep->de_name, dep->de_base_port);
260 dep->de_mode = DEM_DISABLED;
264 r = OK;
266 /* 'de_mode' may change if probe routines fail, test again */
267 switch (dep->de_mode) {
269 case DEM_DISABLED:
270 /* Device is configured OFF or hardware probe failed */
271 r = ENXIO;
272 break;
274 case DEM_ENABLED:
275 /* Device is present and probed */
276 if (dep->de_flags == DEF_EMPTY) {
277 /* These actions only the first time */
278 do_first_init(dep, dcp);
279 dep->de_flags |= DEF_ENABLED;
281 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
282 if (mp->m_net_netdrv_dl_conf.mode & DL_PROMISC_REQ)
283 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
284 if (mp->m_net_netdrv_dl_conf.mode & DL_MULTI_REQ)
285 dep->de_flags |= DEF_MULTI;
286 if (mp->m_net_netdrv_dl_conf.mode & DL_BROAD_REQ)
287 dep->de_flags |= DEF_BROAD;
288 (*dep->de_flagsf) (dep);
289 break;
291 case DEM_SINK:
292 /* Device not present (sink mode) */
293 memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
294 dp_confaddr(dep); /* Station address from env. */
295 break;
297 default: break;
300 reply_mess.m_type = DL_CONF_REPLY;
301 reply_mess.m_netdrv_net_dl_conf.stat = r;
302 if (r == OK)
303 memcpy(reply_mess.m_netdrv_net_dl_conf.hw_addr, dep->de_address.ea_addr,
304 sizeof(reply_mess.m_netdrv_net_dl_conf.hw_addr));
305 DEBUG(printf("\t reply %d\n", reply_mess.m_type));
306 if (ipc_send(mp->m_source, &reply_mess) != OK) /* Can't send */
307 panic(SendErrMsg, mp->m_source);
309 return;
313 ** Name: void dp_next_iovec(iovec_dat_t *iovp)
314 ** Function: Retrieves data from next iovec element.
316 void dp_next_iovec(iovec_dat_s_t * iovp)
319 iovp->iod_iovec_s -= IOVEC_NR;
320 iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
321 get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
322 iovp->iod_iovec_s, iovp->iod_iovec);
323 return;
327 ** Name: int calc_iovec_size(iovec_dat_t *iovp)
328 ** Function: Compute the size of a request.
330 static int calc_iovec_size(iovec_dat_s_t * iovp)
332 int size, ix;
334 size = ix = 0;
335 do {
336 size += iovp->iod_iovec[ix].iov_size;
337 if (++ix >= IOVEC_NR) {
338 dp_next_iovec(iovp);
339 ix = 0;
342 /* Till all vectors added */
343 } while (ix < iovp->iod_iovec_s);
344 return size;
348 ** Name: void do_vwrite_s(message *mp)
349 ** Function:
351 static void do_vwrite_s(const message * mp)
353 int size;
354 dpeth_t *dep;
356 dep = &de_state;
358 dep->de_client = mp->m_source;
360 if (dep->de_mode == DEM_ENABLED) {
362 if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */
363 panic("send already in progress ");
365 dep->de_write_iovec.iod_proc_nr = mp->m_source;
366 get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_writev_s.grant, 0,
367 mp->m_net_netdrv_dl_writev_s.count, dep->de_write_iovec.iod_iovec);
368 dep->de_write_iovec.iod_iovec_s = mp->m_net_netdrv_dl_writev_s.count;
369 dep->de_write_iovec.iod_grant = mp->m_net_netdrv_dl_writev_s.grant;
370 dep->de_write_iovec.iod_iovec_offset = 0;
371 size = calc_iovec_size(&dep->de_write_iovec);
372 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
373 panic(SizeErrMsg, size);
375 dep->de_flags |= DEF_SENDING;
376 (*dep->de_sendf) (dep, FALSE, size);
378 } else if (dep->de_mode == DEM_SINK)
379 dep->de_flags |= DEF_ACK_SEND;
381 reply(dep);
382 return;
386 ** Name: void do_vread_s(message *mp, int vectored)
387 ** Function:
389 static void do_vread_s(const message * mp)
391 int size;
392 dpeth_t *dep;
394 dep = &de_state;
396 dep->de_client = mp->m_source;
398 if (dep->de_mode == DEM_ENABLED) {
400 if (dep->de_flags & DEF_READING) /* Reading in progress */
401 panic("read already in progress");
403 dep->de_read_iovec.iod_proc_nr = mp->m_source;
404 get_userdata_s(mp->m_source, mp->m_net_netdrv_dl_readv_s.grant, 0,
405 mp->m_net_netdrv_dl_readv_s.count, dep->de_read_iovec.iod_iovec);
406 dep->de_read_iovec.iod_iovec_s = mp->m_net_netdrv_dl_readv_s.count;
407 dep->de_read_iovec.iod_grant = mp->m_net_netdrv_dl_readv_s.grant;
408 dep->de_read_iovec.iod_iovec_offset = 0;
409 size = calc_iovec_size(&dep->de_read_iovec);
410 if (size < ETH_MAX_PACK_SIZE) panic(SizeErrMsg, size);
412 dep->de_flags |= DEF_READING;
413 (*dep->de_recvf) (dep, FALSE, size);
414 #if 0
415 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
416 /* The chip is stopped, and all arrived packets delivered */
417 (*dep->de_resetf) (dep);
418 dep->de_flags &= NOT(DEF_STOPPED);
419 #endif
421 reply(dep);
422 return;
426 ** Name: void do_getstat_s(message *mp)
427 ** Function: Reports device statistics.
429 static void do_getstat_s(const message * mp)
431 int rc;
432 dpeth_t *dep;
433 message reply_mess;
435 dep = &de_state;
437 if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
438 if ((rc = sys_safecopyto(mp->m_source, mp->m_net_netdrv_dl_getstat_s.grant, 0,
439 (vir_bytes)&dep->de_stat,
440 (vir_bytes)sizeof(dep->de_stat))) != OK)
441 panic(CopyErrMsg, rc);
443 reply_mess.m_type = DL_STAT_REPLY;
444 rc= ipc_send(mp->m_source, &reply_mess);
445 if (rc != OK)
446 panic("do_getname: ipc_send failed: %d", rc);
447 return;
451 ** Name: void dp_stop(dpeth_t *dep)
452 ** Function: Stops network interface.
454 static void dp_stop(dpeth_t * dep)
457 if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) {
459 /* Stop device */
460 (dep->de_stopf) (dep);
461 dep->de_flags = DEF_EMPTY;
462 dep->de_mode = DEM_DISABLED;
464 return;
467 static void do_watchdog(const void *UNUSED(message))
470 DEBUG(printf("\t no reply"));
471 return;
474 static void handle_hw_intr(void)
476 dpeth_t *dep;
478 dep = &de_state;
480 /* If device is enabled and interrupt pending */
481 if (dep->de_mode == DEM_ENABLED) {
482 dep->de_int_pending = TRUE;
483 (*dep->de_interruptf) (dep);
484 if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
485 reply(dep);
486 dep->de_int_pending = FALSE;
487 sys_irqenable(&dep->de_hook);
491 /* SEF functions and variables. */
492 static void sef_local_startup(void);
493 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
494 static void sef_cb_signal_handler(int signo);
497 ** Name: int dpeth_task(void)
498 ** Function: Main entry for dp task
500 int main(int argc, char **argv)
502 message m;
503 int ipc_status;
504 int rc;
506 /* SEF local startup. */
507 env_setargs(argc, argv);
508 sef_local_startup();
510 while (TRUE) {
511 if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){
512 panic(RecvErrMsg, rc);
515 DEBUG(printf("eth: got message %d, ", m.m_type));
517 if (is_ipc_notify(ipc_status)) {
518 switch(_ENDPOINT_P(m.m_source)) {
519 case CLOCK:
520 /* to be defined */
521 do_watchdog(&m);
522 break;
523 case HARDWARE:
524 /* Interrupt from device */
525 handle_hw_intr();
526 break;
527 case TTY_PROC_NR:
528 /* Function key pressed */
529 do_dump(&m);
530 break;
531 default:
532 /* Invalid message type */
533 panic(TypeErrMsg, m.m_type);
534 break;
536 /* message processed, get another one */
537 continue;
540 switch (m.m_type) {
541 case DL_WRITEV_S: /* Write message to device */
542 do_vwrite_s(&m);
543 break;
544 case DL_READV_S: /* Read message from device */
545 do_vread_s(&m);
546 break;
547 case DL_CONF: /* Initialize device */
548 do_init(&m);
549 break;
550 case DL_GETSTAT_S: /* Get device statistics */
551 do_getstat_s(&m);
552 break;
553 default: /* Invalid message type */
554 panic(TypeErrMsg, m.m_type);
555 break;
558 return OK; /* Never reached, but keeps compiler happy */
561 /*===========================================================================*
562 * sef_local_startup *
563 *===========================================================================*/
564 static void sef_local_startup()
566 /* Register init callbacks. */
567 sef_setcb_init_fresh(sef_cb_init_fresh);
568 sef_setcb_init_lu(sef_cb_init_fresh);
569 sef_setcb_init_restart(sef_cb_init_fresh);
571 /* Register live update callbacks. */
572 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
573 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
575 /* Register signal callbacks. */
576 sef_setcb_signal_handler(sef_cb_signal_handler);
578 /* Let SEF perform startup. */
579 sef_startup();
582 /*===========================================================================*
583 * sef_cb_init_fresh *
584 *===========================================================================*/
585 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
587 /* Initialize the dpeth driver. */
588 int fkeys, sfkeys;
589 long v;
591 /* Request function key for debug dumps */
592 fkeys = sfkeys = 0; bit_set(sfkeys, 8);
593 if ((fkey_map(&fkeys, &sfkeys)) != OK)
594 printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno);
596 v = 0;
597 (void) env_parse("instance", "d", 0, &v, 0, 255);
598 de_instance = (int) v;
600 /* Announce we are up! */
601 netdriver_announce();
603 return(OK);
606 /*===========================================================================*
607 * sef_cb_signal_handler *
608 *===========================================================================*/
609 static void sef_cb_signal_handler(int signo)
611 /* Only check for termination signal, ignore anything else. */
612 if (signo != SIGTERM) return;
614 if (de_state.de_mode == DEM_ENABLED)
615 dp_stop(&de_state);
617 exit(0);
620 /** dp.c **/