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