Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / acorn32 / podulebus / if_ne_pbus.c
blob6c91278ec2de74e1f99f92af2832e07b13d8e2e9
1 /* $NetBSD: if_ne_pbus.c,v 1.14 2008/03/12 14:31:11 cube Exp $ */
3 /*
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Mark Brinicombe of Causality Limited.
10 * EtherH code Copyright (c) 1998 Mike Pumford
11 * EtherN/EtherI code Copyright (c) 1999 Mike Pumford
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.
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.
36 * This driver uses the generic ne2000 & dp8390 IC drivers
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)
44 * Thanks go to Stephen Borrill for providing the EtherN card
45 * and information to program it.
47 * TO DO List for this Driver.
49 * EtherM - Needs proper media support.
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: if_ne_pbus.c,v 1.14 2008/03/12 14:31:11 cube Exp $");
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>
61 #include <net/if.h>
62 #include <net/if_dl.h>
63 #include <net/if_ether.h>
64 #include <net/if_media.h>
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>
77 #include <arch/acorn32/podulebus/podulebus.h>
78 #include <arch/acorn32/podulebus/if_ne_pbusreg.h>
80 #include <dev/podulebus/podules.h>
83 * ne_pbus_softc: ne2000_softc plus podule, interrupt and bs tag info
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 */
97 * Attach data and prototypes for driver
99 static int ne_pbus_probe (device_t, cfdata_t , void *);
100 static void ne_pbus_attach (device_t, device_t, void *);
102 CFATTACH_DECL_NEW(ne_pbus, sizeof(struct ne_pbus_softc),
103 ne_pbus_probe, ne_pbus_attach, NULL, NULL);
106 * Prototypes for interface specific routines
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);
114 void eh600_init_media (struct dp8390_softc *);
116 void en_postattach (struct ne_pbus_softc *);
117 void en_init_media (struct dp8390_softc *);
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.
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 */
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
166 /* ICubed EtherLan EtherH netslot interface */
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
176 /* Acorn EtherLan EtherH netslot interface */
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
186 /* Irlam EtherN podule. (supplied with NC) */
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
196 /* Acorn EtherI podule. (supplied with NC) */
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
209 * Determine if the device is present.
211 static int
212 ne_pbus_probe(device_t parent, cfdata_t cf, void *aux)
214 struct podule_attach_args *pa = (void *) aux;
215 int loop;
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);
223 return(0);
227 * Install interface into kernel networking data structures.
229 static void
230 ne_pbus_attach(device_t parent, device_t self, void *aux)
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;
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;
243 dsc->sc_dev = self;
244 media = NULL;
245 nmedia = defmedia = 0;
246 /* Check a few things about the attach args */
248 if (pa->pa_podule_number == -1)
249 panic("Podule has disappeared !");
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 */
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;
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
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;
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;
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;
309 /* Report the interface name */
310 aprint_normal(": %s ethernet\n", ne->name);
313 * Ok we need our own bus tag as the register spacing
314 * may not the default.
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.
322 npsc->sc_tag = *pa->pa_iot;
323 npsc->sc_tag.bs_cookie = (void *) ne->cookie;
325 dsc->sc_regt = &npsc->sc_tag;
326 nsc->sc_asict = dsc->sc_regt;
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;
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;
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;
349 /* This interface is always enabled. */
350 dsc->sc_enabled = 1;
353 * Now get the ethernet address in an interface specific manner if
354 * specified
356 if (ne->getea)
357 myea = ne->getea(npsc, buffer);
358 else
359 myea = NULL;
361 /* Does the interface need a preattach call ? */
362 if (ne->preattach)
363 ne->preattach(npsc);
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); */
375 * Do generic NE2000 attach. This will read the station address
376 * from the EEPROM.
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("??");
399 aprint_normal(" chipset, %d Kb memory\n", dsc->mem_start/1024);
401 /* Does the interface need a postattach call ? */
402 if (ne->postattach)
403 ne->postattach(npsc);
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;
419 * em_ea()
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
425 static uint8_t *
426 em_ea(struct ne_pbus_softc *sc, uint8_t *buffer)
429 * Use the podulebus netslot_ea() function to get the netslot
430 * ethernet address. This is generated from the machine ID.
433 netslot_ea(buffer);
434 return(buffer);
438 * em_postattach()
440 * The EtherM interface has a Diagnostic Status register. After attaching
441 * the driver, print out some more information using this register.
443 static void
444 em_postattach(struct ne_pbus_softc *sc)
446 int dsr;
449 * Report information from the Diagnostic Status Register for
450 * the EtherM card
452 aprint_normal_dev(sc->sc_ne2000.sc_dp8390.sc_dev,
453 "16KB buffer memory");
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);
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");
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");
481 * eh600_preattach()
483 * pre-initialise the AT/Lantic chipset so that the card probes and
484 * detects properly.
486 static void
487 eh600_preattach(struct ne_pbus_softc *sc)
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;
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);
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);
506 * eh600_postattach()
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.
512 static void
513 eh600_postattach(struct ne_pbus_softc *sc)
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);
528 /* recompute the dp8390 register values. (from dp8390 init code) */
529 dsc->tx_page_start = dsc->mem_start >> ED_PAGE_SHIFT;
531 dsc->rec_page_start = dsc->tx_page_start +
532 (dsc->txb_cnt + 1) * ED_TXBUF_SIZE;
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");
539 * EtherLan 600 media.
541 void eh600_init_media(struct dp8390_softc *sc)
543 static int eh600_media[] = {
544 IFM_ETHER|IFM_AUTO,
545 IFM_ETHER|IFM_10_T,
546 IFM_ETHER|IFM_10_2,
548 int i, defmedia = IFM_ETHER|IFM_AUTO;
549 static const int eh600_nmedia =
550 sizeof(eh600_media) / sizeof(eh600_media[0]);
552 aprint_normal_dev(sc->sc_dev,
553 "10base2, 10baseT, auto, default auto\n");
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);
563 void
564 en_postattach(struct ne_pbus_softc *sc)
567 mx98905_attach(&sc->sc_ne2000.sc_dp8390);
571 * EtherN media.
573 void
574 en_init_media(struct dp8390_softc *sc)
576 static int en_media[] = {
577 IFM_ETHER|IFM_10_T
579 aprint_normal_dev(sc->sc_dev, "10baseT, default 10baseT\n");
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]);
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.
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.
596 #define POD_READ(addr) \
597 podule->read_rom(podule->sync_base, addr)
599 static uint8_t *
600 eh600_ea(struct ne_pbus_softc *sc, uint8_t *buffer)
602 podule_t *podule = sc->sc_podule;
603 u_int address;
604 u_int id;
606 address = 0x40;
607 memset(buffer, 0, 6);
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;
618 /* read the size */
619 size = POD_READ(address + 4);
620 size |= (POD_READ(address + 8) << 8);
621 size |= (POD_READ(address + 12) << 16);
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);
629 if (pod_addr < 0x800) {
630 u_int8_t tmp;
631 int addr_index = 0;
632 int found_ether = 0;
635 * start scanning for ethernet address
636 * which starts with a '('
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;
646 else if (tmp >= 'a' && tmp <= 'f'){
647 buffer[addr_index >> 1] |= (10 + (tmp - 'a')) << ((addr_index & 1) ? 0 : 4);
648 ++addr_index;
650 else if (tmp >= 'A' && tmp <= 'F'){
651 buffer[addr_index >> 1] |= (10 + (tmp - 'A')) << ((addr_index & 1) ? 0 : 4);
652 ++addr_index;
654 else if (tmp == ')') {
655 /* we have read the whole address so we can stop scanning
656 * the podule description */
657 break;
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;
668 * Failed to find the address so fall back
669 * on the netslot address
671 if (!found_ether)
672 netslot_ea(buffer);
673 return(buffer);
676 address += 32;
677 } while (id != 0 && address < 0x8000);
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
683 netslot_ea(buffer);
684 return(buffer);