Home | History | Annotate | Line # | Download | only in podulebus
      1 /*	$NetBSD: if_ne_pbus.c,v 1.20 2019/05/29 06:21:56 msaitoh 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.20 2019/05/29 06:21:56 msaitoh 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 #include <sys/bus.h>
     61 
     62 #include <net/if.h>
     63 #include <net/if_dl.h>
     64 #include <net/if_ether.h>
     65 #include <net/if_media.h>
     66 
     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 uint8_t *em_ea		(struct ne_pbus_softc *sc, uint8_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 uint8_t *eh600_ea	(struct ne_pbus_softc *sc, uint8_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 	uint8_t *	(*getea)	/* do this to get the MAC */
    143 			    (struct ne_pbus_softc *sc, uint8_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 	struct ne_clone *ne = NULL;
    237 	uint8_t buffer[6];
    238 	uint8_t *myea;
    239 	int loop;
    240 
    241 	dsc->sc_dev = self;
    242 	/* Check a few things about the attach args */
    243 
    244 	if (pa->pa_podule_number == -1)
    245 		panic("Podule has disappeared !");
    246 
    247 	npsc->sc_podule_number = pa->pa_podule_number;
    248 	npsc->sc_podule = pa->pa_podule;
    249 	podules[npsc->sc_podule_number].attached = 1;		/* XXX */
    250 
    251 	/* Scan the list of known interfaces for a match */
    252 	for (loop = 0; loop < sizeof(ne_clones) / sizeof(struct ne_clone);
    253 	    ++loop) {
    254 		if (pa->pa_product == ne_clones[loop].product) {
    255 			ne = &ne_clones[loop];
    256 			break;
    257 		}
    258 	}
    259 
    260 #ifdef	DIAGNOSTIC
    261 	/* This should never fail as we must have matched at probe time */
    262 	if (ne == NULL)
    263 		panic("Podule has vanished");
    264 #endif
    265 
    266 	/* Update the nic and asic base addresses appropriately */
    267 	switch (ne->nicspace) {
    268 	case NE_SPACE_EASI:
    269 		ne->nicbase += npsc->sc_podule->easi_base;
    270 		break;
    271 	case NE_SPACE_MOD:
    272 		ne->nicbase += npsc->sc_podule->mod_base;
    273 		break;
    274 	case NE_SPACE_FAST:
    275 	default:
    276 		ne->nicbase += npsc->sc_podule->fast_base;
    277 		break;
    278 	}
    279 	switch (ne->asicspace) {
    280 	case NE_SPACE_EASI:
    281 		ne->asicbase += npsc->sc_podule->easi_base;
    282 		break;
    283 	case NE_SPACE_MOD:
    284 		ne->asicbase += npsc->sc_podule->mod_base;
    285 		break;
    286 	case NE_SPACE_FAST:
    287 	default:
    288 		ne->asicbase += npsc->sc_podule->fast_base;
    289 		break;
    290 	}
    291 
    292 	switch (ne->extraspace) {
    293 	case NE_SPACE_EASI:
    294 		ne->extrabase += npsc->sc_podule->easi_base;
    295 		break;
    296 	case NE_SPACE_MOD:
    297 		ne->extrabase += npsc->sc_podule->mod_base;
    298 		break;
    299 	case NE_SPACE_FAST:
    300 	default:
    301 		ne->extrabase += npsc->sc_podule->fast_base;
    302 		break;
    303 	}
    304 
    305 	/* Report the interface name */
    306 	aprint_normal(": %s ethernet\n", ne->name);
    307 
    308 	/*
    309 	 * Ok we need our own bus tag as the register spacing
    310 	 * may not the default.
    311 	 *
    312 	 * For the podulebus, the bus tag cookie is the shift
    313 	 * to apply to registers
    314 	 * So duplicate the bus space tag and change the
    315 	 * cookie.
    316 	 */
    317 
    318 	npsc->sc_tag = *pa->pa_iot;
    319 	npsc->sc_tag.bs_cookie = (void *) ne->cookie;
    320 
    321 	dsc->sc_regt = &npsc->sc_tag;
    322 	nsc->sc_asict = dsc->sc_regt;
    323 
    324 	/* Map all the I/O space for the NIC */
    325 	if (bus_space_map(dsc->sc_regt, ne->nicbase, ne->nicsize,
    326 	    0, &dsc->sc_regh)) {
    327 		aprint_error_dev(self, "cannot map i/o space\n");
    328 		return;
    329 	}
    330 	/* Map the I/O space for the ASIC */
    331 	if (bus_space_map(nsc->sc_asict, ne->asicbase, ne->asicsize,
    332 	    0, &nsc->sc_asich)) {
    333 		aprint_error_dev(self, "cannot map i/o space\n");
    334 		return;
    335 	}
    336 	/* Map any extra register space required by the card */
    337 	if (ne->extrasize > 0) {
    338 		if (bus_space_map(&npsc->sc_tag, ne->extrabase, ne->extrasize,
    339 				  0, &npsc->sc_extrah)) {
    340 			aprint_error_dev(self, "cannot map extra space\n");
    341 			return;
    342 		}
    343 	}
    344 
    345 	/* This interface is always enabled. */
    346 	dsc->sc_enabled = 1;
    347 
    348 	/*
    349 	 * Now get the ethernet address in an interface specific manner if
    350 	 * specified
    351 	 */
    352 	if (ne->getea)
    353 		myea = ne->getea(npsc, buffer);
    354 	else
    355 		myea = NULL;
    356 
    357 	/* Does the interface need a preattach call ? */
    358 	if (ne->preattach)
    359 		ne->preattach(npsc);
    360 
    361 	/* If the interface has media support initialise it */
    362 	if (ne->init_media) {
    363 		dsc->sc_mediachange = ne->mediachange;
    364 		dsc->sc_mediastatus = ne->mediastatus;
    365 		dsc->init_card = ne->init_card;
    366 		dsc->sc_media_init = ne->init_media;
    367 #if 0
    368 		int *media = NULL, nmedia = 0, defmedia = 0;
    369 		ne->init_media(dsc, &media, &nmedia, &defmedia);
    370 #endif
    371 	}
    372 
    373 	/*
    374 	 * Do generic NE2000 attach.  This will read the station address
    375 	 * from the EEPROM.
    376 	 */
    377 	ne2000_attach(nsc, myea);
    378 	aprint_normal_dev(self, "");
    379 	switch (nsc->sc_type) {
    380 	case NE2000_TYPE_NE1000:
    381 		aprint_normal("NE1000");
    382 		break;
    383 	case NE2000_TYPE_NE2000:
    384 		aprint_normal("NE2000");
    385 		break;
    386 	case NE2000_TYPE_AX88190:
    387 		aprint_normal("AX88190");
    388 		break;
    389 	case NE2000_TYPE_DL10019:
    390 		aprint_normal("DL10019");
    391 		break;
    392 	case NE2000_TYPE_DL10022:
    393 		aprint_normal("DL10022");
    394 		break;
    395 	default:
    396 		printf("??");
    397 	};
    398 	aprint_normal(" chipset, %d Kb memory\n", dsc->mem_start/1024);
    399 
    400 	/* Does the interface need a postattach call ? */
    401 	if (ne->postattach)
    402 		ne->postattach(npsc);
    403 
    404 	/* Install an interrupt handler */
    405 	evcnt_attach_dynamic(&npsc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
    406 	    device_xname(self), "intr");
    407 	npsc->sc_ih = podulebus_irq_establish(pa->pa_ih, IPL_NET, dp8390_intr,
    408 	    dsc, &npsc->sc_intrcnt);
    409 	if (npsc->sc_ih == NULL)
    410 		panic("%s: Cannot install interrupt handler",
    411 		   device_xname(self));
    412 	/* This feels wrong to do this here */
    413 	npsc->sc_ih->ih_maskaddr = npsc->sc_podule->irq_addr;
    414 	npsc->sc_ih->ih_maskbits = npsc->sc_podule->irq_mask;
    415 }
    416 
    417 /*
    418  * em_ea()
    419  *
    420  * return the ethernet address for an EtherM netslot interface.
    421  * The EtherM interface uses the machines ethernet address so just
    422  * fill it out
    423  */
    424 static uint8_t *
    425 em_ea(struct ne_pbus_softc *sc, uint8_t *buffer)
    426 {
    427 	/*
    428 	 * Use the podulebus netslot_ea() function to get the netslot
    429 	 * ethernet address. This is generated from the machine ID.
    430 	 */
    431 
    432 	netslot_ea(buffer);
    433 	return buffer;
    434 }
    435 
    436 /*
    437  * em_postattach()
    438  *
    439  * The EtherM interface has a Diagnostic Status register. After attaching
    440  * the driver, print out some more information using this register.
    441  */
    442 static void
    443 em_postattach(struct ne_pbus_softc *sc)
    444 {
    445 	int dsr;
    446 
    447 	/*
    448 	 * Report information from the Diagnostic Status Register for
    449 	 * the EtherM card
    450 	 */
    451 	aprint_normal_dev(sc->sc_ne2000.sc_dp8390.sc_dev,
    452 	    "16KB buffer memory");
    453 
    454 	/* Get the Diagnostic Status Register */
    455 	dsr = bus_space_read_1(sc->sc_ne2000.sc_asict,
    456 	    sc->sc_ne2000.sc_asich, EM_DSR_REG);
    457 
    458 	/* Check for bits that indicate a fault */
    459 	if (!(dsr & EM_DSR_20M))
    460 		aprint_normal(", VCO faulty");
    461 	if (!(dsr & EM_DSR_TCOK))
    462 		aprint_normal(", TxClk faulty");
    463 
    464 	/* Report status of card */
    465 	if (dsr & EM_DSR_POL)
    466 		aprint_normal(", UTP reverse polarity");
    467 	if (dsr & EM_DSR_JAB)
    468 		aprint_normal(", jabber");
    469 	if (dsr & EM_DSR_LNK)
    470 		aprint_normal(", link OK");
    471 	if (dsr & EM_DSR_LBK)
    472 		aprint_normal(", loopback");
    473 	if (dsr & EM_DSR_UTP)
    474 		aprint_normal(", UTP");
    475 	aprint_normal("\n");
    476 }
    477 
    478 
    479 /*
    480  * eh600_preattach()
    481  *
    482  * pre-initialise the AT/Lantic chipset so that the card probes and
    483  * detects properly.
    484  */
    485 static void
    486 eh600_preattach(struct ne_pbus_softc *sc)
    487 {
    488 	u_char tmp;
    489 	struct ne2000_softc *nsc = &sc->sc_ne2000;
    490 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
    491 	bus_space_tag_t nict = dsc->sc_regt;
    492 	bus_space_handle_t nich = dsc->sc_regh;
    493 
    494 	/* Initialise EH600 config register */
    495 	bus_space_read_1(nict, nich, DP83905_MCRA);
    496 	bus_space_write_1(nict, nich, DP83905_MCRA, DP83905_MCRA_INT3);
    497 
    498 	/* Enable interrupts for the card */
    499 	tmp = bus_space_read_1(&sc->sc_tag, sc->sc_extrah, 0);
    500 	tmp |= EH_INTR_MASK;
    501 	bus_space_write_1(&sc->sc_tag, sc->sc_extrah, 0, tmp);
    502 }
    503 
    504 /*
    505  * eh600_postattach()
    506  *
    507  * Etherlan 600 has 32k of buffer memory as it runs the AT/Lantic
    508  * DP8390 clone in IO non-compatible mode. We need to adjust the memory
    509  * description set up by dp8390.c and ne2000.c to reflect this.
    510  */
    511 static void
    512 eh600_postattach(struct ne_pbus_softc *sc)
    513 {
    514 	struct ne2000_softc *nsc = &sc->sc_ne2000;
    515 	struct dp8390_softc *dsc = &nsc->sc_dp8390;
    516 
    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 = __arraycount(eh600_media);
    550 
    551 	aprint_normal_dev(sc->sc_dev,
    552 	    "10base2, 10baseT, auto, default auto\n");
    553 
    554 	ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
    555 	for (i = 0; i < eh600_nmedia; i++)
    556 		ifmedia_add(&sc->sc_media, eh600_media[i], 0, NULL);
    557 	ifmedia_set(&sc->sc_media, defmedia);
    558 }
    559 
    560 
    561 void
    562 en_postattach(struct ne_pbus_softc *sc)
    563 {
    564 
    565 	mx98905_attach(&sc->sc_ne2000.sc_dp8390);
    566 }
    567 
    568 /*
    569  * EtherN media.
    570  */
    571 void
    572 en_init_media(struct dp8390_softc *sc)
    573 {
    574 	static int en_media[] = {
    575 		IFM_ETHER | IFM_10_T
    576 	};
    577 
    578 	aprint_normal_dev(sc->sc_dev, "10baseT, default 10baseT\n");
    579 
    580 	ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
    581 	ifmedia_add(&sc->sc_media, en_media[0], 0, NULL);
    582 	ifmedia_set(&sc->sc_media, en_media[0]);
    583 }
    584 
    585 
    586 /*
    587  * extracts the station address from the Podule description string.
    588  * The description has to be re-read here since the podule description
    589  * string is not always long enough to contain the full address.
    590  *
    591  * If for any reason we cannot extract the address this routine will
    592  * use netslot_ea() to return the generic address for the network slot.
    593  */
    594 
    595 #define POD_READ(addr) \
    596 	podule->read_rom(podule->sync_base, addr)
    597 
    598 static uint8_t *
    599 eh600_ea(struct ne_pbus_softc *sc, uint8_t *buffer)
    600 {
    601 	podule_t *podule = sc->sc_podule;
    602 	u_int address;
    603 	u_int id;
    604 
    605 	address = 0x40;
    606 	memset(buffer, 0, 6);
    607 
    608 	/* Read chunks from the podule	*/
    609 	do {
    610 		id = POD_READ(address);
    611 		/* Check for description chunk. */
    612 		if (id == 0xf5) {
    613 			u_int size;
    614 			u_int pod_addr;
    615 			int loop;
    616 
    617 			/* Read the size */
    618 			size = POD_READ(address + 4);
    619 			size |= (POD_READ(address + 8) << 8);
    620 			size |= (POD_READ(address + 12) << 16);
    621 
    622 			/* Read address of description */
    623 			pod_addr = POD_READ(address + 16);
    624 			pod_addr |= (POD_READ(address + 20) << 8);
    625 			pod_addr |= (POD_READ(address + 24) << 16);
    626 			pod_addr |= (POD_READ(address + 28) << 24);
    627 
    628 			if (pod_addr < 0x800) {
    629 				uint8_t tmp;
    630 				int addr_index = 0;
    631 				int found_ether = 0;
    632 
    633 				/*
    634 				 * Start scanning for ethernet address
    635 				 * which starts with a '('
    636 				 */
    637 				for (loop = 0; loop < size; ++loop) {
    638 					if (found_ether) {
    639 						/* We have found a '(' so start decoding the address */
    640 						tmp = POD_READ((pod_addr + loop) * 4);
    641 						if (tmp >= '0' &&  tmp <= '9') {
    642 							buffer[addr_index >> 1] |= (tmp - '0') << ((addr_index & 1) ? 0 : 4);
    643 							++addr_index;
    644 						}
    645 						else if (tmp >= 'a' &&	tmp <= 'f'){
    646 							buffer[addr_index >> 1] |= (10 + (tmp - 'a')) << ((addr_index & 1) ? 0 : 4);
    647 							++addr_index;
    648 						}
    649 						else if (tmp >= 'A' &&	tmp <= 'F'){
    650 							buffer[addr_index >> 1] |= (10 + (tmp - 'A')) << ((addr_index & 1) ? 0 : 4);
    651 							++addr_index;
    652 						}
    653 						else if (tmp == ')') {
    654 							/* We have read the whole address so we can stop scanning
    655 							 * the podule description */
    656 							break;
    657 						}
    658 					}
    659 					/*
    660 					 * We have found the start of the ethernet address (decode begins
    661 					 * on the next run round the loop. */
    662 					if (POD_READ((pod_addr + loop) * 4) == '(') {
    663 						found_ether = 1;
    664 					}
    665 				}
    666 				/*
    667 				 * Failed to find the address so fall back
    668 				 * on the netslot address
    669 				 */
    670 				if (!found_ether)
    671 					netslot_ea(buffer);
    672 				return buffer;
    673 			}
    674 		}
    675 		address += 32;
    676 	} while (id != 0 && address < 0x8000);
    677 
    678 	/*
    679 	 * If we get here we failed to find the address
    680 	 * In this case the best solution is to go with the netslot addrness
    681 	 */
    682 	netslot_ea(buffer);
    683 	return buffer;
    684 }
    685