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