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