Home | History | Annotate | Line # | Download | only in pcmcia
xirc.c revision 1.33
      1 /*	$NetBSD: xirc.c,v 1.33 2012/02/14 13:51:19 drochner Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1999, 2000, 2004 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
      9  * NASA Ames Research Center and by Charles M. Hannum.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     30  * POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 #include <sys/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: xirc.c,v 1.33 2012/02/14 13:51:19 drochner Exp $");
     35 
     36 #include "opt_inet.h"
     37 
     38 #include <sys/param.h>
     39 #include <sys/systm.h>
     40 #include <sys/mbuf.h>
     41 #include <sys/socket.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/errno.h>
     44 #include <sys/syslog.h>
     45 #include <sys/select.h>
     46 #include <sys/tty.h>
     47 #include <sys/device.h>
     48 
     49 #include <net/if.h>
     50 #include <net/if_dl.h>
     51 #include <net/if_ether.h>
     52 #include <net/if_media.h>
     53 
     54 #ifdef INET
     55 #include <netinet/in.h>
     56 #include <netinet/in_systm.h>
     57 #include <netinet/in_var.h>
     58 #include <netinet/ip.h>
     59 #include <netinet/if_inarp.h>
     60 #endif
     61 
     62 
     63 #include <net/bpf.h>
     64 #include <net/bpfdesc.h>
     65 
     66 #include <sys/intr.h>
     67 #include <sys/bus.h>
     68 
     69 #include <dev/pcmcia/pcmciareg.h>
     70 #include <dev/pcmcia/pcmciavar.h>
     71 #include <dev/pcmcia/pcmciadevs.h>
     72 
     73 #include "xirc.h"
     74 
     75 #if NCOM_XIRC > 0
     76 #include <dev/ic/comreg.h>
     77 #include <dev/ic/comvar.h>
     78 #endif
     79 
     80 #if NXI_XIRC > 0
     81 #include <dev/mii/mii.h>
     82 #include <dev/mii/miivar.h>
     83 
     84 #include <dev/pcmcia/if_xivar.h>
     85 #endif
     86 #include <dev/pcmcia/if_xireg.h>
     87 
     88 struct xirc_softc {
     89 	device_t sc_dev;		/* generic device glue */
     90 
     91 	struct pcmcia_function *sc_pf;	/* our PCMCIA function */
     92 	void *sc_ih;			/* interrupt handle */
     93 
     94 	u_int16_t sc_id;
     95 	u_int8_t sc_mako_intmask;
     96 	int sc_chipset;
     97 
     98 	/*
     99 	 * Data for the Modem portion.
    100 	 */
    101 	device_t sc_modem;
    102 	struct pcmcia_io_handle sc_modem_pcioh;
    103 	int sc_modem_io_window;
    104 
    105 	/*
    106 	 * Data for the Ethernet portion.
    107 	 */
    108 	device_t sc_ethernet;
    109 	struct pcmcia_io_handle sc_ethernet_pcioh;
    110 	int sc_ethernet_io_window;
    111 
    112 	int sc_flags;
    113 #define	XIRC_MODEM_MAPPED	0x01
    114 #define	XIRC_ETHERNET_MAPPED	0x02
    115 #define	XIRC_MODEM_ENABLED	0x04
    116 #define	XIRC_ETHERNET_ENABLED	0x08
    117 #define	XIRC_MODEM_ALLOCED	0x10
    118 #define	XIRC_ETHERNET_ALLOCED	0x20
    119 };
    120 
    121 int	xirc_match(device_t, cfdata_t, void *);
    122 void	xirc_attach(device_t, device_t, void *);
    123 int	xirc_detach(device_t, int);
    124 void	xirc_childdet(device_t, device_t);
    125 
    126 CFATTACH_DECL2_NEW(xirc, sizeof(struct xirc_softc),
    127     xirc_match, xirc_attach, xirc_detach, NULL, NULL, xirc_childdet);
    128 
    129 int	xirc_print(void *, const char *);
    130 
    131 int	xirc_manfid_ciscallback(struct pcmcia_tuple *, void *);
    132 struct pcmcia_config_entry *
    133 	xirc_mako_alloc(struct xirc_softc *);
    134 struct pcmcia_config_entry *
    135 	xirc_dingo_alloc_modem(struct xirc_softc *);
    136 struct pcmcia_config_entry *
    137 	xirc_dingo_alloc_ethernet(struct xirc_softc *);
    138 
    139 int	xirc_enable(struct xirc_softc *, int, int);
    140 void	xirc_disable(struct xirc_softc *, int, int);
    141 
    142 int	xirc_intr(void *);
    143 
    144 int
    145 xirc_match(device_t parent, cfdata_t match,
    146     void *aux)
    147 {
    148 	struct pcmcia_attach_args *pa = aux;
    149 
    150 	/* XXX Toshiba, Accton */
    151 
    152 	if (pa->manufacturer == PCMCIA_VENDOR_COMPAQ2 &&
    153 	    pa->product == PCMCIA_PRODUCT_COMPAQ2_CPQ_10_100)
    154 		return (1);
    155 
    156 	if (pa->manufacturer == PCMCIA_VENDOR_INTEL &&
    157 	    pa->product == PCMCIA_PRODUCT_INTEL_EEPRO100)
    158 		return (1);
    159 
    160 	if (pa->manufacturer == PCMCIA_VENDOR_XIRCOM &&
    161 	    (pa->product & (XIMEDIA_ETHER << 8)) != 0)
    162 		return (2);
    163 
    164 	return (0);
    165 }
    166 
    167 void
    168 xirc_attach(device_t parent, device_t self, void *aux)
    169 {
    170 	struct xirc_softc *sc = device_private(self);
    171 	struct pcmcia_attach_args *pa = aux;
    172 	struct pcmcia_config_entry *cfe;
    173 	int rv;
    174 	int error;
    175 
    176 	sc->sc_dev = self;
    177 
    178 	sc->sc_pf = pa->pf;
    179 
    180 	pcmcia_socket_enable(parent);
    181 	rv = pcmcia_scan_cis(parent, xirc_manfid_ciscallback, &sc->sc_id);
    182 	pcmcia_socket_disable(parent);
    183 	if (!rv) {
    184 		aprint_error_dev(self, "failed to find ID\n");
    185 		return;
    186 	}
    187 
    188 	switch (sc->sc_id & 0x100f) {
    189 	case 0x0001:	/* CE */
    190 	case 0x0002:	/* CE2 */
    191 		sc->sc_chipset = XI_CHIPSET_SCIPPER;
    192 		break;
    193 	case 0x0003:	/* CE3 */
    194 		sc->sc_chipset = XI_CHIPSET_MOHAWK;
    195 		break;
    196 	case 0x1001:
    197 	case 0x1002:
    198 	case 0x1003:
    199 	case 0x1004:
    200 		sc->sc_chipset = XI_CHIPSET_SCIPPER;
    201 		break;
    202 	case 0x1005:
    203 		sc->sc_chipset = XI_CHIPSET_MOHAWK;
    204 		break;
    205 	case 0x1006:
    206 	case 0x1007:
    207 		sc->sc_chipset = XI_CHIPSET_DINGO;
    208 		break;
    209 	default:
    210 		aprint_error_dev(self, "unknown ID %04x\n",
    211 		    sc->sc_id);
    212 		return;
    213 	}
    214 
    215 	aprint_normal_dev(self, "id=%04x\n", sc->sc_id);
    216 
    217 	if (sc->sc_id & (XIMEDIA_MODEM << 8)) {
    218 		if (sc->sc_chipset >= XI_CHIPSET_DINGO) {
    219 			cfe = xirc_dingo_alloc_modem(sc);
    220 			if (cfe && sc->sc_id & (XIMEDIA_ETHER << 8)) {
    221 				if (!xirc_dingo_alloc_ethernet(sc)) {
    222 					pcmcia_io_free(pa->pf,
    223 					    &sc->sc_modem_pcioh);
    224 					cfe = 0;
    225 				}
    226 			}
    227 		} else
    228 			cfe = xirc_mako_alloc(sc);
    229 	} else
    230 		cfe = xirc_dingo_alloc_ethernet(sc);
    231 	if (!cfe) {
    232 		aprint_error_dev(self, "failed to allocate I/O space\n");
    233 		goto fail;
    234 	}
    235 
    236 	/* Enable the card. */
    237 	pcmcia_function_init(pa->pf, cfe);
    238 
    239 	if (sc->sc_id & (XIMEDIA_MODEM << 8)) {
    240 		if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_IO8,
    241 		    &sc->sc_modem_pcioh, &sc->sc_modem_io_window)) {
    242 			aprint_error_dev(self, "unable to map I/O space\n");
    243 			goto fail;
    244 		}
    245 		sc->sc_flags |= XIRC_MODEM_MAPPED;
    246 	}
    247 
    248 	if (sc->sc_id & (XIMEDIA_ETHER << 8)) {
    249 		if (pcmcia_io_map(sc->sc_pf, PCMCIA_WIDTH_AUTO,
    250 		    &sc->sc_ethernet_pcioh, &sc->sc_ethernet_io_window)) {
    251 			aprint_error_dev(self, "unable to map I/O space\n");
    252 			goto fail;
    253 		}
    254 		sc->sc_flags |= XIRC_ETHERNET_MAPPED;
    255 	}
    256 
    257 	error = xirc_enable(sc, XIRC_MODEM_ENABLED|XIRC_ETHERNET_ENABLED,
    258 	    sc->sc_id & (XIMEDIA_MODEM|XIMEDIA_ETHER));
    259 	if (error)
    260 		goto fail;
    261 
    262 	sc->sc_mako_intmask = 0xee;
    263 
    264 	if (sc->sc_id & (XIMEDIA_MODEM << 8))
    265 		/*XXXUNCONST*/
    266 		sc->sc_modem = config_found(self, __UNCONST("com"), xirc_print);
    267 	if (sc->sc_id & (XIMEDIA_ETHER << 8))
    268 		/*XXXUNCONST*/
    269 		sc->sc_ethernet = config_found(self, __UNCONST("xi"),
    270 		    xirc_print);
    271 
    272 	xirc_disable(sc, XIRC_MODEM_ENABLED|XIRC_ETHERNET_ENABLED,
    273 	    sc->sc_id & (XIMEDIA_MODEM|XIMEDIA_ETHER));
    274 	return;
    275 
    276 fail:
    277 	/* I/O spaces will be freed by detach. */
    278 	;
    279 }
    280 
    281 int
    282 xirc_manfid_ciscallback(struct pcmcia_tuple *tuple, void *arg)
    283 {
    284 	u_int16_t *id = arg;
    285 
    286 	if (tuple->code != PCMCIA_CISTPL_MANFID)
    287 		return (0);
    288 
    289 	if (tuple->length < 5)
    290 		return (0);
    291 
    292 	*id = (pcmcia_tuple_read_1(tuple, 3) << 8) |
    293 	      pcmcia_tuple_read_1(tuple, 4);
    294 	return (1);
    295 }
    296 
    297 struct pcmcia_config_entry *
    298 xirc_mako_alloc(struct xirc_softc *sc)
    299 {
    300 	struct pcmcia_config_entry *cfe;
    301 
    302 	SIMPLEQ_FOREACH(cfe, &sc->sc_pf->cfe_head, cfe_list) {
    303 		if (cfe->num_iospace != 1)
    304 			continue;
    305 
    306 		if (pcmcia_io_alloc(sc->sc_pf, cfe->iospace[0].start,
    307 		    cfe->iospace[0].length, cfe->iospace[0].length,
    308 		    &sc->sc_modem_pcioh))
    309 			continue;
    310 
    311 		cfe->iospace[1].start = cfe->iospace[0].start+8;
    312 		cfe->iospace[1].length = 18;
    313 		if (pcmcia_io_alloc(sc->sc_pf, cfe->iospace[1].start,
    314 		    cfe->iospace[1].length, 0x20,
    315 		    &sc->sc_ethernet_pcioh)) {
    316 			cfe->iospace[1].start = cfe->iospace[0].start-24;
    317 			if (pcmcia_io_alloc(sc->sc_pf, cfe->iospace[1].start,
    318 			    cfe->iospace[1].length, 0x20,
    319 			    &sc->sc_ethernet_pcioh))
    320 				continue;
    321 		}
    322 
    323 		/* Found one! */
    324 		sc->sc_flags |= XIRC_MODEM_ALLOCED;
    325 		sc->sc_flags |= XIRC_ETHERNET_ALLOCED;
    326 		return (cfe);
    327 	}
    328 
    329 	return (0);
    330 }
    331 
    332 struct pcmcia_config_entry *
    333 xirc_dingo_alloc_modem(struct xirc_softc *sc)
    334 {
    335 	struct pcmcia_config_entry *cfe;
    336 
    337 	SIMPLEQ_FOREACH(cfe, &sc->sc_pf->cfe_head, cfe_list) {
    338 		if (cfe->num_iospace != 1)
    339 			continue;
    340 
    341 		if (pcmcia_io_alloc(sc->sc_pf, cfe->iospace[0].start,
    342 		    cfe->iospace[0].length, cfe->iospace[0].length,
    343 		    &sc->sc_modem_pcioh))
    344 			continue;
    345 
    346 		/* Found one! */
    347 		sc->sc_flags |= XIRC_MODEM_ALLOCED;
    348 		return (cfe);
    349 	}
    350 
    351 	return (0);
    352 }
    353 
    354 struct pcmcia_config_entry *
    355 xirc_dingo_alloc_ethernet(struct xirc_softc *sc)
    356 {
    357 	struct pcmcia_config_entry *cfe;
    358 	bus_addr_t port;
    359 
    360 	for (port = 0x300; port < 0x400; port += XI_IOSIZE) {
    361 		if (pcmcia_io_alloc(sc->sc_pf, port,
    362 		    XI_IOSIZE, XI_IOSIZE, &sc->sc_ethernet_pcioh))
    363 			continue;
    364 
    365 		/* Found one for the ethernet! */
    366 		sc->sc_flags |= XIRC_ETHERNET_ALLOCED;
    367 		cfe = SIMPLEQ_FIRST(&sc->sc_pf->cfe_head);
    368 		return (cfe);
    369 	}
    370 
    371 	return (0);
    372 }
    373 
    374 int
    375 xirc_print(void *aux, const char *pnp)
    376 {
    377 	const char *name = aux;
    378 
    379 	if (pnp)
    380 		aprint_normal("%s at %s(*)",  name, pnp);
    381 
    382 	return (UNCONF);
    383 }
    384 
    385 void
    386 xirc_childdet(device_t self, device_t child)
    387 {
    388 	struct xirc_softc *sc = device_private(self);
    389 
    390 	if (sc->sc_ethernet == child)
    391 		sc->sc_ethernet = NULL;
    392 
    393 	if (sc->sc_modem == child)
    394 		sc->sc_modem = NULL;
    395 }
    396 
    397 int
    398 xirc_detach(device_t self, int flags)
    399 {
    400 	struct xirc_softc *sc = device_private(self);
    401 	int rv;
    402 
    403 	if (sc->sc_ethernet != NULL) {
    404 		if ((rv = config_detach(sc->sc_ethernet, flags)) != 0)
    405 			return rv;
    406 	}
    407 
    408 	if (sc->sc_modem != NULL) {
    409 		if ((rv = config_detach(sc->sc_modem, flags)) != 0)
    410 			return rv;
    411 	}
    412 
    413 	/* Unmap our i/o windows. */
    414 	if (sc->sc_flags & XIRC_ETHERNET_MAPPED)
    415 		pcmcia_io_unmap(sc->sc_pf, sc->sc_ethernet_io_window);
    416 	if (sc->sc_flags & XIRC_MODEM_MAPPED)
    417 		pcmcia_io_unmap(sc->sc_pf, sc->sc_modem_io_window);
    418 
    419 	/* Free our i/o spaces. */
    420 	if (sc->sc_flags & XIRC_ETHERNET_ALLOCED)
    421 		pcmcia_io_free(sc->sc_pf, &sc->sc_ethernet_pcioh);
    422 	if (sc->sc_flags & XIRC_MODEM_ALLOCED)
    423 		pcmcia_io_free(sc->sc_pf, &sc->sc_modem_pcioh);
    424 	sc->sc_flags = 0;
    425 
    426 	return (0);
    427 }
    428 
    429 int
    430 xirc_intr(void *arg)
    431 {
    432 	struct xirc_softc *sc = arg;
    433 	int rval = 0;
    434 
    435 #if NCOM_XIRC > 0
    436 	if (sc->sc_modem != NULL &&
    437 	    (sc->sc_flags & XIRC_MODEM_ENABLED) != 0)
    438 		rval |= comintr(device_private(sc->sc_modem));
    439 #endif
    440 
    441 #if NXI_XIRC > 0
    442 	if (sc->sc_ethernet != NULL &&
    443 	    (sc->sc_flags & XIRC_ETHERNET_ENABLED) != 0)
    444 		rval |= xi_intr(device_private(sc->sc_ethernet));
    445 #endif
    446 
    447 	return (rval);
    448 }
    449 
    450 int
    451 xirc_enable(struct xirc_softc *sc, int flag, int media)
    452 {
    453 	int error;
    454 
    455 	if ((sc->sc_flags & flag) == flag) {
    456 		printf("%s: already enabled\n", device_xname(sc->sc_dev));
    457 		return (0);
    458 	}
    459 
    460 	if ((sc->sc_flags & (XIRC_MODEM_ENABLED|XIRC_ETHERNET_ENABLED)) != 0) {
    461 		sc->sc_flags |= flag;
    462 		return (0);
    463 	}
    464 
    465 	/*
    466 	 * Establish our interrupt handler.
    467 	 *
    468 	 * XXX Note, we establish this at IPL_NET.  This is suboptimal
    469 	 * XXX the Modem portion, but is necessary to make the Ethernet
    470 	 * XXX portion have the correct interrupt level semantics.
    471 	 *
    472 	 * XXX Eventually we should use the `enabled' bits in the
    473 	 * XXX flags word to determine which level we should be at.
    474 	 */
    475 	sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET, xirc_intr, sc);
    476 	if (!sc->sc_ih)
    477 		return (EIO);
    478 
    479 	error = pcmcia_function_enable(sc->sc_pf);
    480 	if (error) {
    481 		pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
    482 		sc->sc_ih = 0;
    483 		return (error);
    484 	}
    485 
    486 	sc->sc_flags |= flag;
    487 
    488 	if (sc->sc_chipset < XI_CHIPSET_DINGO &&
    489 	    sc->sc_id & (XIMEDIA_MODEM << 8)) {
    490 		sc->sc_mako_intmask |= media;
    491 		bus_space_write_1(sc->sc_ethernet_pcioh.iot,
    492 		    sc->sc_ethernet_pcioh.ioh, 0x10, sc->sc_mako_intmask);
    493 	}
    494 
    495 	return (0);
    496 }
    497 
    498 void
    499 xirc_disable(struct xirc_softc *sc, int flag, int media)
    500 {
    501 
    502 	if ((sc->sc_flags & flag) == 0) {
    503 		printf("%s: already disabled\n", device_xname(sc->sc_dev));
    504 		return;
    505 	}
    506 
    507 	if (sc->sc_chipset < XI_CHIPSET_DINGO &&
    508 	    sc->sc_id & (XIMEDIA_MODEM << 8)) {
    509 		sc->sc_mako_intmask &= ~media;
    510 		bus_space_write_1(sc->sc_ethernet_pcioh.iot,
    511 		    sc->sc_ethernet_pcioh.ioh, 0x10, sc->sc_mako_intmask);
    512 	}
    513 
    514 	sc->sc_flags &= ~flag;
    515 	if ((sc->sc_flags & (XIRC_MODEM_ENABLED|XIRC_ETHERNET_ENABLED)) != 0)
    516 		return;
    517 
    518 	pcmcia_function_disable(sc->sc_pf);
    519 	pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
    520 	sc->sc_ih = 0;
    521 }
    522 
    523 /****** Here begins the com attachment code. ******/
    524 
    525 #if NCOM_XIRC > 0
    526 int	com_xirc_match(device_t, cfdata_t , void *);
    527 void	com_xirc_attach(device_t, device_t, void *);
    528 int	com_xirc_detach(device_t, int);
    529 
    530 /* No xirc-specific goo in the softc; it's all in the parent. */
    531 CFATTACH_DECL_NEW(com_xirc, sizeof(struct com_softc),
    532     com_xirc_match, com_xirc_attach, com_detach, NULL);
    533 
    534 int	com_xirc_enable(struct com_softc *);
    535 void	com_xirc_disable(struct com_softc *);
    536 
    537 int
    538 com_xirc_match(device_t parent, cfdata_t match, void *aux)
    539 {
    540 	extern struct cfdriver com_cd;
    541 	const char *name = aux;
    542 
    543 	if (strcmp(name, com_cd.cd_name) == 0)
    544 		return (1);
    545 
    546 	return (0);
    547 }
    548 
    549 void
    550 com_xirc_attach(device_t parent, device_t self, void *aux)
    551 {
    552 	struct com_softc *sc = device_private(self);
    553 	struct xirc_softc *msc = device_private(parent);
    554 
    555 	sc->sc_dev = self;
    556 
    557 	aprint_normal("\n");
    558 
    559 	COM_INIT_REGS(sc->sc_regs,
    560 	    msc->sc_modem_pcioh.iot,
    561 	    msc->sc_modem_pcioh.ioh,
    562 	    -1);
    563 
    564 	sc->enabled = 1;
    565 
    566 	sc->sc_frequency = COM_FREQ;
    567 
    568 	sc->enable = com_xirc_enable;
    569 	sc->disable = com_xirc_disable;
    570 
    571 	aprint_normal("%s", device_xname(self));
    572 
    573 	com_attach_subr(sc);
    574 
    575 	sc->enabled = 0;
    576 }
    577 
    578 int
    579 com_xirc_enable(struct com_softc *sc)
    580 {
    581 	struct xirc_softc *msc =
    582 	    device_private(device_parent(sc->sc_dev));
    583 
    584 	return (xirc_enable(msc, XIRC_MODEM_ENABLED, XIMEDIA_MODEM));
    585 }
    586 
    587 void
    588 com_xirc_disable(struct com_softc *sc)
    589 {
    590 	struct xirc_softc *msc =
    591 	    device_private(device_parent(sc->sc_dev));
    592 
    593 	xirc_disable(msc, XIRC_MODEM_ENABLED, XIMEDIA_MODEM);
    594 }
    595 
    596 #endif /* NCOM_XIRC > 0 */
    597 
    598 /****** Here begins the xi attachment code. ******/
    599 
    600 #if NXI_XIRC > 0
    601 int	xi_xirc_match(device_t, cfdata_t, void *);
    602 void	xi_xirc_attach(device_t, device_t, void *);
    603 
    604 /* No xirc-specific goo in the softc; it's all in the parent. */
    605 CFATTACH_DECL_NEW(xi_xirc, sizeof(struct xi_softc),
    606     xi_xirc_match, xi_xirc_attach, xi_detach, NULL);
    607 
    608 int	xi_xirc_enable(struct xi_softc *);
    609 void	xi_xirc_disable(struct xi_softc *);
    610 int	xi_xirc_lan_nid_ciscallback(struct pcmcia_tuple *, void *);
    611 
    612 int
    613 xi_xirc_match(device_t parent, cfdata_t match, void *aux)
    614 {
    615 	extern struct cfdriver xi_cd;
    616 	const char *name = aux;
    617 
    618 	if (strcmp(name, xi_cd.cd_name) == 0)
    619 		return (1);
    620 
    621 	return (0);
    622 }
    623 
    624 void
    625 xi_xirc_attach(device_t parent, device_t self, void *aux)
    626 {
    627 	struct xi_softc *sc = device_private(self);
    628 	struct xirc_softc *msc = device_private(parent);
    629 	u_int8_t myla[ETHER_ADDR_LEN];
    630 
    631 	sc->sc_dev = self;
    632 
    633 	aprint_normal("\n");
    634 
    635 	sc->sc_bst = msc->sc_ethernet_pcioh.iot;
    636 	sc->sc_bsh = msc->sc_ethernet_pcioh.ioh;
    637 
    638 	sc->sc_chipset = msc->sc_chipset;
    639 
    640 	sc->sc_enable = xi_xirc_enable;
    641 	sc->sc_disable = xi_xirc_disable;
    642 
    643 	if (!pcmcia_scan_cis(device_parent(msc->sc_dev),
    644 	    xi_xirc_lan_nid_ciscallback, myla)) {
    645 		aprint_error_dev(self, "can't find MAC address\n");
    646 		return;
    647 	}
    648 
    649 	/* Perform generic initialization. */
    650 	xi_attach(sc, myla);
    651 }
    652 
    653 int
    654 xi_xirc_enable(struct xi_softc *sc)
    655 {
    656 	struct xirc_softc *msc = device_private(device_parent(sc->sc_dev));
    657 
    658 	return (xirc_enable(msc, XIRC_ETHERNET_ENABLED, XIMEDIA_ETHER));
    659 }
    660 
    661 void
    662 xi_xirc_disable(struct xi_softc *sc)
    663 {
    664 	struct xirc_softc *msc = device_private(device_parent(sc->sc_dev));
    665 
    666 	xirc_disable(msc, XIRC_ETHERNET_ENABLED, XIMEDIA_ETHER);
    667 }
    668 
    669 int
    670 xi_xirc_lan_nid_ciscallback(struct pcmcia_tuple *tuple, void *arg)
    671 {
    672 	u_int8_t *myla = arg;
    673 	int i;
    674 
    675 	if (tuple->length < 2)
    676 		return (0);
    677 
    678 	switch (tuple->code) {
    679 	case PCMCIA_CISTPL_FUNCE:
    680 		switch (pcmcia_tuple_read_1(tuple, 0)) {
    681 		case PCMCIA_TPLFE_TYPE_LAN_NID:
    682 			if (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
    683 				return (0);
    684 			for (i = 0; i < ETHER_ADDR_LEN; i++)
    685 				myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
    686 			return (1);
    687 
    688 		case 0x02:
    689 			/*
    690 			 * Not sure about this, I don't have a CE2
    691 			 * that puts the ethernet addr here.
    692 			 */
    693 		 	if (pcmcia_tuple_read_1(tuple, 1) != 0x01 ||
    694 			    pcmcia_tuple_read_1(tuple, 2) != ETHER_ADDR_LEN)
    695 				return (0);
    696 			for (i = 0; i < ETHER_ADDR_LEN; i++)
    697 				myla[i] = pcmcia_tuple_read_1(tuple, i + 3);
    698 			return (1);
    699 		}
    700 
    701 	case 0x89:
    702 		if (pcmcia_tuple_read_1(tuple, 0) != 0x04 ||
    703 		    pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN)
    704 			return (0);
    705 		for (i = 0; i < ETHER_ADDR_LEN; i++)
    706 			myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
    707 		return (1);
    708 	}
    709 
    710 	return (0);
    711 }
    712 
    713 #endif /* NXI_XIRC > 0 */
    714