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