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