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