xref: /netbsd/sys/arch/acorn32/podulebus/if_ne_pbus.c (revision c4a72b64)
1 /*	$NetBSD: if_ne_pbus.c,v 1.9 2002/10/02 03:31:59 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Mark Brinicombe of Causality Limited.
9  *
10  * EtherH code Copyright (c) 1998 Mike Pumford
11  * EtherN/EtherI code Copyright (c) 1999 Mike Pumford
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *	This product includes software developed by the NetBSD
24  *	Foundation, Inc. and its contributors.
25  * 4. Neither the name of The NetBSD Foundation nor the names of its
26  *    contributors may be used to endorse or promote products derived
27  *    from this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  */
41 
42 /*
43  * This driver uses the generic ne2000 & dp8390 IC drivers
44  *
45  * Currently supports:
46  *	ANT EtherM network slot cards
47  *	ICubed Etherlan 600 (EtherH) network slot cards
48  *      Irlam EtherN podules
49  *      Acorn EtherI podules (identical hardware to EtherN)
50  *
51  * Thanks go to Stephen Borrill for providing the EtherN card
52  * and information to program it.
53  *
54  * TO DO List for this Driver.
55  *
56  * EtherM - Needs proper media support.
57  */
58 
59 #include <sys/param.h>
60 #include <sys/device.h>
61 #include <sys/socket.h>
62 #include <sys/systm.h>
63 #include <sys/mbuf.h>
64 
65 #include <net/if.h>
66 #include <net/if_dl.h>
67 #include <net/if_ether.h>
68 #include <net/if_media.h>
69 
70 #include <machine/bus.h>
71 #include <machine/intr.h>
72 #include <machine/io.h>
73 #include <dev/ic/dp8390reg.h>
74 #include <dev/ic/dp8390var.h>
75 #include <dev/ic/ne2000reg.h>
76 #include <dev/ic/ne2000var.h>
77 #include <dev/ic/dp83905reg.h>
78 #include <dev/ic/dp83905var.h>
79 #include <dev/ic/mx98905var.h>
80 
81 #include <arch/acorn32/podulebus/podulebus.h>
82 #include <arch/acorn32/podulebus/if_ne_pbusreg.h>
83 
84 #include <dev/podulebus/podules.h>
85 
86 /*
87  * ne_pbus_softc: ne2000_softc plus podule, interrupt and bs tag info
88  */
89 struct ne_pbus_softc {
90 	struct	ne2000_softc	sc_ne2000;		/* ne2000 softc */
91 	int			sc_podule_number;
92 	podule_t		*sc_podule;
93 	struct bus_space	sc_tag;			/* Patched tag */
94 	irqhandler_t		*sc_ih;			/* Interrupt handler */
95 	struct evcnt		sc_intrcnt;		/* Interrupt count */
96 	bus_space_handle_t	sc_extrah;		/* Bus handle for any
97 							   extra registers */
98 };
99 
100 /*
101  * Attach data and prototypes for driver
102  */
103 static int  ne_pbus_probe	__P((struct device *, struct cfdata *, void *));
104 static void ne_pbus_attach	__P((struct device *, struct device *, void *));
105 
106 CFATTACH_DECL(ne_pbus, sizeof(struct ne_pbus_softc),
107     ne_pbus_probe, ne_pbus_attach, NULL, NULL);
108 
109 /*
110  * Prototypes for interface specific routines
111  */
112 static u_int8_t *em_ea		__P((struct ne_pbus_softc *sc, u_int8_t *buffer));
113 static void em_postattach	__P((struct ne_pbus_softc *sc));
114 static void eh600_postattach	__P((struct ne_pbus_softc *sc));
115 static void eh600_preattach	__P((struct ne_pbus_softc *sc));
116 static u_int8_t *eh600_ea	__P((struct ne_pbus_softc *sc, u_int8_t *buffer));
117 
118 void	eh600_init_media        __P((struct dp8390_softc *));
119 
120 void	en_postattach		__P((struct ne_pbus_softc *));
121 void	en_init_media           __P((struct dp8390_softc *));
122 
123 /*
124  * Define a structure to hold all the information required on an NE2000
125  * clone interface.
126  * We create an array of these structures to describe all the interfaces
127  * that we can handle via the MI NE2000 driver.
128  */
129 struct ne_clone {
130 	int		product;	/* podule product id */
131 	unsigned int	cookie;		/* podulebus space cookie */
132 	unsigned int	nicbase;	/* byte offset of NIC */
133 	unsigned int	nicsize;	/* size of NIC (regs) */
134 	unsigned int	asicbase;	/* byte offset of ASIC */
135 	unsigned int	asicsize;	/* size of ASIC (regs) */
136 	unsigned int    extrabase;      /* extra registers byte offset */
137 	unsigned int    extrasize;      /* size of extra registers(regs) */
138 	unsigned char	nicspace;	/* easi,fast or mod space ? */
139 	unsigned char	asicspace;	/* easi,fast or mod space ? */
140 	unsigned char   extraspace;     /* easi,fast or mod space ? */
141 #define NE_SPACE_FAST		0
142 #define NE_SPACE_MOD		1
143 #define NE_SPACE_EASI           2
144 	unsigned char	reserved0;	/* not used (padding) */
145 	const char	*name;		/* name */
146 	u_int8_t *	(*getea)	/* do this to get the MAC */
147 			    __P((struct ne_pbus_softc *sc, u_int8_t *buffer));
148 	void		(*preattach)	/* do this before attach */
149 			    __P((struct ne_pbus_softc *sc));
150 	void		(*postattach)	/* do this after attach */
151 			    __P((struct ne_pbus_softc *sc));
152         int          	(*mediachange)  /* media change */
153                             __P((struct dp8390_softc *));
154         void          	(*mediastatus)  /* media status */
155                             __P((struct dp8390_softc *, struct ifmediareq *));
156         void          	(*init_card)    /* media init card */
157                             __P((struct dp8390_softc *));
158         void          	(*init_media)   /* media init */
159                             __P((struct dp8390_softc *));
160 } ne_clones[] = {
161 	/* ANT EtherM netslot interface */
162 	{
163 	  PODULE_ETHERM, EM_REGSHIFT,
164 	  EM_NIC_OFFSET, EM_NIC_SIZE, EM_ASIC_OFFSET, EM_ASIC_SIZE,
165 	  0,0, NE_SPACE_FAST,
166 	  NE_SPACE_FAST, NE_SPACE_FAST, 0,
167 	  "EtherM", em_ea, NULL, em_postattach,
168 	  NULL,NULL,NULL,NULL
169 	},
170 	/* ICubed EtherLan EtherH netslot interface */
171 	{
172 	  PODULE_ETHERLAN600, EH600_REGSHIFT,
173 	  EH600_NIC_OFFSET, EH600_NIC_SIZE, EH600_ASIC_OFFSET, EH600_ASIC_SIZE,
174 	  EH600_CONTROL_OFFSET, EH600_CONTROL_SIZE, NE_SPACE_FAST,
175 	  NE_SPACE_FAST, NE_SPACE_FAST, 0,
176 	  "EtherLan 600", eh600_ea, eh600_preattach, eh600_postattach,
177 	  dp83905_mediachange, dp83905_mediastatus, dp83905_init_card,
178 	  eh600_init_media
179 	},
180 	/* Acorn EtherLan EtherH netslot interface */
181 	{
182 	  PODULE_ETHERLAN600AEH, EH600_REGSHIFT,
183 	  EH600_NIC_OFFSET, EH600_NIC_SIZE, EH600_ASIC_OFFSET, EH600_ASIC_SIZE,
184 	  EH600_CONTROL_OFFSET, EH600_CONTROL_SIZE, NE_SPACE_FAST,
185 	  NE_SPACE_FAST, NE_SPACE_FAST, 0,
186 	  "EtherLan 600A", eh600_ea , eh600_preattach, eh600_postattach,
187 	  dp83905_mediachange, dp83905_mediastatus, dp83905_init_card,
188 	  eh600_init_media
189 	},
190 	/* Irlam EtherN podule. (supplied with NC) */
191 	{
192 	  PODULE_ETHERN ,EN_REGSHIFT,
193 	  EN_NIC_OFFSET, EN_NIC_SIZE, EN_ASIC_OFFSET, EN_ASIC_SIZE,
194 	  0,0, NE_SPACE_EASI,
195 	  NE_SPACE_EASI, NE_SPACE_EASI, 0,
196 	  "EtherN", em_ea, NULL, en_postattach,
197 	  dp83905_mediachange, dp83905_mediastatus, dp83905_init_card,
198 	  en_init_media
199 	},
200 	/* Acorn EtherI podule. (supplied with NC) */
201 	{
202 	  PODULE_ETHERI ,EN_REGSHIFT,
203 	  EN_NIC_OFFSET, EN_NIC_SIZE, EN_ASIC_OFFSET, EN_ASIC_SIZE,
204 	  0,0, NE_SPACE_EASI,
205 	  NE_SPACE_EASI, NE_SPACE_EASI, 0,
206 	  "EtherI", em_ea, NULL, en_postattach,
207 	  dp83905_mediachange, dp83905_mediastatus, dp83905_init_card,
208 	  en_init_media
209 	},
210 };
211 
212 /*
213  * Determine if the device is present.
214  */
215 static int
216 ne_pbus_probe(parent, cf, aux)
217 	struct device *parent;
218 	struct cfdata *cf;
219 	void *aux;
220 {
221 	struct podule_attach_args *pa = (void *) aux;
222 	int loop;
223 
224 	/* Scan the list of known interfaces looking for a match */
225 	for (loop = 0; loop < sizeof(ne_clones) / sizeof(struct ne_clone);
226 	    ++loop) {
227 		if (pa->pa_product == ne_clones[loop].product)
228 			return(1);
229 	}
230 	return(0);
231 }
232 
233 /*
234  * Install interface into kernel networking data structures.
235  */
236 static void
237 ne_pbus_attach(parent, self, aux)
238 	struct device *parent, *self;
239 	void *aux;
240 {
241 	struct podule_attach_args *pa = (void *)aux;
242 	struct ne_pbus_softc *npsc = (void *)self;
243 	struct ne2000_softc *nsc = &npsc->sc_ne2000;
244 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
245 
246  	int *media, nmedia, defmedia;
247 	struct ne_clone *ne = NULL;
248 	u_int8_t buffer[6];
249 	u_int8_t *myea;
250 	int loop;
251 
252 	media = NULL;
253 	nmedia = defmedia = 0;
254 	/* Check a few things about the attach args */
255 
256 	if (pa->pa_podule_number == -1)
257 		panic("Podule has disappeared !");
258 
259 	npsc->sc_podule_number = pa->pa_podule_number;
260 	npsc->sc_podule = pa->pa_podule;
261 	podules[npsc->sc_podule_number].attached = 1;		/* XXX */
262 
263 	/* Scan the list of known interfaces for a match */
264 	for (loop = 0; loop < sizeof(ne_clones) / sizeof(struct ne_clone);
265 	    ++loop) {
266 		if (pa->pa_product == ne_clones[loop].product) {
267 			ne = &ne_clones[loop];
268 			break;
269 		}
270 	}
271 
272 #ifdef	DIAGNOSTIC
273 	/* This should never fail as we must have matched at probe time */
274 	if (ne == NULL)
275 		panic("Podule has vanished");
276 #endif
277 
278 	/* Update the nic and asic base addresses appropriately */
279 	switch (ne->nicspace) {
280 	case NE_SPACE_EASI:
281 		ne->nicbase += npsc->sc_podule->easi_base;
282 		break;
283 	case NE_SPACE_MOD:
284 		ne->nicbase += npsc->sc_podule->mod_base;
285 		break;
286 	case NE_SPACE_FAST:
287 	default:
288 		ne->nicbase += npsc->sc_podule->fast_base;
289 		break;
290 	}
291 	switch (ne->asicspace) {
292 	case NE_SPACE_EASI:
293 		ne->asicbase += npsc->sc_podule->easi_base;
294 		break;
295 	case NE_SPACE_MOD:
296 		ne->asicbase += npsc->sc_podule->mod_base;
297 		break;
298 	case NE_SPACE_FAST:
299 	default:
300 		ne->asicbase += npsc->sc_podule->fast_base;
301 		break;
302 	}
303 
304 	switch (ne->extraspace) {
305 	case NE_SPACE_EASI:
306 		ne->extrabase += npsc->sc_podule->easi_base;
307 		break;
308 	case NE_SPACE_MOD:
309 		ne->extrabase += npsc->sc_podule->mod_base;
310 		break;
311 	case NE_SPACE_FAST:
312 	default:
313 		ne->extrabase += npsc->sc_podule->fast_base;
314 		break;
315 	}
316 
317 	/* Report the interface name */
318 	printf(": %s ethernet\n", ne->name);
319 
320 	/*
321 	 * Ok we need our own bus tag as the register spacing
322 	 * may not the default.
323 	 *
324 	 * For the podulebus, the bus tag cookie is the shift
325 	 * to apply to registers
326 	 * So duplicate the bus space tag and change the
327 	 * cookie.
328 	 */
329 
330 	npsc->sc_tag = *pa->pa_iot;
331 	npsc->sc_tag.bs_cookie = (void *) ne->cookie;
332 
333 	dsc->sc_regt = &npsc->sc_tag;
334 	nsc->sc_asict = dsc->sc_regt;
335 
336 	/* Map all the I/O space for the NIC */
337 	if (bus_space_map(dsc->sc_regt, ne->nicbase, ne->nicsize,
338 	    0, &dsc->sc_regh)) {
339 		printf("%s: cannot map i/o space\n", dsc->sc_dev.dv_xname);
340 		return;
341 	}
342 	/* Map the I/O space for the ASIC */
343 	if (bus_space_map(nsc->sc_asict, ne->asicbase, ne->asicsize,
344 	    0, &nsc->sc_asich)) {
345 		printf("%s: cannot map i/o space\n", dsc->sc_dev.dv_xname);
346 		return;
347 	}
348 	/* Map any extra register space required by the card */
349 	if (ne->extrasize > 0) {
350 		if (bus_space_map(&npsc->sc_tag, ne->extrabase, ne->extrasize,
351 				  0, &npsc->sc_extrah)) {
352 			printf("%s: cannot map extra space\n",
353 			       dsc->sc_dev.dv_xname);
354 			return;
355 		}
356 	}
357 
358 	/* This interface is always enabled. */
359 	dsc->sc_enabled = 1;
360 
361 	/*
362 	 * Now get the ethernet address in an interface specific manner if
363 	 * specified
364 	 */
365 	if (ne->getea)
366 		myea = ne->getea(npsc, buffer);
367 	else
368 		myea = NULL;
369 
370 	/* Does the interface need a preattach call ? */
371 	if (ne->preattach)
372 		ne->preattach(npsc);
373 
374 	/* if the interface has media support initialise it */
375 	if (ne->init_media) {
376 		dsc->sc_mediachange = ne->mediachange;
377 		dsc->sc_mediastatus = ne->mediastatus;
378 		dsc->init_card = ne->init_card;
379 		dsc->sc_media_init = ne->init_media;
380 /*		ne->init_media(dsc,&media,&nmedia,&defmedia); */
381 	}
382 
383 	/*
384 	 * Do generic NE2000 attach.  This will read the station address
385 	 * from the EEPROM.
386 	 */
387 	ne2000_attach(nsc, myea);
388 	printf("%s: ", dsc->sc_dev.dv_xname);
389 	switch (nsc->sc_type) {
390 	case NE2000_TYPE_NE1000:
391 		printf("NE1000");
392 		break;
393 	case NE2000_TYPE_NE2000:
394 		printf("NE2000");
395 		break;
396 	case NE2000_TYPE_AX88190:
397 		printf("AX88190");
398 		break;
399 	case NE2000_TYPE_DL10019:
400 		printf("DL10019");
401 		break;
402         case NE2000_TYPE_DL10022:
403 		printf("DL10022");
404 		break;
405 	default:
406 		printf("??");
407 	};
408 	printf(" chipset, %d Kb memory\n", dsc->mem_start/1024);
409 
410 	/* Does the interface need a postattach call ? */
411 	if (ne->postattach)
412 		ne->postattach(npsc);
413 
414 	/* Install an interrupt handler */
415 	evcnt_attach_dynamic(&npsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
416 	    self->dv_xname, "intr");
417 	npsc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_NET, dp8390_intr,
418 	    dsc, &npsc->sc_intrcnt);
419 	if (npsc->sc_ih == NULL)
420 		panic("%s: Cannot install interrupt handler",
421 		   dsc->sc_dev.dv_xname);
422 	/* this feels wrong to do this here */
423 	npsc->sc_ih->ih_maskaddr = npsc->sc_podule->irq_addr;
424 	npsc->sc_ih->ih_maskbits = npsc->sc_podule->irq_mask;
425 }
426 
427 /*
428  * em_ea()
429  *
430  * return the ethernet address for an EtherM netslot interface.
431  * The EtherM interface uses the machines ethernet address so just
432  * fill it out
433  */
434 static u_int8_t *
435 em_ea(sc, buffer)
436 	struct ne_pbus_softc *sc;
437 	u_int8_t *buffer;
438 {
439 	/*
440 	 * Use the podulebus netslot_ea() function to get the netslot
441 	 * ethernet address. This is generated from the machine ID.
442 	 */
443 
444 	netslot_ea(buffer);
445 	return(buffer);
446 }
447 
448 /*
449  * em_postattach()
450  *
451  * The EtherM interface has a Diagnostic Status register. After attaching
452  * the driver, print out some more information using this register.
453  */
454 static void
455 em_postattach(sc)
456 	struct ne_pbus_softc *sc;
457 {
458 	int dsr;
459 
460 	/*
461 	 * Report information from the Diagnostic Status Register for
462 	 * the EtherM card
463 	 */
464 	printf("%s: 16KB buffer memory",
465 	    sc->sc_ne2000.sc_dp8390.sc_dev.dv_xname);
466 
467 	/* Get the Diagnostic Status Register */
468 	dsr = bus_space_read_1(sc->sc_ne2000.sc_asict,
469 	    sc->sc_ne2000.sc_asich, EM_DSR_REG);
470 
471 	/* Check for bits that indicate a fault */
472 	if (!(dsr & EM_DSR_20M))
473 		printf(", VCO faulty");
474 	if (!(dsr & EM_DSR_TCOK))
475 		printf(", TxClk faulty");
476 
477 	/* Report status of card */
478 	if (dsr & EM_DSR_POL)
479 		printf(", UTP reverse polarity");
480 	if (dsr & EM_DSR_JAB)
481 		printf(", jabber");
482 	if (dsr & EM_DSR_LNK)
483 		printf(", link OK");
484 	if (dsr & EM_DSR_LBK)
485 		printf(", loopback");
486 	if (dsr & EM_DSR_UTP)
487 		printf(", UTP");
488 	printf("\n");
489 }
490 
491 
492 /*
493  * eh600_preattach()
494  *
495  * pre-initialise the AT/Lantic chipset so that the card probes and
496  * detects properly.
497  */
498 static void
499 eh600_preattach(sc)
500 	struct ne_pbus_softc *sc;
501 {
502 	u_char tmp;
503 	struct ne2000_softc *nsc = &sc->sc_ne2000;
504 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
505 	bus_space_tag_t nict = dsc->sc_regt;
506 	bus_space_handle_t nich = dsc->sc_regh;
507 
508 	/* initialise EH600 config register */
509 	bus_space_read_1(nict, nich, DP83905_MCRA);
510 	bus_space_write_1(nict, nich, DP83905_MCRA, DP83905_MCRA_INT3);
511 
512 	/* enable interrupts for the card */
513 	tmp = bus_space_read_1(&sc->sc_tag,sc->sc_extrah,0);
514 	tmp |= EH_INTR_MASK;
515 	bus_space_write_1(&sc->sc_tag,sc->sc_extrah,0,tmp);
516 }
517 
518 /*
519  * eh600_postattach()
520  *
521  * Etherlan 600 has 32k of buffer memory as it runs the AT/Lantic
522  * DP8390 clone in IO non-compatible mode. We need to adjust the memory
523  * description set up by dp8390.c and ne2000.c to reflect this.
524  */
525 static void
526 eh600_postattach(sc)
527 	struct ne_pbus_softc *sc;
528 {
529 	struct ne2000_softc *nsc = &sc->sc_ne2000;
530 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
531 	/* first page is mapped to the PROM. so start at 2nd page */
532 	dsc->mem_start = EH600_MEM_START;
533 	dsc->mem_size = EH600_MEM_END - EH600_MEM_START;
534 	dsc->mem_end = EH600_MEM_END;
535 	dsc->txb_cnt = 3; /* >16k of ram setup 3 tx buffers */
536 	/* recompute the mem ring (taken straight from the ne2000 init code) */
537 	dsc->mem_ring =
538 		dsc->mem_start +
539 		(((dsc->txb_cnt + 1) * ED_TXBUF_SIZE ) <<
540 		 ED_PAGE_SHIFT);
541 
542 	/* recompute the dp8390 register values. (from dp8390 init code) */
543 	dsc->tx_page_start = dsc->mem_start >> ED_PAGE_SHIFT;
544 
545 	dsc->rec_page_start = dsc->tx_page_start +
546 		(dsc->txb_cnt + 1) * ED_TXBUF_SIZE;
547 
548 	dsc->rec_page_stop = dsc->tx_page_start +
549 		(dsc->mem_size >> ED_PAGE_SHIFT);
550 	printf("%s: 32KB buffer memory\n", dsc->sc_dev.dv_xname);
551 
552 }
553 /*
554  * EtherLan 600 media.
555  */
556 void eh600_init_media(sc)
557 	struct dp8390_softc *sc;
558 {
559 	static int eh600_media[] = {
560 		IFM_ETHER|IFM_AUTO,
561 		IFM_ETHER|IFM_10_T,
562 		IFM_ETHER|IFM_10_2,
563 	};
564 	int i, defmedia = IFM_ETHER|IFM_AUTO;
565 	static const int eh600_nmedia =
566 	    sizeof(eh600_media) / sizeof(eh600_media[0]);
567 
568 	printf("%s: 10base2, 10baseT, auto, default auto\n",
569 	    sc->sc_dev.dv_xname);
570 
571 	ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
572 	for (i = 0; i < eh600_nmedia; i++)
573 		ifmedia_add(&sc->sc_media, eh600_media[i], 0, NULL);
574 	ifmedia_set(&sc->sc_media, defmedia);
575 
576 }
577 
578 
579 void
580 en_postattach(sc)
581 	struct ne_pbus_softc *sc;
582 {
583 
584 	mx98905_attach(&sc->sc_ne2000.sc_dp8390);
585 }
586 
587 /*
588  * EtherN media.
589  */
590 void
591 en_init_media(sc)
592 	struct dp8390_softc *sc;
593 {
594 	static int en_media[] = {
595 		IFM_ETHER|IFM_10_T
596 	};
597 	printf("%s: 10baseT, default 10baseT\n",
598 	    sc->sc_dev.dv_xname);
599 
600 	ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
601 	ifmedia_add(&sc->sc_media, en_media[0], 0, NULL);
602 	ifmedia_set(&sc->sc_media, en_media[0]);
603 }
604 
605 
606 /*
607  * extracts the station address from the Podule description string.
608  * The description has to be re-read here since the podule description
609  * string is not always long enough to contain the full address.
610  *
611  * If for any reason we cannot extract the address this routine will
612  * use netslot_ea() to return the generic address for the network slot.
613  */
614 
615 #define POD_READ(addr) \
616 	podule->read_rom(podule->sync_base, addr)
617 
618 static u_int8_t *
619 eh600_ea(sc, buffer)
620 	struct ne_pbus_softc *sc;
621 	u_int8_t *buffer;
622 {
623 	podule_t *podule = sc->sc_podule;
624 	u_int address;
625 	u_int id;
626 
627 	address = 0x40;
628 	memset(buffer, 0, 6);
629 
630 	/* read chunks from the podule  */
631 	do {
632 		id = POD_READ(address);
633 		/* check for description chunk. */
634 		if (id == 0xf5) {
635 			u_int size;
636 			u_int pod_addr;
637 			int loop;
638 
639 			/* read the size */
640 			size = POD_READ(address + 4);
641 			size |= (POD_READ(address + 8) << 8);
642 			size |= (POD_READ(address + 12) << 16);
643 
644 			/* read address of description */
645 			pod_addr = POD_READ(address + 16);
646 			pod_addr |= (POD_READ(address + 20) << 8);
647 			pod_addr |= (POD_READ(address + 24) << 16);
648 			pod_addr |= (POD_READ(address + 28) << 24);
649 
650 			if (pod_addr < 0x800) {
651 				u_int8_t tmp;
652 				int addr_index = 0;
653 				int found_ether = 0;
654 
655 				/*
656 				 * start scanning for ethernet address
657 				 * which starts with a '('
658 				 */
659 				for (loop = 0; loop < size; ++loop) {
660 					if (found_ether) {
661 					        /* we have found a '(' so start decoding the address */
662 						tmp = POD_READ((pod_addr + loop) * 4);
663 						if (tmp >= '0' &&  tmp <= '9') {
664 							buffer[addr_index >> 1] |= (tmp - '0') << ((addr_index & 1) ? 0 : 4);
665 							++addr_index;
666 						}
667 						else if (tmp >= 'a' &&  tmp <= 'f'){
668 							buffer[addr_index >> 1] |= (10 + (tmp - 'a')) << ((addr_index & 1) ? 0 : 4);
669 							++addr_index;
670 						}
671 						else if (tmp >= 'A' &&  tmp <= 'F'){
672 							buffer[addr_index >> 1] |= (10 + (tmp - 'A')) << ((addr_index & 1) ? 0 : 4);
673 							++addr_index;
674 						}
675 						else if (tmp == ')') {
676 							/* we have read the whole address so we can stop scanning
677 							 * the podule description */
678 							break;
679 						}
680 					}
681 					/*
682 					 * we have found the start of the ethernet address (decode begins
683 					 * on the next run round the loop. */
684 					if (POD_READ((pod_addr + loop) * 4) == '(') {
685 						found_ether = 1;
686 					}
687 				}
688 				/*
689 				 * Failed to find the address so fall back
690 				 * on the netslot address
691 				 */
692 				if (!found_ether)
693 					netslot_ea(buffer);
694 				return(buffer);
695 			}
696 		}
697 		address += 32;
698 	} while (id != 0 && address < 0x8000);
699 
700 	/*
701 	 * If we get here we failed to find the address
702 	 * In this case the best solution is to go with the netslot addrness
703 	 */
704 	netslot_ea(buffer);
705 	return(buffer);
706 }
707