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