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