kernel: kill proc with bogus ipc address
[minix.git] / drivers / dpeth / dp.c
blob818d3d181980d54aab022d076739b3c0664146aa
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.DL_FLAGS = flags;
66 reply.DL_COUNT = dep->de_read_s;
68 DEBUG(printf("\t reply %d (%lx)\n", reply.m_type, reply.DL_FLAGS));
70 if ((r = send(dep->de_client, &reply)) != OK)
71 panic(SendErrMsg, r);
73 dep->de_read_s = 0;
74 dep->de_flags &= NOT(DEF_ACK_SEND | DEF_ACK_RECV);
76 return;
80 ** Name: void dp_confaddr(dpeth_t *dep)
81 ** Function: Checks environment for a User defined ethernet address.
83 static void dp_confaddr(dpeth_t * dep)
85 static char ea_fmt[] = "x:x:x:x:x:x";
86 char ea_key[16];
87 int ix;
88 long val;
90 strlcpy(ea_key, "DPETH0_EA", sizeof(ea_key));
91 ea_key[5] += de_instance;
93 for (ix = 0; ix < SA_ADDR_LEN; ix++) {
94 val = dep->de_address.ea_addr[ix];
95 if (env_parse(ea_key, ea_fmt, ix, &val, 0x00L, 0xFFL) != EP_SET)
96 break;
97 dep->de_address.ea_addr[ix] = val;
100 if (ix != 0 && ix != SA_ADDR_LEN)
101 /* It's all or nothing, force a panic */
102 env_parse(ea_key, "?", 0, &val, 0L, 0L);
103 return;
107 ** Name: void update_conf(dpeth_t *dep, dp_conf_t *dcp)
108 ** Function: Gets the default settings from 'dp_conf' table and
109 ** modifies them from the environment.
111 static void update_conf(dpeth_t * dep, const dp_conf_t * dcp)
113 static char dpc_fmt[] = "x:d:x";
114 char ec_key[16];
115 long val;
117 strlcpy(ec_key, "DPETH0", sizeof(ec_key));
118 ec_key[5] += de_instance;
120 dep->de_mode = DEM_SINK;
121 val = dcp->dpc_port; /* Get I/O port address */
122 switch (env_parse(ec_key, dpc_fmt, 0, &val, 0x000L, 0x3FFL)) {
123 case EP_OFF: dep->de_mode = DEM_DISABLED; break;
124 case EP_ON:
125 case EP_SET: dep->de_mode = DEM_ENABLED; break;
127 dep->de_base_port = val;
129 val = dcp->dpc_irq | DEI_DEFAULT; /* Get Interrupt line (IRQ) */
130 env_parse(ec_key, dpc_fmt, 1, &val, 0L, (long) NR_IRQ_VECTORS - 1);
131 dep->de_irq = val;
133 val = dcp->dpc_mem; /* Get shared memory address */
134 env_parse(ec_key, dpc_fmt, 2, &val, 0L, LONG_MAX);
135 dep->de_linmem = val;
137 return;
141 ** Name: void do_dump(message *mp)
142 ** Function: Displays statistics on screen (SFx key from console)
144 static void do_dump(const message *mp)
146 dpeth_t *dep;
148 dep = &de_state;
150 printf("\n\n");
152 if (dep->de_mode == DEM_DISABLED) return;
154 printf("%s statistics:\t\t", dep->de_name);
156 /* Network interface status */
157 printf("Status: 0x%04x (%d)\n\n", dep->de_flags, dep->de_int_pending);
159 (*dep->de_dumpstatsf) (dep);
161 /* Transmitted/received bytes */
162 printf("Tx bytes:%10ld\t", dep->bytes_Tx);
163 printf("Rx bytes:%10ld\n", dep->bytes_Rx);
165 /* Transmitted/received packets */
166 printf("Tx OK: %8ld\t", dep->de_stat.ets_packetT);
167 printf("Rx OK: %8ld\n", dep->de_stat.ets_packetR);
169 /* Transmit/receive errors */
170 printf("Tx Err: %8ld\t", dep->de_stat.ets_sendErr);
171 printf("Rx Err: %8ld\n", dep->de_stat.ets_recvErr);
173 /* Transmit unnerruns/receive overrruns */
174 printf("Tx Und: %8ld\t", dep->de_stat.ets_fifoUnder);
175 printf("Rx Ovr: %8ld\n", dep->de_stat.ets_fifoOver);
177 /* Transmit collisions/receive CRC errors */
178 printf("Tx Coll: %8ld\t", dep->de_stat.ets_collision);
179 printf("Rx CRC: %8ld\n", dep->de_stat.ets_CRCerr);
181 return;
185 ** Name: void get_userdata_s(int user_proc, vir_bytes user_addr, int count, void *loc_addr)
186 ** Function: Copies data from user area.
188 static void get_userdata_s(int user_proc, cp_grant_id_t grant,
189 vir_bytes offset, int count, void *loc_addr)
191 int rc;
192 vir_bytes len;
194 len = (count > IOVEC_NR ? IOVEC_NR : count) * sizeof(iovec_t);
195 if ((rc = sys_safecopyfrom(user_proc, grant, 0, (vir_bytes)loc_addr, len)) != OK)
196 panic(CopyErrMsg, rc);
197 return;
201 ** Name: void do_first_init(dpeth_t *dep, dp_conf_t *dcp);
202 ** Function: Init action to setup task
204 static void do_first_init(dpeth_t *dep, const dp_conf_t *dcp)
207 dep->de_linmem = 0xFFFF0000;
209 /* Make sure statisics are cleared */
210 memset((void *) &(dep->de_stat), 0, sizeof(eth_stat_t));
212 /* Device specific initialization */
213 (*dep->de_initf) (dep);
215 /* Set the interrupt handler policy. Request interrupts not to be reenabled
216 * automatically. Return the IRQ line number when an interrupt occurs.
218 dep->de_hook = dep->de_irq;
219 if (sys_irqsetpolicy(dep->de_irq, 0 /*IRQ_REENABLE*/, &dep->de_hook) != OK)
220 panic("unable to set IRQ policy");
221 dep->de_int_pending = FALSE;
222 sys_irqenable(&dep->de_hook);
224 return;
228 ** Name: void do_init(message *mp)
229 ** Function: Checks for hardware presence.
230 ** Provides initialization of hardware and data structures
232 static void do_init(const message * mp)
234 dpeth_t *dep;
235 dp_conf_t *dcp;
236 message reply_mess;
237 int r, confnr;
239 dep = &de_state;
241 /* Pick a default configuration for this instance. */
242 confnr = MIN(de_instance, DP_CONF_NR-1);
244 dcp = &dp_conf[confnr];
245 strlcpy(dep->de_name, DevName, sizeof(dep->de_name));
246 dep->de_name[4] = '0' + de_instance;
248 if (dep->de_mode == DEM_DISABLED) {
250 update_conf(dep, dcp); /* First time thru */
251 if (dep->de_mode == DEM_ENABLED &&
252 !el1_probe(dep) && /* Probe for 3c501 */
253 !wdeth_probe(dep) && /* Probe for WD80x3 */
254 !ne_probe(dep) && /* Probe for NEx000 */
255 !el2_probe(dep) && /* Probe for 3c503 */
256 !el3_probe(dep)) { /* Probe for 3c509 */
257 printf("%s: warning no ethernet card found at 0x%04X\n",
258 dep->de_name, dep->de_base_port);
259 dep->de_mode = DEM_DISABLED;
263 r = OK;
265 /* 'de_mode' may change if probe routines fail, test again */
266 switch (dep->de_mode) {
268 case DEM_DISABLED:
269 /* Device is configured OFF or hardware probe failed */
270 r = ENXIO;
271 break;
273 case DEM_ENABLED:
274 /* Device is present and probed */
275 if (dep->de_flags == DEF_EMPTY) {
276 /* These actions only the first time */
277 do_first_init(dep, dcp);
278 dep->de_flags |= DEF_ENABLED;
280 dep->de_flags &= NOT(DEF_PROMISC | DEF_MULTI | DEF_BROAD);
281 if (mp->DL_MODE & DL_PROMISC_REQ)
282 dep->de_flags |= DEF_PROMISC | DEF_MULTI | DEF_BROAD;
283 if (mp->DL_MODE & DL_MULTI_REQ) dep->de_flags |= DEF_MULTI;
284 if (mp->DL_MODE & DL_BROAD_REQ) dep->de_flags |= DEF_BROAD;
285 (*dep->de_flagsf) (dep);
286 break;
288 case DEM_SINK:
289 /* Device not present (sink mode) */
290 memset(dep->de_address.ea_addr, 0, sizeof(ether_addr_t));
291 dp_confaddr(dep); /* Station address from env. */
292 break;
294 default: break;
297 reply_mess.m_type = DL_CONF_REPLY;
298 reply_mess.DL_STAT = r;
299 if (r == OK)
300 *(ether_addr_t *) reply_mess.DL_HWADDR = dep->de_address;
301 DEBUG(printf("\t reply %d\n", reply_mess.m_type));
302 if (send(mp->m_source, &reply_mess) != OK) /* Can't send */
303 panic(SendErrMsg, mp->m_source);
305 return;
309 ** Name: void dp_next_iovec(iovec_dat_t *iovp)
310 ** Function: Retrieves data from next iovec element.
312 void dp_next_iovec(iovec_dat_s_t * iovp)
315 iovp->iod_iovec_s -= IOVEC_NR;
316 iovp->iod_iovec_offset += IOVEC_NR * sizeof(iovec_t);
317 get_userdata_s(iovp->iod_proc_nr, iovp->iod_grant, iovp->iod_iovec_offset,
318 iovp->iod_iovec_s, iovp->iod_iovec);
319 return;
323 ** Name: int calc_iovec_size(iovec_dat_t *iovp)
324 ** Function: Compute the size of a request.
326 static int calc_iovec_size(iovec_dat_s_t * iovp)
328 int size, ix;
330 size = ix = 0;
331 do {
332 size += iovp->iod_iovec[ix].iov_size;
333 if (++ix >= IOVEC_NR) {
334 dp_next_iovec(iovp);
335 ix = 0;
338 /* Till all vectors added */
339 } while (ix < iovp->iod_iovec_s);
340 return size;
344 ** Name: void do_vwrite_s(message *mp)
345 ** Function:
347 static void do_vwrite_s(const message * mp)
349 int size;
350 dpeth_t *dep;
352 dep = &de_state;
354 dep->de_client = mp->m_source;
356 if (dep->de_mode == DEM_ENABLED) {
358 if (dep->de_flags & DEF_SENDING) /* Is sending in progress? */
359 panic("send already in progress ");
361 dep->de_write_iovec.iod_proc_nr = mp->m_source;
362 get_userdata_s(mp->m_source, mp->DL_GRANT, 0,
363 mp->DL_COUNT, dep->de_write_iovec.iod_iovec);
364 dep->de_write_iovec.iod_iovec_s = mp->DL_COUNT;
365 dep->de_write_iovec.iod_grant = (cp_grant_id_t) mp->DL_GRANT;
366 dep->de_write_iovec.iod_iovec_offset = 0;
367 size = calc_iovec_size(&dep->de_write_iovec);
368 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE)
369 panic(SizeErrMsg, size);
371 dep->de_flags |= DEF_SENDING;
372 (*dep->de_sendf) (dep, FALSE, size);
374 } else if (dep->de_mode == DEM_SINK)
375 dep->de_flags |= DEF_ACK_SEND;
377 reply(dep);
378 return;
382 ** Name: void do_vread_s(message *mp, int vectored)
383 ** Function:
385 static void do_vread_s(const message * mp)
387 int size;
388 dpeth_t *dep;
390 dep = &de_state;
392 dep->de_client = mp->m_source;
394 if (dep->de_mode == DEM_ENABLED) {
396 if (dep->de_flags & DEF_READING) /* Reading in progress */
397 panic("read already in progress");
399 dep->de_read_iovec.iod_proc_nr = mp->m_source;
400 get_userdata_s(mp->m_source, (cp_grant_id_t) mp->DL_GRANT, 0,
401 mp->DL_COUNT, dep->de_read_iovec.iod_iovec);
402 dep->de_read_iovec.iod_iovec_s = mp->DL_COUNT;
403 dep->de_read_iovec.iod_grant = (cp_grant_id_t) mp->DL_GRANT;
404 dep->de_read_iovec.iod_iovec_offset = 0;
405 size = calc_iovec_size(&dep->de_read_iovec);
406 if (size < ETH_MAX_PACK_SIZE) panic(SizeErrMsg, size);
408 dep->de_flags |= DEF_READING;
409 (*dep->de_recvf) (dep, FALSE, size);
410 #if 0
411 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
412 /* The chip is stopped, and all arrived packets delivered */
413 (*dep->de_resetf) (dep);
414 dep->de_flags &= NOT(DEF_STOPPED);
415 #endif
417 reply(dep);
418 return;
422 ** Name: void do_getstat_s(message *mp)
423 ** Function: Reports device statistics.
425 static void do_getstat_s(const message * mp)
427 int rc;
428 dpeth_t *dep;
429 message reply_mess;
431 dep = &de_state;
433 if (dep->de_mode == DEM_ENABLED) (*dep->de_getstatsf) (dep);
434 if ((rc = sys_safecopyto(mp->m_source, mp->DL_GRANT, 0,
435 (vir_bytes)&dep->de_stat,
436 (vir_bytes) sizeof(dep->de_stat))) != OK)
437 panic(CopyErrMsg, rc);
439 reply_mess.m_type = DL_STAT_REPLY;
440 rc= send(mp->m_source, &reply_mess);
441 if (rc != OK)
442 panic("do_getname: send failed: %d", rc);
443 return;
447 ** Name: void dp_stop(dpeth_t *dep)
448 ** Function: Stops network interface.
450 static void dp_stop(dpeth_t * dep)
453 if (dep->de_mode == DEM_ENABLED && (dep->de_flags & DEF_ENABLED)) {
455 /* Stop device */
456 (dep->de_stopf) (dep);
457 dep->de_flags = DEF_EMPTY;
458 dep->de_mode = DEM_DISABLED;
460 return;
463 static void do_watchdog(const void *UNUSED(message))
466 DEBUG(printf("\t no reply"));
467 return;
470 static void handle_hw_intr(void)
472 dpeth_t *dep;
474 dep = &de_state;
476 /* If device is enabled and interrupt pending */
477 if (dep->de_mode == DEM_ENABLED) {
478 dep->de_int_pending = TRUE;
479 (*dep->de_interruptf) (dep);
480 if (dep->de_flags & (DEF_ACK_SEND | DEF_ACK_RECV))
481 reply(dep);
482 dep->de_int_pending = FALSE;
483 sys_irqenable(&dep->de_hook);
487 /* SEF functions and variables. */
488 static void sef_local_startup(void);
489 static int sef_cb_init_fresh(int type, sef_init_info_t *info);
490 static void sef_cb_signal_handler(int signo);
493 ** Name: int dpeth_task(void)
494 ** Function: Main entry for dp task
496 int main(int argc, char **argv)
498 message m;
499 int ipc_status;
500 int rc;
502 /* SEF local startup. */
503 env_setargs(argc, argv);
504 sef_local_startup();
506 while (TRUE) {
507 if ((rc = netdriver_receive(ANY, &m, &ipc_status)) != OK){
508 panic(RecvErrMsg, rc);
511 DEBUG(printf("eth: got message %d, ", m.m_type));
513 if (is_ipc_notify(ipc_status)) {
514 switch(_ENDPOINT_P(m.m_source)) {
515 case CLOCK:
516 /* to be defined */
517 do_watchdog(&m);
518 break;
519 case HARDWARE:
520 /* Interrupt from device */
521 handle_hw_intr();
522 break;
523 case TTY_PROC_NR:
524 /* Function key pressed */
525 do_dump(&m);
526 break;
527 default:
528 /* Invalid message type */
529 panic(TypeErrMsg, m.m_type);
530 break;
532 /* message processed, get another one */
533 continue;
536 switch (m.m_type) {
537 case DL_WRITEV_S: /* Write message to device */
538 do_vwrite_s(&m);
539 break;
540 case DL_READV_S: /* Read message from device */
541 do_vread_s(&m);
542 break;
543 case DL_CONF: /* Initialize device */
544 do_init(&m);
545 break;
546 case DL_GETSTAT_S: /* Get device statistics */
547 do_getstat_s(&m);
548 break;
549 default: /* Invalid message type */
550 panic(TypeErrMsg, m.m_type);
551 break;
554 return OK; /* Never reached, but keeps compiler happy */
557 /*===========================================================================*
558 * sef_local_startup *
559 *===========================================================================*/
560 static void sef_local_startup()
562 /* Register init callbacks. */
563 sef_setcb_init_fresh(sef_cb_init_fresh);
564 sef_setcb_init_lu(sef_cb_init_fresh);
565 sef_setcb_init_restart(sef_cb_init_fresh);
567 /* Register live update callbacks. */
568 sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
569 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
571 /* Register signal callbacks. */
572 sef_setcb_signal_handler(sef_cb_signal_handler);
574 /* Let SEF perform startup. */
575 sef_startup();
578 /*===========================================================================*
579 * sef_cb_init_fresh *
580 *===========================================================================*/
581 static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info))
583 /* Initialize the dpeth driver. */
584 int fkeys, sfkeys;
585 long v;
587 /* Request function key for debug dumps */
588 fkeys = sfkeys = 0; bit_set(sfkeys, 8);
589 if ((fkey_map(&fkeys, &sfkeys)) != OK)
590 printf("%s: couldn't program Shift+F8 key (%d)\n", DevName, errno);
592 v = 0;
593 (void) env_parse("instance", "d", 0, &v, 0, 255);
594 de_instance = (int) v;
596 /* Announce we are up! */
597 netdriver_announce();
599 return(OK);
602 /*===========================================================================*
603 * sef_cb_signal_handler *
604 *===========================================================================*/
605 static void sef_cb_signal_handler(int signo)
607 /* Only check for termination signal, ignore anything else. */
608 if (signo != SIGTERM) return;
610 if (de_state.de_mode == DEM_ENABLED)
611 dp_stop(&de_state);
613 exit(0);
616 /** dp.c **/