Index: head/sys/dev/aic/aic_pccard.c =================================================================== --- head/sys/dev/aic/aic_pccard.c (revision 292078) +++ head/sys/dev/aic/aic_pccard.c (revision 292079) @@ -1,198 +1,199 @@ /*- * Copyright (c) 1999 Luoqi Chen. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" struct aic_pccard_softc { struct aic_softc sc_aic; struct resource *sc_port; struct resource *sc_irq; void *sc_ih; }; static int aic_pccard_alloc_resources(device_t); static void aic_pccard_release_resources(device_t); static int aic_pccard_probe(device_t); static int aic_pccard_attach(device_t); static const struct pccard_product aic_pccard_products[] = { PCMCIA_CARD(ADAPTEC, APA1460), PCMCIA_CARD(ADAPTEC, APA1460A), PCMCIA_CARD(NEWMEDIA, BUSTOASTER), PCMCIA_CARD(NEWMEDIA, BUSTOASTER2), PCMCIA_CARD(NEWMEDIA, BUSTOASTER3), { NULL } }; #define AIC_PCCARD_PORTSIZE 0x20 static int aic_pccard_alloc_resources(device_t dev) { struct aic_pccard_softc *sc = device_get_softc(dev); int rid; sc->sc_port = sc->sc_irq = NULL; rid = 0; sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, AIC_PCCARD_PORTSIZE, RF_ACTIVE); if (!sc->sc_port) return (ENOMEM); rid = 0; sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!sc->sc_irq) { aic_pccard_release_resources(dev); return (ENOMEM); } sc->sc_aic.dev = dev; sc->sc_aic.res = sc->sc_port; mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF); return (0); } static void aic_pccard_release_resources(device_t dev) { struct aic_pccard_softc *sc = device_get_softc(dev); if (sc->sc_port) bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port); if (sc->sc_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq); sc->sc_port = sc->sc_irq = NULL; mtx_destroy(&sc->sc_aic.lock); } static int aic_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, aic_pccard_products, sizeof(aic_pccard_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); else device_set_desc(dev, "Adaptec 6260/6360 SCSI controller"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int aic_pccard_attach(device_t dev) { struct aic_pccard_softc *sc = device_get_softc(dev); struct aic_softc *aic = &sc->sc_aic; int error; if (aic_pccard_alloc_resources(dev)) return (ENXIO); if (aic_probe(aic)) { aic_pccard_release_resources(dev); return (ENXIO); } error = aic_attach(aic); if (error) { device_printf(dev, "attach failed\n"); aic_pccard_release_resources(dev); return (error); } error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih); if (error) { device_printf(dev, "failed to register interrupt handler\n"); aic_pccard_release_resources(dev); return (error); } return (0); } static int aic_pccard_detach(device_t dev) { struct aic_pccard_softc *sc = device_get_softc(dev); struct aic_softc *aic = &sc->sc_aic; int error; error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih); if (error) { device_printf(dev, "failed to unregister interrupt handler\n"); } error = aic_detach(aic); if (error) { device_printf(dev, "detach failed\n"); return (error); } aic_pccard_release_resources(dev); return (0); } static device_method_t aic_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, aic_pccard_probe), DEVMETHOD(device_attach, aic_pccard_attach), DEVMETHOD(device_detach, aic_pccard_detach), { 0, 0 } }; static driver_t aic_pccard_driver = { "aic", aic_pccard_methods, sizeof(struct aic_pccard_softc), }; extern devclass_t aic_devclass; MODULE_DEPEND(aic, cam, 1,1,1); DRIVER_MODULE(aic, pccard, aic_pccard_driver, aic_devclass, 0, 0); +PCCARD_PNP_INFO(aic_pccard_products); Index: head/sys/dev/an/if_an_pccard.c =================================================================== --- head/sys/dev/an/if_an_pccard.c (revision 292078) +++ head/sys/dev/an/if_an_pccard.c (revision 292079) @@ -1,157 +1,158 @@ /*- * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Aironet 4500/4800 802.11 PCMCIA/ISA/PCI driver for FreeBSD. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ #include __FBSDID("$FreeBSD$"); #include "opt_inet.h" #ifdef INET #define ANCACHE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" #include "card_if.h" /* * Support for PCMCIA cards. */ static int an_pccard_probe(device_t); static int an_pccard_attach(device_t); static device_method_t an_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, an_pccard_probe), DEVMETHOD(device_attach, an_pccard_attach), DEVMETHOD(device_detach, an_detach), DEVMETHOD(device_shutdown, an_shutdown), { 0, 0 } }; static driver_t an_pccard_driver = { "an", an_pccard_methods, sizeof(struct an_softc) }; static devclass_t an_pccard_devclass; DRIVER_MODULE(an, pccard, an_pccard_driver, an_pccard_devclass, 0, 0); MODULE_DEPEND(an, wlan, 1, 1, 1); static const struct pccard_product an_pccard_products[] = { PCMCIA_CARD(AIRONET, PC4800), PCMCIA_CARD(AIRONET, PC4500), PCMCIA_CARD(AIRONET, 350), PCMCIA_CARD(XIRCOM, CWE1130), { NULL } }; +PCCARD_PNP_INFO(an_pccard_products); static int an_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, an_pccard_products, sizeof(an_pccard_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return (0); } return (ENXIO); } static int an_pccard_attach(device_t dev) { struct an_softc *sc = device_get_softc(dev); int flags = device_get_flags(dev); int error; error = an_probe(dev); /* 0 is failure for now */ if (error == 0) { error = ENXIO; goto fail; } error = an_alloc_irq(dev, 0, 0); if (error != 0) goto fail; an_alloc_irq(dev, sc->irq_rid, 0); error = an_attach(sc, flags); if (error) goto fail; /* * Must setup the interrupt after the an_attach to prevent racing. */ error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, NULL, an_intr, sc, &sc->irq_handle); fail: if (error) an_release_resources(dev); return (error); } Index: head/sys/dev/ata/ata-card.c =================================================================== --- head/sys/dev/ata/ata-card.c (revision 292078) +++ head/sys/dev/ata/ata-card.c (revision 292079) @@ -1,185 +1,186 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification, immediately at the beginning of the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product ata_pccard_products[] = { PCMCIA_CARD(FREECOM, PCCARDIDE), PCMCIA_CARD(EXP, EXPMULTIMEDIA), PCMCIA_CARD(IODATA3, CBIDE2), PCMCIA_CARD(OEM2, CDROM1), PCMCIA_CARD(OEM2, IDE), PCMCIA_CARD(PANASONIC, KXLC005), PCMCIA_CARD(TEAC, IDECARDII), {NULL} }; static int ata_pccard_probe(device_t dev) { const struct pccard_product *pp; u_int32_t fcn = PCCARD_FUNCTION_UNSPEC; int error = 0; if ((error = pccard_get_function(dev, &fcn))) return error; /* if it says its a disk we should register it */ if (fcn == PCCARD_FUNCTION_DISK) return 0; /* match other devices here, primarily cdrom/dvd rom */ if ((pp = pccard_product_lookup(dev, ata_pccard_products, sizeof(ata_pccard_products[0]), NULL))) { if (pp->pp_name) device_set_desc(dev, pp->pp_name); return 0; } return ENXIO; } static int ata_pccard_attach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); struct resource *io, *ctlio; int i, rid, err; uint16_t funce; if (ch->attached) return (0); ch->attached = 1; /* allocate the io range to get start and length */ rid = ATA_IOADDR_RID; if (!(io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_IOSIZE, RF_ACTIVE))) return (ENXIO); /* setup the resource vectors */ for (i = ATA_DATA; i <= ATA_COMMAND; i++) { ch->r_io[i].res = io; ch->r_io[i].offset = i; } ch->r_io[ATA_IDX_ADDR].res = io; /* * if we got more than the default ATA_IOSIZE ports, this is a device * where ctlio is located at offset 14 into "normal" io space. */ if (rman_get_size(io) > ATA_IOSIZE) { ch->r_io[ATA_CONTROL].res = io; ch->r_io[ATA_CONTROL].offset = 14; } else { rid = ATA_CTLADDR_RID; if (!(ctlio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, ATA_CTLIOSIZE, RF_ACTIVE))) { bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io); for (i = ATA_DATA; i < ATA_MAX_RES; i++) ch->r_io[i].res = NULL; return (ENXIO); } ch->r_io[ATA_CONTROL].res = ctlio; ch->r_io[ATA_CONTROL].offset = 0; } ata_default_registers(dev); /* initialize softc for this channel */ ch->unit = 0; ch->flags |= ATA_USE_16BIT; funce = 0; /* Default to sane setting of FUNCE */ pccard_get_funce_disk(dev, &funce); if (!(funce & PFD_I_D)) ch-> flags |= ATA_NO_SLAVE; ata_generic_hw(dev); err = ata_probe(dev); if (err > 0) return (err); return (ata_attach(dev)); } static int ata_pccard_detach(device_t dev) { struct ata_channel *ch = device_get_softc(dev); int i; if (!ch->attached) return (0); ch->attached = 0; ata_detach(dev); if (ch->r_io[ATA_CONTROL].res != ch->r_io[ATA_DATA].res) bus_release_resource(dev, SYS_RES_IOPORT, ATA_CTLADDR_RID, ch->r_io[ATA_CONTROL].res); bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, ch->r_io[ATA_DATA].res); for (i = ATA_DATA; i < ATA_MAX_RES; i++) ch->r_io[i].res = NULL; return 0; } static device_method_t ata_pccard_methods[] = { /* device interface */ DEVMETHOD(device_probe, ata_pccard_probe), DEVMETHOD(device_attach, ata_pccard_attach), DEVMETHOD(device_detach, ata_pccard_detach), DEVMETHOD_END }; static driver_t ata_pccard_driver = { "ata", ata_pccard_methods, sizeof(struct ata_channel), }; DRIVER_MODULE(ata, pccard, ata_pccard_driver, ata_devclass, NULL, NULL); MODULE_DEPEND(ata, ata, 1, 1, 1); +PCCARD_PNP_INFO(ata_pccard_products); Index: head/sys/dev/cmx/cmx_pccard.c =================================================================== --- head/sys/dev/cmx/cmx_pccard.c (revision 292078) +++ head/sys/dev/cmx/cmx_pccard.c (revision 292079) @@ -1,115 +1,115 @@ /*- * Copyright (c) 2006-2007 Daniel Roethlisberger * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product cmx_pccard_products[] = { PCMCIA_CARD(OMNIKEY, CM4040), { NULL } }; /* * Probe for the card. */ static int cmx_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, cmx_pccard_products, sizeof(cmx_pccard_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return 0; } return EIO; } /* * Attach to the pccard, and call bus independant attach and * resource allocation routines. */ static int cmx_pccard_attach(device_t dev) { int rv = 0; cmx_init_softc(dev); if ((rv = cmx_alloc_resources(dev)) != 0) { device_printf(dev, "cmx_alloc_resources() failed!\n"); cmx_release_resources(dev); return rv; } if ((rv = cmx_attach(dev)) != 0) { device_printf(dev, "cmx_attach() failed!\n"); cmx_release_resources(dev); return rv; } device_printf(dev, "attached\n"); return 0; } static device_method_t cmx_pccard_methods[] = { DEVMETHOD(device_probe, cmx_pccard_probe), DEVMETHOD(device_attach, cmx_pccard_attach), DEVMETHOD(device_detach, cmx_detach), { 0, 0 } }; static driver_t cmx_pccard_driver = { "cmx", cmx_pccard_methods, sizeof(struct cmx_softc), }; DRIVER_MODULE(cmx, pccard, cmx_pccard_driver, cmx_devclass, 0, 0); - +PCCARD_PNP_INFO(cmx_pccard_products); Index: head/sys/dev/cs/if_cs_pccard.c =================================================================== --- head/sys/dev/cs/if_cs_pccard.c (revision 292078) +++ head/sys/dev/cs/if_cs_pccard.c (revision 292079) @@ -1,117 +1,119 @@ /*- * Copyright (c) 1999 M. Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" static const struct pccard_product cs_pccard_products[] = { PCMCIA_CARD(IBM, ETHERJET), { NULL } }; + static int cs_pccard_probe(device_t dev) { const struct pccard_product *pp; uint32_t fcn = PCCARD_FUNCTION_UNSPEC; /* Make sure we're a network function */ pccard_get_function(dev, &fcn); if (fcn != PCCARD_FUNCTION_NETWORK) return (ENXIO); if ((pp = pccard_product_lookup(dev, cs_pccard_products, sizeof(cs_pccard_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return 0; } return EIO; } static int cs_pccard_attach(device_t dev) { struct cs_softc *sc = device_get_softc(dev); int error; sc->flags |= CS_NO_IRQ; error = cs_cs89x0_probe(dev); if (error != 0) return (error); error = cs_alloc_irq(dev, sc->irq_rid); if (error != 0) goto bad; return (cs_attach(dev)); bad: cs_release_resources(dev); return (error); } static device_method_t cs_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cs_pccard_probe), DEVMETHOD(device_attach, cs_pccard_attach), DEVMETHOD(device_detach, cs_detach), { 0, 0 } }; static driver_t cs_pccard_driver = { "cs", cs_pccard_methods, sizeof(struct cs_softc), }; extern devclass_t cs_devclass; DRIVER_MODULE(cs, pccard, cs_pccard_driver, cs_devclass, 0, 0); MODULE_DEPEND(cs, ether, 1, 1, 1); +PCCARD_PNP_INFO(cs_pccard_products); Index: head/sys/dev/ed/if_ed_pccard.c =================================================================== --- head/sys/dev/ed/if_ed_pccard.c (revision 292078) +++ head/sys/dev/ed/if_ed_pccard.c (revision 292079) @@ -1,1250 +1,1251 @@ /*- * Copyright (c) 2005, M. Warner Losh * Copyright (c) 1995, David Greenman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Notes for adding media support. Each chipset is somewhat different * from the others. Linux has a table of OIDs that it uses to see what * supports the misc register of the NS83903. But a sampling of datasheets * I could dig up on cards I own paints a different picture. * * Chipset specific details: * NS 83903/902A paired * ccr base 0x1020 * id register at 0x1000: 7-3 = 0, 2-0 = 1. * (maybe this test is too week) * misc register at 0x018: * 6 WAIT_TOUTENABLE enable watchdog timeout * 3 AUI/TPI 1 AUX, 0 TPI * 2 loopback * 1 gdlink (tpi mode only) 1 tp good, 0 tp bad * 0 0-no mam, 1 mam connected * * NS83926 appears to be a NS pcmcia glue chip used on the IBM Ethernet II * and the NEC PC9801N-J12 ccr base 0x2000! * * winbond 289c926 * ccr base 0xfd0 * cfb (am 0xff2): * 0-1 PHY01 00 TPI, 01 10B2, 10 10B5, 11 TPI (reduced squ) * 2 LNKEN 0 - enable link and auto switch, 1 disable * 3 LNKSTS TPI + LNKEN=0 + link good == 1, else 0 * sr (am 0xff4) * 88 00 88 00 88 00, etc * * TMI tc3299a (cr PHY01 == 0) * ccr base 0x3f8 * cra (io 0xa) * crb (io 0xb) * 0-1 PHY01 00 auto, 01 res, 10 10B5, 11 TPI * 2 GDLINK 1 disable checking of link * 6 LINK 0 bad link, 1 good link * * EN5017A, EN5020 no data, but very popular * Other chips? * NetBSD supports RTL8019, but none have surfaced that I can see */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" /* "device miibus" required. See GENERIC if you get errors here. */ #include "miibus_if.h" #include "pccarddevs.h" /* * NE-2000 based PC Cards have a number of ways to get the MAC address. * Some cards encode this as a FUNCE. Others have this in the ROMs the * same way that ISA cards do. Some have it encoded in the attribute * memory somewhere that isn't in the CIS. Some new chipsets have it * in special registers in the ASIC part of the chip. * * For those cards that have the MAC adress stored in attribute memory * outside of a FUNCE entry in the CIS, nearly all of them have it at * a fixed offset (0xff0). We use that offset as a source of last * resource if other offsets have failed. This is the address of the * National Semiconductor DP83903A, which is the only chip's datasheet * I've found. */ #define ED_DEFAULT_MAC_OFFSET 0xff0 static const struct ed_product { struct pccard_product prod; int flags; #define NE2000DVF_DL100XX 0x0001 /* chip is D-Link DL10019/22 */ #define NE2000DVF_AX88X90 0x0002 /* chip is ASIX AX88[17]90 */ #define NE2000DVF_TC5299J 0x0004 /* chip is Tamarack TC5299J */ #define NE2000DVF_TOSHIBA 0x0008 /* Toshiba DP83902A */ #define NE2000DVF_ENADDR 0x0100 /* Get MAC from attr mem */ #define NE2000DVF_ANYFUNC 0x0200 /* Allow any function type */ #define NE2000DVF_MODEM 0x0400 /* Has a modem/serial */ int enoff; } ed_pccard_products[] = { { PCMCIA_CARD(ACCTON, EN2212), 0}, { PCMCIA_CARD(ACCTON, EN2216), 0}, { PCMCIA_CARD(ALLIEDTELESIS, LA_PCM), 0}, { PCMCIA_CARD(AMBICOM, AMB8002), 0}, { PCMCIA_CARD(AMBICOM, AMB8002T), 0}, { PCMCIA_CARD(AMBICOM, AMB8010), 0}, { PCMCIA_CARD(AMBICOM, AMB8010_ALT), 0}, { PCMCIA_CARD(AMBICOM, AMB8610), 0}, { PCMCIA_CARD(BILLIONTON, CFLT10N), 0}, { PCMCIA_CARD(BILLIONTON, LNA100B), NE2000DVF_AX88X90}, { PCMCIA_CARD(BILLIONTON, LNT10TB), 0}, { PCMCIA_CARD(BILLIONTON, LNT10TN), 0}, { PCMCIA_CARD(BROMAX, AXNET), NE2000DVF_AX88X90}, { PCMCIA_CARD(BROMAX, IPORT), 0}, { PCMCIA_CARD(BROMAX, IPORT2), 0}, { PCMCIA_CARD(BUFFALO, LPC2_CLT), 0}, { PCMCIA_CARD(BUFFALO, LPC3_CLT), 0}, { PCMCIA_CARD(BUFFALO, LPC3_CLX), NE2000DVF_AX88X90}, { PCMCIA_CARD(BUFFALO, LPC4_TX), NE2000DVF_AX88X90}, { PCMCIA_CARD(BUFFALO, LPC4_CLX), NE2000DVF_AX88X90}, { PCMCIA_CARD(BUFFALO, LPC_CF_CLT), 0}, { PCMCIA_CARD(CNET, NE2000), 0}, { PCMCIA_CARD(COMPEX, AX88190), NE2000DVF_AX88X90}, { PCMCIA_CARD(COMPEX, LANMODEM), 0}, { PCMCIA_CARD(COMPEX, LINKPORT_ENET_B), 0}, { PCMCIA_CARD(COREGA, ETHER_II_PCC_T), 0}, { PCMCIA_CARD(COREGA, ETHER_II_PCC_TD), 0}, { PCMCIA_CARD(COREGA, ETHER_PCC_T), 0}, { PCMCIA_CARD(COREGA, ETHER_PCC_TD), 0}, { PCMCIA_CARD(COREGA, FAST_ETHER_PCC_TX), NE2000DVF_DL100XX}, { PCMCIA_CARD(COREGA, FETHER_PCC_TXD), NE2000DVF_AX88X90}, { PCMCIA_CARD(COREGA, FETHER_PCC_TXF), NE2000DVF_DL100XX}, { PCMCIA_CARD(COREGA, FETHER_II_PCC_TXD), NE2000DVF_AX88X90}, { PCMCIA_CARD(COREGA, LAPCCTXD), 0}, { PCMCIA_CARD(DAYNA, COMMUNICARD_E_1), 0}, { PCMCIA_CARD(DAYNA, COMMUNICARD_E_2), 0}, { PCMCIA_CARD(DLINK, DE650), NE2000DVF_ANYFUNC }, { PCMCIA_CARD(DLINK, DE660), 0 }, { PCMCIA_CARD(DLINK, DE660PLUS), 0}, { PCMCIA_CARD(DYNALINK, L10C), 0}, { PCMCIA_CARD(EDIMAX, EP4000A), 0}, { PCMCIA_CARD(EPSON, EEN10B), 0}, { PCMCIA_CARD(EXP, THINLANCOMBO), 0}, { PCMCIA_CARD(GLOBALVILLAGE, LANMODEM), 0}, { PCMCIA_CARD(GREY_CELL, TDK3000), 0}, { PCMCIA_CARD(GREY_CELL, DMF650TX), NE2000DVF_ANYFUNC | NE2000DVF_DL100XX | NE2000DVF_MODEM}, { PCMCIA_CARD(GVC, NIC_2000P), 0}, { PCMCIA_CARD(IBM, HOME_AND_AWAY), 0}, { PCMCIA_CARD(IBM, INFOMOVER), 0}, { PCMCIA_CARD(IODATA3, PCLAT), 0}, { PCMCIA_CARD(KINGSTON, CIO10T), 0}, { PCMCIA_CARD(KINGSTON, KNE2), 0}, { PCMCIA_CARD(LANTECH, FASTNETTX), NE2000DVF_AX88X90}, /* Same ID for many different cards, including generic NE2000 */ { PCMCIA_CARD(LINKSYS, COMBO_ECARD), NE2000DVF_DL100XX | NE2000DVF_AX88X90}, { PCMCIA_CARD(LINKSYS, ECARD_1), 0}, { PCMCIA_CARD(LINKSYS, ECARD_2), 0}, { PCMCIA_CARD(LINKSYS, ETHERFAST), NE2000DVF_DL100XX}, { PCMCIA_CARD(LINKSYS, TRUST_COMBO_ECARD), 0}, { PCMCIA_CARD(MACNICA, ME1_JEIDA), 0}, { PCMCIA_CARD(MAGICRAM, ETHER), 0}, { PCMCIA_CARD(MELCO, LPC3_CLX), NE2000DVF_AX88X90}, { PCMCIA_CARD(MELCO, LPC3_TX), NE2000DVF_AX88X90}, { PCMCIA_CARD(MELCO2, LPC2_T), 0}, { PCMCIA_CARD(MELCO2, LPC2_TX), 0}, { PCMCIA_CARD(MITSUBISHI, B8895), NE2000DVF_ANYFUNC}, /* NG */ { PCMCIA_CARD(MICRORESEARCH, MR10TPC), 0}, { PCMCIA_CARD(NDC, ND5100_E), 0}, { PCMCIA_CARD(NETGEAR, FA410TXC), NE2000DVF_DL100XX}, /* Same ID as DLINK DFE-670TXD. 670 has DL10022, fa411 has ax88790 */ { PCMCIA_CARD(NETGEAR, FA411), NE2000DVF_AX88X90 | NE2000DVF_DL100XX}, { PCMCIA_CARD(NEXTCOM, NEXTHAWK), 0}, { PCMCIA_CARD(NEWMEDIA, LANSURFER), NE2000DVF_ANYFUNC}, { PCMCIA_CARD(NEWMEDIA, LIVEWIRE), 0}, { PCMCIA_CARD(OEM2, 100BASE), NE2000DVF_AX88X90}, { PCMCIA_CARD(OEM2, ETHERNET), 0}, { PCMCIA_CARD(OEM2, FAST_ETHERNET), NE2000DVF_AX88X90}, { PCMCIA_CARD(OEM2, NE2000), 0}, { PCMCIA_CARD(PLANET, SMARTCOM2000), 0 }, { PCMCIA_CARD(PREMAX, PE200), 0}, { PCMCIA_CARD(PSION, LANGLOBAL), NE2000DVF_ANYFUNC | NE2000DVF_AX88X90 | NE2000DVF_MODEM}, { PCMCIA_CARD(RACORE, ETHERNET), 0}, { PCMCIA_CARD(RACORE, FASTENET), NE2000DVF_AX88X90}, { PCMCIA_CARD(RACORE, 8041TX), NE2000DVF_AX88X90 | NE2000DVF_TC5299J}, { PCMCIA_CARD(RELIA, COMBO), 0}, { PCMCIA_CARD(RIOS, PCCARD3), 0}, { PCMCIA_CARD(RPTI, EP400), 0}, { PCMCIA_CARD(RPTI, EP401), 0}, { PCMCIA_CARD(SMC, EZCARD), 0}, { PCMCIA_CARD(SOCKET, EA_ETHER), 0}, { PCMCIA_CARD(SOCKET, ES_1000), 0}, { PCMCIA_CARD(SOCKET, LP_ETHER), 0}, { PCMCIA_CARD(SOCKET, LP_ETHER_CF), 0}, { PCMCIA_CARD(SOCKET, LP_ETH_10_100_CF), NE2000DVF_DL100XX}, { PCMCIA_CARD(SVEC, COMBOCARD), 0}, { PCMCIA_CARD(SVEC, LANCARD), 0}, { PCMCIA_CARD(TAMARACK, ETHERNET), 0}, { PCMCIA_CARD(TDK, CFE_10), 0}, { PCMCIA_CARD(TDK, LAK_CD031), 0}, { PCMCIA_CARD(TDK, DFL5610WS), 0}, { PCMCIA_CARD(TELECOMDEVICE, LM5LT), 0 }, { PCMCIA_CARD(TELECOMDEVICE, TCD_HPC100), NE2000DVF_AX88X90}, { PCMCIA_CARD(TJ, PTJ_LAN_T), 0 }, { PCMCIA_CARD(TOSHIBA2, LANCT00A), NE2000DVF_ANYFUNC | NE2000DVF_TOSHIBA}, { PCMCIA_CARD(ZONET, ZEN), 0}, { { NULL } } }; /* * MII bit-bang glue */ static uint32_t ed_pccard_dl100xx_mii_bitbang_read(device_t dev); static void ed_pccard_dl100xx_mii_bitbang_write(device_t dev, uint32_t val); static const struct mii_bitbang_ops ed_pccard_dl100xx_mii_bitbang_ops = { ed_pccard_dl100xx_mii_bitbang_read, ed_pccard_dl100xx_mii_bitbang_write, { ED_DL100XX_MII_DATAOUT, /* MII_BIT_MDO */ ED_DL100XX_MII_DATAIN, /* MII_BIT_MDI */ ED_DL100XX_MII_CLK, /* MII_BIT_MDC */ ED_DL100XX_MII_DIROUT, /* MII_BIT_DIR_HOST_PHY */ 0 /* MII_BIT_DIR_PHY_HOST */ } }; static uint32_t ed_pccard_ax88x90_mii_bitbang_read(device_t dev); static void ed_pccard_ax88x90_mii_bitbang_write(device_t dev, uint32_t val); static const struct mii_bitbang_ops ed_pccard_ax88x90_mii_bitbang_ops = { ed_pccard_ax88x90_mii_bitbang_read, ed_pccard_ax88x90_mii_bitbang_write, { ED_AX88X90_MII_DATAOUT, /* MII_BIT_MDO */ ED_AX88X90_MII_DATAIN, /* MII_BIT_MDI */ ED_AX88X90_MII_CLK, /* MII_BIT_MDC */ 0, /* MII_BIT_DIR_HOST_PHY */ ED_AX88X90_MII_DIRIN /* MII_BIT_DIR_PHY_HOST */ } }; static uint32_t ed_pccard_tc5299j_mii_bitbang_read(device_t dev); static void ed_pccard_tc5299j_mii_bitbang_write(device_t dev, uint32_t val); static const struct mii_bitbang_ops ed_pccard_tc5299j_mii_bitbang_ops = { ed_pccard_tc5299j_mii_bitbang_read, ed_pccard_tc5299j_mii_bitbang_write, { ED_TC5299J_MII_DATAOUT, /* MII_BIT_MDO */ ED_TC5299J_MII_DATAIN, /* MII_BIT_MDI */ ED_TC5299J_MII_CLK, /* MII_BIT_MDC */ 0, /* MII_BIT_DIR_HOST_PHY */ ED_AX88X90_MII_DIRIN /* MII_BIT_DIR_PHY_HOST */ } }; /* * PC Card (PCMCIA) specific code. */ static int ed_pccard_probe(device_t); static int ed_pccard_attach(device_t); static void ed_pccard_tick(struct ed_softc *); static int ed_pccard_dl100xx(device_t dev, const struct ed_product *); static void ed_pccard_dl100xx_mii_reset(struct ed_softc *sc); static int ed_pccard_ax88x90(device_t dev, const struct ed_product *); static int ed_miibus_readreg(device_t dev, int phy, int reg); static int ed_ifmedia_upd(struct ifnet *); static void ed_ifmedia_sts(struct ifnet *, struct ifmediareq *); static int ed_pccard_tc5299j(device_t dev, const struct ed_product *); static void ed_pccard_print_entry(const struct ed_product *pp) { int i; printf("Product entry: "); if (pp->prod.pp_name) printf("name='%s',", pp->prod.pp_name); printf("vendor=%#x,product=%#x", pp->prod.pp_vendor, pp->prod.pp_product); for (i = 0; i < 4; i++) if (pp->prod.pp_cis[i]) printf(",CIS%d='%s'", i, pp->prod.pp_cis[i]); printf("\n"); } static int ed_pccard_probe(device_t dev) { const struct ed_product *pp, *pp2; int error, first = 1; uint32_t fcn = PCCARD_FUNCTION_UNSPEC; /* Make sure we're a network function */ error = pccard_get_function(dev, &fcn); if (error != 0) return (error); if ((pp = (const struct ed_product *) pccard_product_lookup(dev, (const struct pccard_product *) ed_pccard_products, sizeof(ed_pccard_products[0]), NULL)) != NULL) { if (pp->prod.pp_name != NULL) device_set_desc(dev, pp->prod.pp_name); /* * Some devices don't ID themselves as network, but * that's OK if the flags say so. */ if (!(pp->flags & NE2000DVF_ANYFUNC) && fcn != PCCARD_FUNCTION_NETWORK) return (ENXIO); /* * Some devices match multiple entries. Report that * as a warning to help cull the table */ pp2 = pp; while ((pp2 = (const struct ed_product *)pccard_product_lookup( dev, (const struct pccard_product *)(pp2 + 1), sizeof(ed_pccard_products[0]), NULL)) != NULL) { if (first) { device_printf(dev, "Warning: card matches multiple entries. Report to imp@freebsd.org\n"); ed_pccard_print_entry(pp); first = 0; } ed_pccard_print_entry(pp2); } return (0); } return (ENXIO); } static int ed_pccard_rom_mac(device_t dev, uint8_t *enaddr) { struct ed_softc *sc = device_get_softc(dev); uint8_t romdata[32], sum; int i; /* * Read in the rom data at location 0. Since there are no * NE-1000 based PC Card devices, we'll assume we're 16-bit. * * In researching what format this takes, I've found that the * following appears to be true for multiple cards based on * observation as well as datasheet digging. * * Data is stored in some ROM and is copied out 8 bits at a time * into 16-bit wide locations. This means that the odd locations * of the ROM are not used (and can be either 0 or ff). * * The contents appears to be as follows: * PROM RAM * Offset Offset What * 0 0 ENETADDR 0 * 1 2 ENETADDR 1 * 2 4 ENETADDR 2 * 3 6 ENETADDR 3 * 4 8 ENETADDR 4 * 5 10 ENETADDR 5 * 6-13 12-26 Reserved (varies by manufacturer) * 14 28 0x57 * 15 30 0x57 * * Some manufacturers have another image of enetaddr from * PROM offset 0x10 to 0x15 with 0x42 in 0x1e and 0x1f, but * this doesn't appear to be universally documented in the * datasheets. Some manufactuers have a card type, card config * checksums, etc encoded into PROM offset 6-13, but deciphering it * requires more knowledge about the exact underlying chipset than * we possess (and maybe can possess). */ ed_pio_readmem(sc, 0, romdata, 32); if (bootverbose) device_printf(dev, "ROM DATA: %32D\n", romdata, " "); if (romdata[28] != 0x57 || romdata[30] != 0x57) return (0); for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= romdata[i * 2]; if (sum == 0) return (0); for (i = 0; i < ETHER_ADDR_LEN; i++) enaddr[i] = romdata[i * 2]; return (1); } static int ed_pccard_add_modem(device_t dev) { device_printf(dev, "Need to write this code\n"); return 0; } static int ed_pccard_kick_phy(struct ed_softc *sc) { struct mii_softc *miisc; struct mii_data *mii; mii = device_get_softc(sc->miibus); LIST_FOREACH(miisc, &mii->mii_phys, mii_list) PHY_RESET(miisc); return (mii_mediachg(mii)); } static int ed_pccard_media_ioctl(struct ed_softc *sc, struct ifreq *ifr, u_long command) { struct mii_data *mii; if (sc->miibus == NULL) return (EINVAL); mii = device_get_softc(sc->miibus); return (ifmedia_ioctl(sc->ifp, ifr, &mii->mii_media, command)); } static void ed_pccard_mediachg(struct ed_softc *sc) { struct mii_data *mii; if (sc->miibus == NULL) return; mii = device_get_softc(sc->miibus); mii_mediachg(mii); } static int ed_pccard_attach(device_t dev) { u_char sum; u_char enaddr[ETHER_ADDR_LEN]; const struct ed_product *pp; int error, i, flags, port_rid, modem_rid; struct ed_softc *sc = device_get_softc(dev); u_long size; static uint16_t *intr_vals[] = {NULL, NULL}; sc->dev = dev; if ((pp = (const struct ed_product *) pccard_product_lookup(dev, (const struct pccard_product *) ed_pccard_products, sizeof(ed_pccard_products[0]), NULL)) == NULL) { printf("Can't find\n"); return (ENXIO); } modem_rid = port_rid = -1; if (pp->flags & NE2000DVF_MODEM) { for (i = 0; i < 4; i++) { size = bus_get_resource_count(dev, SYS_RES_IOPORT, i); if (size == ED_NOVELL_IO_PORTS) port_rid = i; else if (size == 8) modem_rid = i; } if (port_rid == -1) { device_printf(dev, "Cannot locate my ports!\n"); return (ENXIO); } } else { port_rid = 0; } /* Allocate the port resource during setup. */ error = ed_alloc_port(dev, port_rid, ED_NOVELL_IO_PORTS); if (error) { printf("alloc_port failed\n"); return (error); } if (rman_get_size(sc->port_res) == ED_NOVELL_IO_PORTS / 2) { port_rid++; sc->port_res2 = bus_alloc_resource(dev, SYS_RES_IOPORT, &port_rid, 0ul, ~0ul, 1, RF_ACTIVE); if (sc->port_res2 == NULL || rman_get_size(sc->port_res2) != ED_NOVELL_IO_PORTS / 2) { error = ENXIO; goto bad; } } error = ed_alloc_irq(dev, 0, 0); if (error) goto bad; /* * Determine which chipset we are. Almost all the PC Card chipsets * have the Novel ASIC and NIC offsets. There's 2 known cards that * follow the WD80x3 conventions, which are handled as a special case. */ sc->asic_offset = ED_NOVELL_ASIC_OFFSET; sc->nic_offset = ED_NOVELL_NIC_OFFSET; error = ENXIO; flags = device_get_flags(dev); if (error != 0) error = ed_pccard_dl100xx(dev, pp); if (error != 0) error = ed_pccard_ax88x90(dev, pp); if (error != 0) error = ed_pccard_tc5299j(dev, pp); if (error != 0) { error = ed_probe_Novell_generic(dev, flags); printf("Novell generic probe failed: %d\n", error); } if (error != 0 && (pp->flags & NE2000DVF_TOSHIBA)) { flags |= ED_FLAGS_TOSH_ETHER; flags |= ED_FLAGS_PCCARD; sc->asic_offset = ED_WD_ASIC_OFFSET; sc->nic_offset = ED_WD_NIC_OFFSET; error = ed_probe_WD80x3_generic(dev, flags, intr_vals); } if (error) goto bad; /* * There are several ways to get the MAC address for the card. * Some of the above probe routines can fill in the enaddr. If * not, we run through a number of 'well known' locations: * (1) From the PC Card FUNCE * (2) From offset 0 in the shared memory * (3) From a hinted offset in attribute memory * (4) From 0xff0 in attribute memory * If we can't get a non-zero MAC address from this list, we fail. */ for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= sc->enaddr[i]; if (sum == 0) { pccard_get_ether(dev, enaddr); if (bootverbose) device_printf(dev, "CIS MAC %6D\n", enaddr, ":"); for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= enaddr[i]; if (sum == 0 && ed_pccard_rom_mac(dev, enaddr)) { if (bootverbose) device_printf(dev, "ROM mac %6D\n", enaddr, ":"); sum++; } if (sum == 0 && pp->flags & NE2000DVF_ENADDR) { for (i = 0; i < ETHER_ADDR_LEN; i++) { pccard_attr_read_1(dev, pp->enoff + i * 2, enaddr + i); sum |= enaddr[i]; } if (bootverbose) device_printf(dev, "Hint %x MAC %6D\n", pp->enoff, enaddr, ":"); } if (sum == 0) { for (i = 0; i < ETHER_ADDR_LEN; i++) { pccard_attr_read_1(dev, ED_DEFAULT_MAC_OFFSET + i * 2, enaddr + i); sum |= enaddr[i]; } if (bootverbose) device_printf(dev, "Fallback MAC %6D\n", enaddr, ":"); } if (sum == 0) { device_printf(dev, "Cannot extract MAC address.\n"); ed_release_resources(dev); return (ENXIO); } bcopy(enaddr, sc->enaddr, ETHER_ADDR_LEN); } error = ed_attach(dev); if (error) goto bad; if (sc->chip_type == ED_CHIP_TYPE_DL10019 || sc->chip_type == ED_CHIP_TYPE_DL10022) { /* Try to attach an MII bus, but ignore errors. */ ed_pccard_dl100xx_mii_reset(sc); (void)mii_attach(dev, &sc->miibus, sc->ifp, ed_ifmedia_upd, ed_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG); } else if (sc->chip_type == ED_CHIP_TYPE_AX88190 || sc->chip_type == ED_CHIP_TYPE_AX88790 || sc->chip_type == ED_CHIP_TYPE_TC5299J) { error = mii_attach(dev, &sc->miibus, sc->ifp, ed_ifmedia_upd, ed_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG); if (error != 0) { device_printf(dev, "attaching PHYs failed\n"); goto bad; } } if (sc->miibus != NULL) { sc->sc_tick = ed_pccard_tick; sc->sc_mediachg = ed_pccard_mediachg; sc->sc_media_ioctl = ed_pccard_media_ioctl; ed_pccard_kick_phy(sc); } else { ed_gen_ifmedia_init(sc); } if (modem_rid != -1) ed_pccard_add_modem(dev); error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, NULL, edintr, sc, &sc->irq_handle); if (error) { device_printf(dev, "setup intr failed %d \n", error); goto bad; } return (0); bad: ed_detach(dev); return (error); } /* * Probe the Ethernet MAC addrees for PCMCIA Linksys EtherFast 10/100 * and compatible cards (DL10019C Ethernet controller). */ static int ed_pccard_dl100xx(device_t dev, const struct ed_product *pp) { struct ed_softc *sc = device_get_softc(dev); u_char sum; uint8_t id; u_int memsize; int i, error; if (!(pp->flags & NE2000DVF_DL100XX)) return (ENXIO); if (bootverbose) device_printf(dev, "Trying DL100xx\n"); error = ed_probe_Novell_generic(dev, device_get_flags(dev)); if (bootverbose && error) device_printf(dev, "Novell generic probe failed: %d\n", error); if (error != 0) return (error); /* * Linksys registers(offset from ASIC base) * * 0x04-0x09 : Physical Address Register 0-5 (PAR0-PAR5) * 0x0A : Card ID Register (CIR) * 0x0B : Check Sum Register (SR) */ for (sum = 0, i = 0x04; i < 0x0c; i++) sum += ed_asic_inb(sc, i); if (sum != 0xff) { if (bootverbose) device_printf(dev, "Bad checksum %#x\n", sum); return (ENXIO); /* invalid DL10019C */ } if (bootverbose) device_printf(dev, "CIR is %d\n", ed_asic_inb(sc, 0xa)); for (i = 0; i < ETHER_ADDR_LEN; i++) sc->enaddr[i] = ed_asic_inb(sc, 0x04 + i); ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); id = ed_asic_inb(sc, 0xf); sc->isa16bit = 1; /* * Hard code values based on the datasheet. We're NE-2000 compatible * NIC with 24kb of packet memory starting at 24k offset. These * cards also work with 16k at 16k, but don't work with 24k at 16k * or 32k at 16k. */ sc->type = ED_TYPE_NE2000; sc->mem_start = 24 * 1024; memsize = sc->mem_size = 24 * 1024; sc->mem_end = sc->mem_start + memsize; sc->tx_page_start = memsize / ED_PAGE_SIZE; sc->txb_cnt = 3; sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; ed_nic_outb(sc, ED_P0_PSTART, sc->mem_start / ED_PAGE_SIZE); ed_nic_outb(sc, ED_P0_PSTOP, sc->mem_end / ED_PAGE_SIZE); sc->vendor = ED_VENDOR_NOVELL; sc->chip_type = (id & 0x90) == 0x90 ? ED_CHIP_TYPE_DL10022 : ED_CHIP_TYPE_DL10019; sc->type_str = ((id & 0x90) == 0x90) ? "DL10022" : "DL10019"; sc->mii_bitbang_ops = &ed_pccard_dl100xx_mii_bitbang_ops; return (0); } /* MII bit-twiddling routines for cards using Dlink chipset */ static void ed_pccard_dl100xx_mii_reset(struct ed_softc *sc) { if (sc->chip_type != ED_CHIP_TYPE_DL10022) return; ed_asic_outb(sc, ED_DL100XX_MIIBUS, ED_DL10022_MII_RESET2); DELAY(10); ed_asic_outb(sc, ED_DL100XX_MIIBUS, ED_DL10022_MII_RESET2 | ED_DL10022_MII_RESET1); DELAY(10); ed_asic_outb(sc, ED_DL100XX_MIIBUS, ED_DL10022_MII_RESET2); DELAY(10); ed_asic_outb(sc, ED_DL100XX_MIIBUS, ED_DL10022_MII_RESET2 | ED_DL10022_MII_RESET1); DELAY(10); ed_asic_outb(sc, ED_DL100XX_MIIBUS, 0); } static void ed_pccard_dl100xx_mii_bitbang_write(device_t dev, uint32_t val) { struct ed_softc *sc; sc = device_get_softc(dev); ed_asic_outb(sc, ED_DL100XX_MIIBUS, val); ed_asic_barrier(sc, ED_DL100XX_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } static uint32_t ed_pccard_dl100xx_mii_bitbang_read(device_t dev) { struct ed_softc *sc; uint32_t val; sc = device_get_softc(dev); val = ed_asic_inb(sc, ED_DL100XX_MIIBUS); ed_asic_barrier(sc, ED_DL100XX_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return (val); } static void ed_pccard_ax88x90_reset(struct ed_softc *sc) { int i; /* Reset Card */ ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); ed_nic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP | ED_CR_PAGE_0); ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); ed_asic_outb(sc, ED_NOVELL_RESET, ed_asic_inb(sc, ED_NOVELL_RESET)); /* Wait for the RST bit to assert, but cap it at 10ms */ for (i = 10000; !(ed_nic_inb(sc, ED_P0_ISR) & ED_ISR_RST) && i > 0; i--) continue; ed_nic_outb(sc, ED_P0_ISR, ED_ISR_RST); /* ACK INTR */ if (i == 0) device_printf(sc->dev, "Reset didn't finish\n"); } /* * Probe and vendor-specific initialization routine for ax88x90 boards */ static int ed_probe_ax88x90_generic(device_t dev, int flags) { struct ed_softc *sc = device_get_softc(dev); u_int memsize; static char test_pattern[32] = "THIS is A memory TEST pattern"; char test_buffer[32]; ed_pccard_ax88x90_reset(sc); DELAY(10*1000); /* Make sure that we really have an 8390 based board */ if (!ed_probe_generic8390(sc)) return (ENXIO); sc->vendor = ED_VENDOR_NOVELL; sc->mem_shared = 0; sc->cr_proto = ED_CR_RD2; /* * This prevents packets from being stored in the NIC memory when the * readmem routine turns on the start bit in the CR. We write some * bytes in word mode and verify we can read them back. If we can't * then we don't have an AX88x90 chip here. */ sc->isa16bit = 1; ed_nic_outb(sc, ED_P0_RCR, ED_RCR_MON); ed_nic_outb(sc, ED_P0_DCR, ED_DCR_WTS | ED_DCR_FT1 | ED_DCR_LS); ed_pio_writemem(sc, test_pattern, 16384, sizeof(test_pattern)); ed_pio_readmem(sc, 16384, test_buffer, sizeof(test_pattern)); if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) != 0) return (ENXIO); /* * Hard code values based on the datasheet. We're NE-2000 compatible * NIC with 16kb of packet memory starting at 16k offset. */ sc->type = ED_TYPE_NE2000; memsize = sc->mem_size = 16*1024; sc->mem_start = 16 * 1024; if (ed_asic_inb(sc, ED_AX88X90_TEST) != 0) sc->chip_type = ED_CHIP_TYPE_AX88790; else { sc->chip_type = ED_CHIP_TYPE_AX88190; /* * The AX88190 (not A) has external 64k SRAM. Probe for this * here. Most of the cards I have either use the AX88190A * part, or have only 32k SRAM for some reason, so I don't * know if this works or not. */ ed_pio_writemem(sc, test_pattern, 32768, sizeof(test_pattern)); ed_pio_readmem(sc, 32768, test_buffer, sizeof(test_pattern)); if (bcmp(test_pattern, test_buffer, sizeof(test_pattern)) == 0) { sc->mem_start = 2*1024; memsize = sc->mem_size = 62 * 1024; } } sc->mem_end = sc->mem_start + memsize; sc->tx_page_start = memsize / ED_PAGE_SIZE; if (sc->mem_size > 16 * 1024) sc->txb_cnt = 3; else sc->txb_cnt = 2; sc->rec_page_start = sc->tx_page_start + sc->txb_cnt * ED_TXBUF_SIZE; sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; sc->mem_ring = sc->mem_start + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; ed_nic_outb(sc, ED_P0_PSTART, sc->mem_start / ED_PAGE_SIZE); ed_nic_outb(sc, ED_P0_PSTOP, sc->mem_end / ED_PAGE_SIZE); /* Get the mac before we go -- It's just at 0x400 in "SRAM" */ ed_pio_readmem(sc, 0x400, sc->enaddr, ETHER_ADDR_LEN); /* clear any pending interrupts that might have occurred above */ ed_nic_outb(sc, ED_P0_ISR, 0xff); sc->sc_write_mbufs = ed_pio_write_mbufs; return (0); } static int ed_pccard_ax88x90_check_mii(device_t dev, struct ed_softc *sc) { int i, id; /* * All AX88x90 devices have MII and a PHY, so we use this to weed out * chips that would otherwise make it through the tests we have after * this point. */ for (i = 0; i < 32; i++) { id = ed_miibus_readreg(dev, i, MII_BMSR); if (id != 0 && id != 0xffff) break; } /* * Found one, we're good. */ if (i != 32) return (0); /* * Didn't find anything, so try to power up and try again. The PHY * may be not responding because we're in power down mode. */ if (sc->chip_type == ED_CHIP_TYPE_AX88190) return (ENXIO); pccard_ccr_write_1(dev, PCCARD_CCR_STATUS, PCCARD_CCR_STATUS_PWRDWN); for (i = 0; i < 32; i++) { id = ed_miibus_readreg(dev, i, MII_BMSR); if (id != 0 && id != 0xffff) break; } /* * Still no joy? We're AFU, punt. */ if (i == 32) return (ENXIO); return (0); } /* * Special setup for AX88[17]90 */ static int ed_pccard_ax88x90(device_t dev, const struct ed_product *pp) { int error; int iobase; struct ed_softc *sc = device_get_softc(dev); if (!(pp->flags & NE2000DVF_AX88X90)) return (ENXIO); if (bootverbose) device_printf(dev, "Checking AX88x90\n"); /* * Set the IOBASE Register. The AX88x90 cards are potentially * multifunction cards, and thus requires a slight workaround. * We write the address the card is at, on the off chance that this * card is not MFC. * XXX I'm not sure that this is still needed... */ iobase = rman_get_start(sc->port_res); pccard_ccr_write_1(dev, PCCARD_CCR_IOBASE0, iobase & 0xff); pccard_ccr_write_1(dev, PCCARD_CCR_IOBASE1, (iobase >> 8) & 0xff); error = ed_probe_ax88x90_generic(dev, device_get_flags(dev)); if (error) { if (bootverbose) device_printf(dev, "probe ax88x90 failed %d\n", error); return (error); } sc->mii_bitbang_ops = &ed_pccard_ax88x90_mii_bitbang_ops; error = ed_pccard_ax88x90_check_mii(dev, sc); if (error) return (error); sc->vendor = ED_VENDOR_NOVELL; sc->type = ED_TYPE_NE2000; if (sc->chip_type == ED_CHIP_TYPE_AX88190) sc->type_str = "AX88190"; else sc->type_str = "AX88790"; return (0); } static void ed_pccard_ax88x90_mii_bitbang_write(device_t dev, uint32_t val) { struct ed_softc *sc; sc = device_get_softc(dev); ed_asic_outb(sc, ED_AX88X90_MIIBUS, val); ed_asic_barrier(sc, ED_AX88X90_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } static uint32_t ed_pccard_ax88x90_mii_bitbang_read(device_t dev) { struct ed_softc *sc; uint32_t val; sc = device_get_softc(dev); val = ed_asic_inb(sc, ED_AX88X90_MIIBUS); ed_asic_barrier(sc, ED_AX88X90_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return (val); } /* * Special setup for TC5299J */ static int ed_pccard_tc5299j(device_t dev, const struct ed_product *pp) { int error, i, id; char *ts; struct ed_softc *sc = device_get_softc(dev); if (!(pp->flags & NE2000DVF_TC5299J)) return (ENXIO); if (bootverbose) device_printf(dev, "Checking Tc5299j\n"); error = ed_probe_Novell_generic(dev, device_get_flags(dev)); if (bootverbose) device_printf(dev, "Novell generic probe failed: %d\n", error); if (error != 0) return (error); /* * Check to see if we have a MII PHY ID at any address. All TC5299J * devices have MII and a PHY, so we use this to weed out chips that * would otherwise make it through the tests we have after this point. */ sc->mii_bitbang_ops = &ed_pccard_tc5299j_mii_bitbang_ops; for (i = 0; i < 32; i++) { id = ed_miibus_readreg(dev, i, MII_PHYIDR1); if (id != 0 && id != 0xffff) break; } if (i == 32) return (ENXIO); ts = "TC5299J"; if (ed_pccard_rom_mac(dev, sc->enaddr) == 0) return (ENXIO); sc->vendor = ED_VENDOR_NOVELL; sc->type = ED_TYPE_NE2000; sc->chip_type = ED_CHIP_TYPE_TC5299J; sc->type_str = ts; return (0); } static void ed_pccard_tc5299j_mii_bitbang_write(device_t dev, uint32_t val) { struct ed_softc *sc; sc = device_get_softc(dev); /* We are already on page 3. */ ed_nic_outb(sc, ED_TC5299J_MIIBUS, val); ed_nic_barrier(sc, ED_TC5299J_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } static uint32_t ed_pccard_tc5299j_mii_bitbang_read(device_t dev) { struct ed_softc *sc; uint32_t val; sc = device_get_softc(dev); /* We are already on page 3. */ val = ed_asic_inb(sc, ED_TC5299J_MIIBUS); ed_nic_barrier(sc, ED_TC5299J_MIIBUS, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); return (val); } /* * MII bus support routines. */ static int ed_miibus_readreg(device_t dev, int phy, int reg) { struct ed_softc *sc; int val; uint8_t cr = 0; sc = device_get_softc(dev); /* * The AX88790 has an interesting quirk. It has an internal phy that * needs a special bit set to access, but can also have additional * external PHYs set for things like HomeNET media. When accessing * the internal PHY, a bit has to be set, when accessing the external * PHYs, it must be clear. See Errata 1, page 51, in the AX88790 * datasheet for more details. * * Also, PHYs above 16 appear to be phantoms on some cards, but not * others. Registers read for this are often the same as prior values * read. Filter all register requests to 17-31. */ if (sc->chip_type == ED_CHIP_TYPE_AX88790) { if (phy > 0x10) return (0); if (phy == 0x10) ed_asic_outb(sc, ED_AX88X90_GPIO, ED_AX88X90_GPIO_INT_PHY); else ed_asic_outb(sc, ED_AX88X90_GPIO, 0); ed_asic_barrier(sc, ED_AX88X90_GPIO, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } else if (sc->chip_type == ED_CHIP_TYPE_TC5299J) { /* Select page 3. */ ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); cr = ed_nic_inb(sc, ED_P0_CR); ed_nic_outb(sc, ED_P0_CR, cr | ED_CR_PAGE_3); ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } val = mii_bitbang_readreg(dev, sc->mii_bitbang_ops, phy, reg); if (sc->chip_type == ED_CHIP_TYPE_TC5299J) { /* Restore prior page. */ ed_nic_outb(sc, ED_P0_CR, cr); ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } return (val); } static int ed_miibus_writereg(device_t dev, int phy, int reg, int data) { struct ed_softc *sc; uint8_t cr = 0; sc = device_get_softc(dev); /* See ed_miibus_readreg for details */ if (sc->chip_type == ED_CHIP_TYPE_AX88790) { if (phy > 0x10) return (0); if (phy == 0x10) ed_asic_outb(sc, ED_AX88X90_GPIO, ED_AX88X90_GPIO_INT_PHY); else ed_asic_outb(sc, ED_AX88X90_GPIO, 0); ed_asic_barrier(sc, ED_AX88X90_GPIO, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } else if (sc->chip_type == ED_CHIP_TYPE_TC5299J) { /* Select page 3. */ ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); cr = ed_nic_inb(sc, ED_P0_CR); ed_nic_outb(sc, ED_P0_CR, cr | ED_CR_PAGE_3); ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } mii_bitbang_writereg(dev, sc->mii_bitbang_ops, phy, reg, data); if (sc->chip_type == ED_CHIP_TYPE_TC5299J) { /* Restore prior page. */ ed_nic_outb(sc, ED_P0_CR, cr); ed_nic_barrier(sc, ED_P0_CR, 1, BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); } return (0); } static int ed_ifmedia_upd(struct ifnet *ifp) { struct ed_softc *sc; int error; sc = ifp->if_softc; ED_LOCK(sc); if (sc->miibus == NULL) { ED_UNLOCK(sc); return (ENXIO); } error = ed_pccard_kick_phy(sc); ED_UNLOCK(sc); return (error); } static void ed_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct ed_softc *sc; struct mii_data *mii; sc = ifp->if_softc; ED_LOCK(sc); if (sc->miibus == NULL) { ED_UNLOCK(sc); return; } mii = device_get_softc(sc->miibus); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; ED_UNLOCK(sc); } static void ed_child_detached(device_t dev, device_t child) { struct ed_softc *sc; sc = device_get_softc(dev); if (child == sc->miibus) sc->miibus = NULL; } static void ed_pccard_tick(struct ed_softc *sc) { struct mii_data *mii; int media = 0; ED_ASSERT_LOCKED(sc); if (sc->miibus != NULL) { mii = device_get_softc(sc->miibus); media = mii->mii_media_status; mii_tick(mii); if (mii->mii_media_status & IFM_ACTIVE && media != mii->mii_media_status) { if (sc->chip_type == ED_CHIP_TYPE_DL10022) { ed_asic_outb(sc, ED_DL10022_DIAG, (mii->mii_media_active & IFM_FDX) ? ED_DL10022_COLLISON_DIS : 0); #ifdef notyet } else if (sc->chip_type == ED_CHIP_TYPE_DL10019) { write_asic(sc, ED_DL10019_MAGIC, (mii->mii_media_active & IFM_FDX) ? DL19FDUPLX : 0); #endif } } } } static device_method_t ed_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ed_pccard_probe), DEVMETHOD(device_attach, ed_pccard_attach), DEVMETHOD(device_detach, ed_detach), /* Bus interface */ DEVMETHOD(bus_child_detached, ed_child_detached), /* MII interface */ DEVMETHOD(miibus_readreg, ed_miibus_readreg), DEVMETHOD(miibus_writereg, ed_miibus_writereg), DEVMETHOD_END }; static driver_t ed_pccard_driver = { "ed", ed_pccard_methods, sizeof(struct ed_softc) }; DRIVER_MODULE(ed, pccard, ed_pccard_driver, ed_devclass, 0, NULL); DRIVER_MODULE(miibus, ed, miibus_driver, miibus_devclass, 0, NULL); MODULE_DEPEND(ed, miibus, 1, 1, 1); MODULE_DEPEND(ed, ether, 1, 1, 1); +PCCARD_PNP_INFO(ed_pccard_products); Index: head/sys/dev/ep/if_ep_pccard.c =================================================================== --- head/sys/dev/ep/if_ep_pccard.c (revision 292078) +++ head/sys/dev/ep/if_ep_pccard.c (revision 292079) @@ -1,237 +1,238 @@ /*- * Copyright (c) 1994 Herb Peyerl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Herb Peyerl. * 4. The name of Herb Peyerl may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Pccard support for 3C589 by: * HAMADA Naoki * nao@tom-yam.or.jp */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" struct ep_pccard_product { struct pccard_product prod; int chipset; }; #define EP_CHIP_589 1 /* Classic 3c5x9 chipset */ #define EP_CHIP_574 2 /* Roadrunner */ #define EP_CHIP_C1 3 /* 3c1 */ static const struct ep_pccard_product ep_pccard_products[] = { { PCMCIA_CARD(3COM, 3C1), EP_CHIP_C1 }, { PCMCIA_CARD(3COM, 3C562), EP_CHIP_589 }, { PCMCIA_CARD(3COM, 3C589), EP_CHIP_589 }, { PCMCIA_CARD(3COM, 3CXEM556), EP_CHIP_589 }, { PCMCIA_CARD(3COM, 3CXEM556INT), EP_CHIP_589 }, { PCMCIA_CARD(3COM, 3C574), EP_CHIP_574 }, { PCMCIA_CARD(3COM, 3CCFEM556BI), EP_CHIP_574 }, { { NULL } } }; static const struct ep_pccard_product * ep_pccard_lookup(device_t dev) { return ((const struct ep_pccard_product *)pccard_product_lookup(dev, (const struct pccard_product *)ep_pccard_products, sizeof(ep_pccard_products[0]), NULL)); } static int ep_pccard_probe(device_t dev) { const struct ep_pccard_product *pp; int error; uint32_t fcn = PCCARD_FUNCTION_UNSPEC; /* Make sure we're a network function */ error = pccard_get_function(dev, &fcn); if (error != 0) return (error); if (fcn != PCCARD_FUNCTION_NETWORK) return (ENXIO); /* Check to see if we know about this card */ if ((pp = ep_pccard_lookup(dev)) == NULL) return EIO; if (pp->prod.pp_name != NULL) device_set_desc(dev, pp->prod.pp_name); return 0; } static int ep_pccard_mac(const struct pccard_tuple *tuple, void *argp) { uint8_t *enaddr = argp; int i; /* Code 0x88 is 3com's special cis node contianing the MAC */ if (tuple->code != 0x88) return (0); /* Make sure this is a sane node */ if (tuple->length < ETHER_ADDR_LEN) return (0); /* Copy the MAC ADDR and return success */ for (i = 0; i < ETHER_ADDR_LEN; i += 2) { enaddr[i] = pccard_tuple_read_1(tuple, i + 1); enaddr[i + 1] = pccard_tuple_read_1(tuple, i); } return (1); } static int ep_pccard_attach(device_t dev) { struct ep_softc *sc = device_get_softc(dev); uint16_t result; int error = 0; const struct ep_pccard_product *pp; if ((pp = ep_pccard_lookup(dev)) == NULL) panic("ep_pccard_attach: can't find product in attach."); if (pp->chipset == EP_CHIP_574) { sc->epb.mii_trans = 1; sc->epb.cmd_off = 2; } else { sc->epb.mii_trans = 0; sc->epb.cmd_off = 0; } if ((error = ep_alloc(dev))) { device_printf(dev, "ep_alloc() failed! (%d)\n", error); goto bad; } if (pp->chipset == EP_CHIP_C1) sc->stat |= F_HAS_TX_PLL; /* ROM size = 0, ROM base = 0 */ /* For now, ignore AUTO SELECT feature of 3C589B and later. */ error = ep_get_e(sc, EEPROM_ADDR_CFG, &result); CSR_WRITE_2(sc, EP_W0_ADDRESS_CFG, result & 0xc000); /* * Fake IRQ must be 3 for 3C589 and 3C589B. 3C589D and newer * ignore this value. 3C589C is unknown, as are the other * cards supported by this driver, but it appears to never hurt * and always helps. */ SET_IRQ(sc, 3); CSR_WRITE_2(sc, EP_W0_PRODUCT_ID, sc->epb.prod_id); if (sc->epb.mii_trans) { /* * turn on the MII transciever */ GO_WINDOW(sc, 3); CSR_WRITE_2(sc, EP_W3_OPTIONS, 0x8040); DELAY(1000); CSR_WRITE_2(sc, EP_W3_OPTIONS, 0xc040); CSR_WRITE_2(sc, EP_COMMAND, RX_RESET); CSR_WRITE_2(sc, EP_COMMAND, TX_RESET); EP_BUSY_WAIT(sc); DELAY(1000); CSR_WRITE_2(sc, EP_W3_OPTIONS, 0x8040); } else ep_get_media(sc); /* * The 3C562 (a-c revisions) stores the MAC in the CIS in a * way that's unique to 3com. If we have one of these cards, * scan the CIS for that MAC address, and use it if we find * it. The NetBSD driver says that the ROADRUNNER chips also * do this, which may be true, but none of the cards that I * have include this TUPLE. Always prefer the MAC addr in the * CIS tuple to the one returned by the card, as it appears that * only those cards that need it have this special tuple. */ if (pccard_cis_scan(dev, ep_pccard_mac, sc->eaddr)) sc->stat |= F_ENADDR_SKIP; if ((error = ep_attach(sc))) { device_printf(dev, "ep_attach() failed! (%d)\n", error); goto bad; } if ((error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, ep_intr, sc, &sc->ep_intrhand))) { device_printf(dev, "bus_setup_intr() failed! (%d)\n", error); goto bad; } return (0); bad: ep_free(dev); return (error); } static device_method_t ep_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ep_pccard_probe), DEVMETHOD(device_attach, ep_pccard_attach), DEVMETHOD(device_detach, ep_detach), DEVMETHOD_END }; static driver_t ep_pccard_driver = { "ep", ep_pccard_methods, sizeof(struct ep_softc), }; extern devclass_t ep_devclass; DRIVER_MODULE(ep, pccard, ep_pccard_driver, ep_devclass, 0, 0); +PCCARD_PNP_INFO(ep_pccard_products); Index: head/sys/dev/ex/if_ex_pccard.c =================================================================== --- head/sys/dev/ex/if_ex_pccard.c (revision 292078) +++ head/sys/dev/ex/if_ex_pccard.c (revision 292079) @@ -1,230 +1,231 @@ /*- * Copyright (c) 2000 Mitsuru IWASAKI * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product ex_pccard_products[] = { PCMCIA_CARD(OLICOM, OC2220), PCMCIA_CARD(OLICOM, OC2231), PCMCIA_CARD(OLICOM, OC2232), PCMCIA_CARD(INTEL, ETHEREXPPRO), { NULL } }; /* Bus Front End Functions */ static int ex_pccard_probe(device_t); static int ex_pccard_attach(device_t); static int ex_pccard_enet_ok(u_char *enaddr) { int i; u_char sum; if (enaddr[0] == 0xff) return (0); for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= enaddr[i]; return (sum != 0); } static int ex_pccard_silicom_cb(const struct pccard_tuple *tuple, void *arg) { u_char *enaddr = arg; int i; if (tuple->code != CISTPL_FUNCE) return (0); if (tuple->length != 15) return (0); if (pccard_tuple_read_1(tuple, 6) != 6) return (0); for (i = 0; i < 6; i++) enaddr[i] = pccard_tuple_read_1(tuple, 7 + i); return (1); } static void ex_pccard_get_silicom_mac(device_t dev, u_char *ether_addr) { pccard_cis_scan(dev, ex_pccard_silicom_cb, ether_addr); } static int ex_pccard_probe(device_t dev) { const struct pccard_product *pp; int error, i, j; uint32_t fcn = PCCARD_FUNCTION_UNSPEC; if ((pp = pccard_product_lookup(dev, ex_pccard_products, sizeof(ex_pccard_products[0]), NULL)) == NULL) return (EIO); if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); /* * Olicom 22.8k and 33.6k modems need to activate the right * CFE. The odd formula below replicates the sequence of cfes * that have multiple resources: * 9, 11, 13, 15, 0 + 9 * 25, 27, 29, 31, 16 + 9 * 41, 43, 45, 47, 32 + 9 * 57, 59, 61, 63 48 + 9 * (entries 8, 24, 40 and 56 are single resoruce cfes) * Fortunately the code that enables and disables the multiple * fuctions of the card won't mess with the lower bit for cards * that aren't stanards conforming MFC cards (which these olicom * cards aren't). * * Note: These cards still don't get interrupts for reasons * unknown, even when the right cfe is selected. There's likely * something in the CCR that needs to be manually tweaked, but * the COR bits seem to all be used. Bit 0 and 3 are always set * and the other bits select the config to use. Maybe one of those * two bits needs to be cleared, or there's something else in the * CCR that needs tweaking. The pattern of resources suggests * bit 0 turns on the ethernet, however... */ if (pp->pp_vendor == PCMCIA_VENDOR_OLICOM && (pp->pp_product == PCMCIA_PRODUCT_OLICOM_OC2231 || pp->pp_product == PCMCIA_PRODUCT_OLICOM_OC2232)) { if (pccard_select_cfe(dev, 1) == 0) goto good; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { printf("Trying %d %d\n", i, j); if (pccard_select_cfe(dev, (i << 4) + (j << 1) + 9) == 0) goto good; } } /* Can't activate the net entries, punt */ return (EIO); } /* * All other cards supported by this driver don't need specail * treatment, so just filter based on the type of card. The * special treatment ones are setup to 'fail safe' to a modem so * this check would effectively filter them out as well. */ error = pccard_get_function(dev, &fcn); if (error != 0) return (error); if (fcn != PCCARD_FUNCTION_NETWORK) return (EIO); good:; return (0); } static int ex_pccard_attach(device_t dev) { struct ex_softc * sc = device_get_softc(dev); int error = 0; u_char ether_addr[ETHER_ADDR_LEN]; sc->dev = dev; sc->ioport_rid = 0; sc->irq_rid = 0; if ((error = ex_alloc_resources(dev)) != 0) { device_printf(dev, "ex_alloc_resources() failed!\n"); goto bad; } /* * Fill in several fields of the softc structure: * - Hardware Ethernet address. * - IRQ number. */ sc->irq_no = rman_get_start(sc->irq); /* Try to get the ethernet address from the chip, then the CIS */ ex_get_address(sc, ether_addr); if (!ex_pccard_enet_ok(ether_addr)) pccard_get_ether(dev, ether_addr); if (!ex_pccard_enet_ok(ether_addr)) ex_pccard_get_silicom_mac(dev, ether_addr); if (!ex_pccard_enet_ok(ether_addr)) { device_printf(dev, "No NIC address found.\n"); error = ENXIO; goto bad; } bcopy(ether_addr, sc->enaddr, ETHER_ADDR_LEN); if ((error = ex_attach(dev)) != 0) { device_printf(dev, "ex_attach() failed!\n"); goto bad; } return(0); bad: ex_release_resources(dev); return (error); } static device_method_t ex_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ex_pccard_probe), DEVMETHOD(device_attach, ex_pccard_attach), DEVMETHOD(device_detach, ex_detach), { 0, 0 } }; static driver_t ex_pccard_driver = { "ex", ex_pccard_methods, sizeof(struct ex_softc), }; DRIVER_MODULE(ex, pccard, ex_pccard_driver, ex_devclass, 0, 0); MODULE_DEPEND(ex, pccard, 1, 1, 1); +PCCARD_PNP_INFO(ex_pccard_products); Index: head/sys/dev/fdc/fdc_pccard.c =================================================================== --- head/sys/dev/fdc/fdc_pccard.c (revision 292078) +++ head/sys/dev/fdc/fdc_pccard.c (revision 292079) @@ -1,141 +1,142 @@ /*- * Copyright (c) 2004-2005 M. Warner Losh. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static int fdc_pccard_probe(device_t); static int fdc_pccard_attach(device_t); static const struct pccard_product fdc_pccard_products[] = { PCMCIA_CARD(YEDATA, EXTERNAL_FDD), }; static int fdc_pccard_alloc_resources(device_t dev, struct fdc_data *fdc) { struct resource *res; int rid, i; rid = 0; res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul, 1, RF_ACTIVE); if (res == NULL) { device_printf(dev, "cannot alloc I/O port range\n"); return (ENXIO); } for (i = 0; i < FDC_MAXREG; i++) { fdc->resio[i] = res; fdc->ridio[i] = rid; fdc->ioff[i] = i; fdc->ioh[i] = rman_get_bushandle(res); } fdc->iot = rman_get_bustag(res); fdc->rid_irq = 0; fdc->res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &fdc->rid_irq, RF_ACTIVE | RF_SHAREABLE); if (fdc->res_irq == NULL) { device_printf(dev, "cannot reserve interrupt line\n"); return (ENXIO); } return (0); } static int fdc_pccard_probe(device_t dev) { if (pccard_product_lookup(dev, fdc_pccard_products, sizeof(fdc_pccard_products[0]), NULL) != NULL) { device_set_desc(dev, "PC Card Floppy"); return (0); } return (ENXIO); } static int fdc_pccard_attach(device_t dev) { int error; struct fdc_data *fdc; device_t child; fdc = device_get_softc(dev); fdc->flags = FDC_NODMA | FDC_NOFAST; fdc->fdct = FDC_NE765; error = fdc_pccard_alloc_resources(dev, fdc); if (error == 0) error = fdc_attach(dev); if (error == 0) { child = fdc_add_child(dev, "fd", -1); device_set_flags(child, 0x24); error = bus_generic_attach(dev); } if (error) fdc_release_resources(fdc); return (error); } static device_method_t fdc_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fdc_pccard_probe), DEVMETHOD(device_attach, fdc_pccard_attach), DEVMETHOD(device_detach, fdc_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_print_child, fdc_print_child), DEVMETHOD(bus_read_ivar, fdc_read_ivar), DEVMETHOD(bus_write_ivar, fdc_write_ivar), /* Our children never use any other bus interface methods. */ { 0, 0 } }; static driver_t fdc_pccard_driver = { "fdc", fdc_pccard_methods, sizeof(struct fdc_data) }; DRIVER_MODULE(fdc, pccard, fdc_pccard_driver, fdc_devclass, 0, 0); +PCCARD_PNP_INFO(fdc_pccard_products); Index: head/sys/dev/fe/if_fe_pccard.c =================================================================== --- head/sys/dev/fe/if_fe_pccard.c (revision 292078) +++ head/sys/dev/fe/if_fe_pccard.c (revision 292079) @@ -1,360 +1,361 @@ /*- * All Rights Reserved, Copyright (C) Fujitsu Limited 1995 * * This software may be used, modified, copied, distributed, and sold, in * both source and binary form provided that the above copyright, these * terms and the following disclaimer are retained. The name of the author * and/or the contributor may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" /* * PC Card (PCMCIA) specific code. */ static int fe_pccard_probe(device_t); static int fe_pccard_attach(device_t); static int fe_pccard_detach(device_t); static const struct fe_pccard_product { struct pccard_product mpp_product; int mpp_flags; int mpp_cfe; #define MPP_MBH10302 1 #define MPP_ANYFUNC 2 #define MPP_SKIP_TO_CFE 4 } fe_pccard_products[] = { /* These need to be first */ { PCMCIA_CARD(FUJITSU2, FMV_J181), MPP_MBH10302 }, { PCMCIA_CARD(FUJITSU2, FMV_J182), 0 }, { PCMCIA_CARD(FUJITSU2, FMV_J182A), 0 }, { PCMCIA_CARD(FUJITSU2, ITCFJ182A), 0 }, /* These need to be second */ { PCMCIA_CARD(TDK, LAK_CD011), 0 }, { PCMCIA_CARD(TDK, LAK_CD021BX), 0 }, { PCMCIA_CARD(TDK, LAK_CF010), 0 }, #if 0 /* XXX 86960-based? */ { PCMCIA_CARD(TDK, LAK_DFL9610), 0 }, #endif { PCMCIA_CARD(CONTEC, CNETPC), MPP_SKIP_TO_CFE, 2 }, { PCMCIA_CARD(FUJITSU, LA501), 0 }, { PCMCIA_CARD(FUJITSU, LA10S), 0 }, { PCMCIA_CARD(FUJITSU, NE200T), MPP_MBH10302 },/* Sold by Eagle */ { PCMCIA_CARD(HITACHI, HT_4840), MPP_MBH10302 | MPP_SKIP_TO_CFE, 10 }, { PCMCIA_CARD(RATOC, REX_R280), 0 }, { PCMCIA_CARD(XIRCOM, CE), MPP_ANYFUNC }, { { NULL } } }; static int fe_pccard_probe(device_t dev) { int error; uint32_t fcn = PCCARD_FUNCTION_UNSPEC; const struct fe_pccard_product *pp; int i; if ((pp = (const struct fe_pccard_product *)pccard_product_lookup(dev, (const struct pccard_product *)fe_pccard_products, sizeof(fe_pccard_products[0]), NULL)) != NULL) { if (pp->mpp_product.pp_name != NULL) device_set_desc(dev, pp->mpp_product.pp_name); if (pp->mpp_flags & MPP_ANYFUNC) return (0); /* Make sure we're a network function */ error = pccard_get_function(dev, &fcn); if (error != 0) return (error); if (fcn != PCCARD_FUNCTION_NETWORK) return (ENXIO); if (pp->mpp_flags & MPP_SKIP_TO_CFE) { for (i = pp->mpp_cfe; i < 32; i++) { if (pccard_select_cfe(dev, i) == 0) goto good; } device_printf(dev, "Failed to map CFE %d or higher\n", pp->mpp_cfe); return ENXIO; } good:; return (0); } return (ENXIO); } static device_method_t fe_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, fe_pccard_probe), DEVMETHOD(device_attach, fe_pccard_attach), DEVMETHOD(device_detach, fe_pccard_detach), { 0, 0 } }; static driver_t fe_pccard_driver = { "fe", fe_pccard_methods, sizeof (struct fe_softc) }; DRIVER_MODULE(fe, pccard, fe_pccard_driver, fe_devclass, 0, 0); MODULE_DEPEND(fe, pccard, 1, 1, 1); +PCCARD_PNP_INFO(fe_pccard_products); static int fe_probe_mbh(device_t, const struct fe_pccard_product *); static int fe_probe_tdk(device_t, const struct fe_pccard_product *); static int fe_pccard_attach(device_t dev) { struct fe_softc *sc; const struct fe_pccard_product *pp; int error; /* Prepare for the device probe process. */ sc = device_get_softc(dev); sc->sc_unit = device_get_unit(dev); pp = (const struct fe_pccard_product *) pccard_product_lookup(dev, (const struct pccard_product *)fe_pccard_products, sizeof(fe_pccard_products[0]), NULL); if (pp == NULL) return (ENXIO); if (pp->mpp_flags & MPP_MBH10302) error = fe_probe_mbh(dev, pp); else error = fe_probe_tdk(dev, pp); if (error != 0) { fe_release_resource(dev); return (error); } error = fe_alloc_irq(dev, 0); if (error != 0) { fe_release_resource(dev); return (error); } return (fe_attach(dev)); } /* * feunload - unload the driver and clear the table. */ static int fe_pccard_detach(device_t dev) { struct fe_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->ifp; FE_LOCK(sc); fe_stop(sc); FE_UNLOCK(sc); callout_drain(&sc->timer); ether_ifdetach(ifp); bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); if_free(ifp); fe_release_resource(dev); mtx_destroy(&sc->lock); return 0; } /* * Probe and initialization for Fujitsu MBH10302 PCMCIA Ethernet interface. * Note that this is for 10302 only; MBH10304 is handled by fe_probe_tdk(). */ static void fe_init_mbh(struct fe_softc *sc) { /* Minimal initialization of 86960. */ DELAY(200); fe_outb(sc, FE_DLCR6, sc->proto_dlcr6 | FE_D6_DLC_DISABLE); DELAY(200); /* Disable all interrupts. */ fe_outb(sc, FE_DLCR2, 0); fe_outb(sc, FE_DLCR3, 0); /* Enable master interrupt flag. */ fe_outb(sc, FE_MBH0, FE_MBH0_MAGIC | FE_MBH0_INTR_ENABLE); } static int fe_probe_mbh(device_t dev, const struct fe_pccard_product *pp) { struct fe_softc *sc = device_get_softc(dev); static struct fe_simple_probe_struct probe_table [] = { { FE_DLCR2, 0x58, 0x00 }, { FE_DLCR4, 0x08, 0x00 }, { FE_DLCR6, 0xFF, 0xB6 }, { 0 } }; /* MBH10302 occupies 32 I/O addresses. */ if (fe_alloc_port(dev, 32)) return ENXIO; /* Fill the softc struct with default values. */ fe_softc_defaults(sc); /* * See if MBH10302 is on its address. * I'm not sure the following probe code works. FIXME. */ if (!fe_simple_probe(sc, probe_table)) return ENXIO; /* Get our station address from EEPROM. */ fe_inblk(sc, FE_MBH10, sc->enaddr, ETHER_ADDR_LEN); /* Make sure we got a valid station address. */ if (!fe_valid_Ether_p(sc->enaddr, 0)) return ENXIO; /* Determine the card type. */ sc->type = FE_TYPE_MBH; sc->typestr = "MBH10302 (PCMCIA)"; /* We seems to need our own IDENT bits... FIXME. */ sc->proto_dlcr7 = FE_D7_BYTSWP_LH | FE_D7_IDENT_NICE; /* Setup hooks. We need a special initialization procedure. */ sc->init = fe_init_mbh; return 0; } static int fe_pccard_xircom_mac(const struct pccard_tuple *tuple, void *argp) { uint8_t *enaddr = argp; int i; #if 1 /* * We fail to map the CIS twice, for reasons unknown. We * may fix this in the future by loading the CIS with a sane * CIS from userland. */ static uint8_t defaultmac[ETHER_ADDR_LEN] = { 0x00, 0x80, 0xc7, 0xed, 0x16, 0x7b}; /* Copy the MAC ADDR and return success */ for (i = 0; i < ETHER_ADDR_LEN; i++) enaddr[i] = defaultmac[i]; #else /* FUNCE is not after FUNCID, so we gotta go find it */ if (tuple->code != 0x22) return (0); /* Make sure this is a sane node */ if (tuple->length < ETHER_ADDR_LEN + 3) return (0); /* Copy the MAC ADDR and return success */ for (i = 0; i < ETHER_ADDR_LEN; i++) enaddr[i] = pccard_tuple_read_1(tuple, i + 3); #endif return (1); } /* * Probe and initialization for TDK/CONTEC PCMCIA Ethernet interface. * by MASUI Kenji * * (Contec uses TDK Ethernet chip -- hosokawa) * * This version of fe_probe_tdk has been rewrote to handle * *generic* PC Card implementation of Fujitsu MB8696x family. The * name _tdk is just for a historical reason. :-) */ static int fe_probe_tdk (device_t dev, const struct fe_pccard_product *pp) { struct fe_softc *sc = device_get_softc(dev); static struct fe_simple_probe_struct probe_table [] = { { FE_DLCR2, 0x10, 0x00 }, { FE_DLCR4, 0x08, 0x00 }, /* { FE_DLCR5, 0x80, 0x00 }, Does not work well. */ { 0 } }; /* C-NET(PC)C occupies 16 I/O addresses. */ if (fe_alloc_port(dev, 16)) return ENXIO; /* Fill the softc struct with default values. */ fe_softc_defaults(sc); /* * See if C-NET(PC)C is on its address. */ if (!fe_simple_probe(sc, probe_table)) return ENXIO; /* Determine the card type. */ sc->type = FE_TYPE_TDK; sc->typestr = "Generic MB8696x/78Q837x Ethernet (PCMCIA)"; pccard_get_ether(dev, sc->enaddr); /* Make sure we got a valid station address. */ if (!fe_valid_Ether_p(sc->enaddr, 0)) { pccard_cis_scan(dev, fe_pccard_xircom_mac, sc->enaddr); } /* Make sure we got a valid station address. */ if (!fe_valid_Ether_p(sc->enaddr, 0)) return ENXIO; return 0; } Index: head/sys/dev/ncv/ncr53c500_pccard.c =================================================================== --- head/sys/dev/ncv/ncr53c500_pccard.c (revision 292078) +++ head/sys/dev/ncv/ncr53c500_pccard.c (revision 292079) @@ -1,336 +1,337 @@ /* $NecBSD: ncr53c500_pisa.c,v 1.28 1998/11/26 01:59:11 honda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1995, 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1995, 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KME_KXLC004_01 0x100 #define OFFSET_KME_KXLC004_01 0x10 #include "pccarddevs.h" static int ncvprobe(device_t devi); static int ncvattach(device_t devi); static void ncv_card_unload(device_t); static const struct ncv_product { struct pccard_product prod; int flags; } ncv_products[] = { { PCMCIA_CARD(EPSON, SC200), 0}, { PCMCIA_CARD(PANASONIC, KXLC002), 0xb4d00000 }, { PCMCIA_CARD(PANASONIC, KXLC003), 0xb4d00000 }, /* untested */ { PCMCIA_CARD(PANASONIC, KXLC004), 0xb4d00100 }, { PCMCIA_CARD(MACNICA, MPS100), 0xb6250000 }, { PCMCIA_CARD(MACNICA, MPS110), 0 }, { PCMCIA_CARD(NEC, PC9801N_J03R), 0 }, { PCMCIA_CARD(NEWMEDIA, BASICS_SCSI), 0 }, { PCMCIA_CARD(QLOGIC, PC05), 0x84d00000 }, #define FLAGS_REX5572 0x84d00000 { PCMCIA_CARD(RATOC, REX5572), FLAGS_REX5572 }, { PCMCIA_CARD(RATOC, REX9530), 0x84d00000 }, { { NULL }, 0 } }; /* * Additional code for FreeBSD new-bus PCCard frontend */ static void ncv_pccard_intr(void * arg) { struct ncv_softc *sc; sc = arg; SCSI_LOW_LOCK(&sc->sc_sclow); ncvintr(arg); SCSI_LOW_UNLOCK(&sc->sc_sclow); } static void ncv_release_resource(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); if (sc->ncv_intrhand) { bus_teardown_intr(dev, sc->irq_res, sc->ncv_intrhand); } if (sc->port_res) { bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); } if (sc->port_res_dmy) { bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid_dmy, sc->port_res_dmy); } if (sc->irq_res) { bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); } if (sc->mem_res) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); } mtx_destroy(&sc->sc_sclow.sl_lock); } static int ncv_alloc_resource(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); u_int32_t flags = device_get_flags(dev); u_long ioaddr, iosize, maddr, msize; int error; bus_addr_t offset = 0; if(flags & KME_KXLC004_01) offset = OFFSET_KME_KXLC004_01; error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); if (error || (iosize < (offset + NCVIOSZ))) { return(ENOMEM); } mtx_init(&sc->sc_sclow.sl_lock, "ncv", NULL, MTX_DEF); sc->port_rid = 0; sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, ioaddr+offset, ioaddr+iosize-offset, iosize-offset, RF_ACTIVE); if (sc->port_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } if (offset != 0) { sc->port_rid_dmy = 0; sc->port_res_dmy = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid_dmy, ioaddr, ioaddr+offset, offset, RF_ACTIVE); if (sc->port_res_dmy == NULL) { printf("Warning: cannot allocate IOPORT partially.\n"); } } else { sc->port_rid_dmy = 0; sc->port_res_dmy = NULL; } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); if (error) { return(0); /* XXX */ } /* no need to allocate memory if not configured */ if (maddr == 0 || msize == 0) { return(0); } sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { ncv_release_resource(dev); return(ENOMEM); } return(0); } static int ncv_pccard_probe(device_t dev) { const struct ncv_product *pp; const char *vendorstr; const char *prodstr; if ((pp = (const struct ncv_product *) pccard_product_lookup(dev, (const struct pccard_product *) ncv_products, sizeof(ncv_products[0]), NULL)) != NULL) { if (pp->prod.pp_name != NULL) device_set_desc(dev, pp->prod.pp_name); device_set_flags(dev, pp->flags); return(0); } if (pccard_get_vendor_str(dev, &vendorstr)) return(EIO); if (pccard_get_product_str(dev, &prodstr)) return(EIO); if (strcmp(vendorstr, "RATOC System Inc.") == 0 && strncmp(prodstr, "SOUND/SCSI2 CARD", 16) == 0) { device_set_desc(dev, "RATOC REX-5572"); device_set_flags(dev, FLAGS_REX5572); return (BUS_PROBE_DEFAULT); } return(EIO); } static int ncv_pccard_attach(device_t dev) { struct ncv_softc *sc = device_get_softc(dev); int error; error = ncv_alloc_resource(dev); if (error) { return(error); } if (ncvprobe(dev) == 0) { ncv_release_resource(dev); return(ENXIO); } error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, ncv_pccard_intr, sc, &sc->ncv_intrhand); if (error) { ncv_release_resource(dev); return(error); } if (ncvattach(dev) == 0) { ncv_release_resource(dev); return(ENXIO); } return(0); } static int ncv_pccard_detach(device_t dev) { ncv_card_unload(dev); ncv_release_resource(dev); return (0); } static device_method_t ncv_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ncv_pccard_probe), DEVMETHOD(device_attach, ncv_pccard_attach), DEVMETHOD(device_detach, ncv_pccard_detach), { 0, 0 } }; static driver_t ncv_pccard_driver = { "ncv", ncv_pccard_methods, sizeof(struct ncv_softc), }; static devclass_t ncv_devclass; MODULE_DEPEND(ncv, scsi_low, 1, 1, 1); DRIVER_MODULE(ncv, pccard, ncv_pccard_driver, ncv_devclass, 0, 0); +PCCARD_PNP_INFO(ncv_pccard_products); static void ncv_card_unload(device_t devi) { struct ncv_softc *sc = device_get_softc(devi); scsi_low_deactivate(&sc->sc_sclow); scsi_low_detach(&sc->sc_sclow); } static int ncvprobe(device_t devi) { int rv; struct ncv_softc *sc = device_get_softc(devi); u_int32_t flags = device_get_flags(devi); rv = ncvprobesubr(sc->port_res, flags, NCV_HOSTID); return rv; } static int ncvattach(device_t devi) { struct ncv_softc *sc; struct scsi_low_softc *slp; u_int32_t flags = device_get_flags(devi); sc = device_get_softc(devi); slp = &sc->sc_sclow; slp->sl_dev = devi; slp->sl_hostid = NCV_HOSTID; slp->sl_cfgflags = flags; ncvattachsubr(sc); return(NCVIOSZ); } Index: head/sys/dev/nsp/nsp_pccard.c =================================================================== --- head/sys/dev/nsp/nsp_pccard.c (revision 292078) +++ head/sys/dev/nsp/nsp_pccard.c (revision 292079) @@ -1,291 +1,292 @@ /* $NecBSD: nsp_pisa.c,v 1.4 1999/04/15 01:35:54 kmatsuda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1998 * NetBSD/pc98 porting staff. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NSP_HOSTID 7 #include "pccarddevs.h" #define PIO_MODE 0x100 /* pd_flags */ static int nspprobe(device_t devi); static int nspattach(device_t devi); static void nsp_card_unload (device_t); const struct pccard_product nsp_products[] = { PCMCIA_CARD(IODATA3, CBSC16), PCMCIA_CARD(PANASONIC, KME), PCMCIA_CARD(WORKBIT2, NINJA_SCSI3), PCMCIA_CARD(WORKBIT, ULTRA_NINJA_16), { NULL } }; /* * Additional code for FreeBSD new-bus PC Card frontend */ static void nsp_pccard_intr(void * arg) { struct nsp_softc *sc; sc = arg; SCSI_LOW_LOCK(&sc->sc_sclow); nspintr(sc); SCSI_LOW_UNLOCK(&sc->sc_sclow); } static void nsp_release_resource(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); if (sc->nsp_intrhand) bus_teardown_intr(dev, sc->irq_res, sc->nsp_intrhand); if (sc->port_res) bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); mtx_destroy(&sc->sc_sclow.sl_lock); } static int nsp_alloc_resource(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); u_long ioaddr, iosize, maddr, msize; int error; error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &ioaddr, &iosize); if (error || iosize < NSP_IOSIZE) return(ENOMEM); mtx_init(&sc->sc_sclow.sl_lock, "nsp", NULL, MTX_DEF); sc->port_rid = 0; sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, 0, ~0, NSP_IOSIZE, RF_ACTIVE); if (sc->port_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } sc->irq_rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } error = bus_get_resource(dev, SYS_RES_MEMORY, 0, &maddr, &msize); if (error) return(0); /* XXX */ /* No need to allocate memory if not configured and it's in PIO mode */ if (maddr == 0 || msize == 0) { if ((device_get_flags(dev) & PIO_MODE) == 0) { printf("Memory window was not configured. Configure or use in PIO mode."); nsp_release_resource(dev); return(ENOMEM); } /* no need to allocate memory if PIO mode */ return(0); } sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { nsp_release_resource(dev); return(ENOMEM); } return(0); } static int nsp_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, nsp_products, sizeof(nsp_products[0]), NULL)) != NULL) { if (pp->pp_name) device_set_desc(dev, pp->pp_name); return (BUS_PROBE_DEFAULT); } return(EIO); } static int nsp_pccard_attach(device_t dev) { struct nsp_softc *sc = device_get_softc(dev); int error; error = nsp_alloc_resource(dev); if (error) return(error); if (nspprobe(dev) == 0) { nsp_release_resource(dev); return(ENXIO); } error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, nsp_pccard_intr, sc, &sc->nsp_intrhand); if (error) { nsp_release_resource(dev); return(error); } if (nspattach(dev) == 0) { nsp_release_resource(dev); return(ENXIO); } return(0); } static int nsp_pccard_detach(device_t dev) { nsp_card_unload(dev); nsp_release_resource(dev); return (0); } static device_method_t nsp_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nsp_pccard_probe), DEVMETHOD(device_attach, nsp_pccard_attach), DEVMETHOD(device_detach, nsp_pccard_detach), { 0, 0 } }; static driver_t nsp_pccard_driver = { "nsp", nsp_pccard_methods, sizeof(struct nsp_softc), }; static devclass_t nsp_devclass; MODULE_DEPEND(nsp, scsi_low, 1, 1, 1); DRIVER_MODULE(nsp, pccard, nsp_pccard_driver, nsp_devclass, 0, 0); +PCCARD_PNP_INFO(nsp_pccard_products); static void nsp_card_unload(device_t devi) { struct nsp_softc *sc = device_get_softc(devi); scsi_low_deactivate(&sc->sc_sclow); scsi_low_detach(&sc->sc_sclow); } static int nspprobe(device_t devi) { int rv; struct nsp_softc *sc = device_get_softc(devi); rv = nspprobesubr(sc->port_res, device_get_flags(devi)); return rv; } static int nspattach(device_t devi) { struct nsp_softc *sc; struct scsi_low_softc *slp; u_int32_t flags = device_get_flags(devi); u_int iobase = bus_get_resource_start(devi, SYS_RES_IOPORT, 0); if (iobase == 0) { device_printf(devi, "no ioaddr is given\n"); return (ENXIO); } sc = device_get_softc(devi); slp = &sc->sc_sclow; slp->sl_dev = devi; if (sc->mem_res == NULL) { device_printf(devi, "WARNING: CANNOT GET Memory RESOURCE going PIO mode\n"); flags |= PIO_MODE; } /* slp->sl_irq = devi->pd_irq; */ sc->sc_iclkdiv = CLKDIVR_20M; sc->sc_clkdiv = CLKDIVR_40M; slp->sl_hostid = NSP_HOSTID; slp->sl_cfgflags = flags; nspattachsubr(sc); return(NSP_IOSIZE); } Index: head/sys/dev/pccard/pccardvar.h =================================================================== --- head/sys/dev/pccard/pccardvar.h (revision 292078) +++ head/sys/dev/pccard/pccardvar.h (revision 292079) @@ -1,243 +1,253 @@ /* $NetBSD: pcmciavar.h,v 1.12 2000/02/08 12:51:31 enami Exp $ */ /* $FreeBSD$ */ /*- * Copyright (c) 1997 Marc Horowitz. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Marc Horowitz. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Contains information about mapped/allocated i/o spaces. */ struct pccard_io_handle { bus_space_tag_t iot; /* bus space tag (from chipset) */ bus_space_handle_t ioh; /* mapped space handle */ bus_addr_t addr; /* resulting address in bus space */ bus_size_t size; /* size of i/o space */ int flags; /* misc. information */ int width; }; #define PCCARD_IO_ALLOCATED 0x01 /* i/o space was allocated */ /* * Contains information about allocated memory space. */ struct pccard_mem_handle { bus_space_tag_t memt; /* bus space tag (from chipset) */ bus_space_handle_t memh; /* mapped space handle */ bus_addr_t addr; /* resulting address in bus space */ bus_size_t size; /* size of mem space */ bus_size_t realsize; /* how much we really allocated */ bus_addr_t cardaddr; /* Absolute address on card */ int kind; }; /* Bits for kind */ #define PCCARD_MEM_16BIT 1 /* 1 -> 16bit 0 -> 8bit */ #define PCCARD_MEM_ATTR 2 /* 1 -> attribute mem 0 -> common */ #define PCCARD_WIDTH_AUTO 0 #define PCCARD_WIDTH_IO8 1 #define PCCARD_WIDTH_IO16 2 struct pccard_tuple { unsigned int code; unsigned int length; u_long mult; /* dist btn successive bytes */ bus_addr_t ptr; bus_space_tag_t memt; bus_space_handle_t memh; }; typedef int (*pccard_scan_t)(const struct pccard_tuple *, void *); struct pccard_product { const char *pp_name; #define PCCARD_VENDOR_ANY (0xffffffff) uint32_t pp_vendor; /* 0 == end of table */ #define PCCARD_PRODUCT_ANY (0xffffffff) uint32_t pp_product; const char *pp_cis[4]; }; +/** + * Note: There's no cis3 or cis4 reported for NOMATCH / pnpinfo events for pccard + * It's unclear if we actually need that for automatic loading or not. These stirngs + * are informative, according to the standard, but I have a dim memory of using these + * strings to match things, though I can't find the example right now. + */ +#define PCCARD_PNP_DESCR "D:human;V32:manufacturer;V32:product;Z:cisvendor;Z:cisproduct;" +#define PCCARD_PNP_INFO(t) \ + MODULE_PNP_INFO(PCCARD_PNP_DESCR, pccard, t, t, sizeof(t[0]), sizeof(t) / sizeof(t[0])); \ + typedef int (*pccard_product_match_fn) (device_t dev, const struct pccard_product *ent, int vpfmatch); #include "card_if.h" /* * make this inline so that we don't have to worry about dangling references * to it in the modules or the code. */ static inline const struct pccard_product * pccard_product_lookup(device_t dev, const struct pccard_product *tab, size_t ent_size, pccard_product_match_fn matchfn) { return CARD_DO_PRODUCT_LOOKUP(device_get_parent(dev), dev, tab, ent_size, matchfn); } #define pccard_cis_read_1(tuple, idx0) \ (bus_space_read_1((tuple)->memt, (tuple)->memh, (tuple)->mult*(idx0))) #define pccard_tuple_read_1(tuple, idx1) \ (pccard_cis_read_1((tuple), ((tuple)->ptr+(2+(idx1))))) #define pccard_tuple_read_2(tuple, idx2) \ (pccard_tuple_read_1((tuple), (idx2)) | \ (pccard_tuple_read_1((tuple), (idx2)+1)<<8)) #define pccard_tuple_read_3(tuple, idx3) \ (pccard_tuple_read_1((tuple), (idx3)) | \ (pccard_tuple_read_1((tuple), (idx3)+1)<<8) | \ (pccard_tuple_read_1((tuple), (idx3)+2)<<16)) #define pccard_tuple_read_4(tuple, idx4) \ (pccard_tuple_read_1((tuple), (idx4)) | \ (pccard_tuple_read_1((tuple), (idx4)+1)<<8) | \ (pccard_tuple_read_1((tuple), (idx4)+2)<<16) | \ (pccard_tuple_read_1((tuple), (idx4)+3)<<24)) #define pccard_tuple_read_n(tuple, n, idxn) \ (((n)==1)?pccard_tuple_read_1((tuple), (idxn)) : \ (((n)==2)?pccard_tuple_read_2((tuple), (idxn)) : \ (((n)==3)?pccard_tuple_read_3((tuple), (idxn)) : \ /* n == 4 */ pccard_tuple_read_4((tuple), (idxn))))) #define PCCARD_SPACE_MEMORY 1 #define PCCARD_SPACE_IO 2 #define pccard_mfc(sc) \ (STAILQ_FIRST(&(sc)->card.pf_head) && \ STAILQ_NEXT(STAILQ_FIRST(&(sc)->card.pf_head),pf_list)) /* Convenience functions */ static inline int pccard_cis_scan(device_t dev, pccard_scan_t fct, void *arg) { return (CARD_CIS_SCAN(device_get_parent(dev), dev, fct, arg)); } static inline int pccard_attr_read_1(device_t dev, uint32_t offset, uint8_t *val) { return (CARD_ATTR_READ(device_get_parent(dev), dev, offset, val)); } static inline int pccard_attr_write_1(device_t dev, uint32_t offset, uint8_t val) { return (CARD_ATTR_WRITE(device_get_parent(dev), dev, offset, val)); } static inline int pccard_ccr_read_1(device_t dev, uint32_t offset, uint8_t *val) { return (CARD_CCR_READ(device_get_parent(dev), dev, offset, val)); } static inline int pccard_ccr_write_1(device_t dev, uint32_t offset, uint8_t val) { return (CARD_CCR_WRITE(device_get_parent(dev), dev, offset, val)); } /* Hack */ int pccard_select_cfe(device_t dev, int entry); /* ivar interface */ enum { PCCARD_IVAR_ETHADDR, /* read ethernet address from CIS tupple */ PCCARD_IVAR_VENDOR, PCCARD_IVAR_PRODUCT, PCCARD_IVAR_PRODEXT, PCCARD_IVAR_FUNCTION_NUMBER, PCCARD_IVAR_VENDOR_STR, /* CIS string for "Manufacturer" */ PCCARD_IVAR_PRODUCT_STR,/* CIS string for "Product" */ PCCARD_IVAR_CIS3_STR, PCCARD_IVAR_CIS4_STR, PCCARD_IVAR_FUNCTION, PCCARD_IVAR_FUNCE_DISK }; #define PCCARD_ACCESSOR(A, B, T) \ static inline int \ pccard_get_ ## A(device_t dev, T *t) \ { \ return BUS_READ_IVAR(device_get_parent(dev), dev, \ PCCARD_IVAR_ ## B, (uintptr_t *) t); \ } PCCARD_ACCESSOR(ether, ETHADDR, uint8_t) PCCARD_ACCESSOR(vendor, VENDOR, uint32_t) PCCARD_ACCESSOR(product, PRODUCT, uint32_t) PCCARD_ACCESSOR(prodext, PRODEXT, uint16_t) PCCARD_ACCESSOR(function_number,FUNCTION_NUMBER, uint32_t) PCCARD_ACCESSOR(function, FUNCTION, uint32_t) PCCARD_ACCESSOR(funce_disk, FUNCE_DISK, uint16_t) PCCARD_ACCESSOR(vendor_str, VENDOR_STR, const char *) PCCARD_ACCESSOR(product_str, PRODUCT_STR, const char *) PCCARD_ACCESSOR(cis3_str, CIS3_STR, const char *) PCCARD_ACCESSOR(cis4_str, CIS4_STR, const char *) /* shared memory flags */ enum { PCCARD_A_MEM_COM, /* common */ PCCARD_A_MEM_ATTR, /* attribute */ PCCARD_A_MEM_8BIT, /* 8 bit */ PCCARD_A_MEM_16BIT /* 16 bit */ }; #define PCCARD_S(a, b) PCMCIA_STR_ ## a ## _ ## b #define PCCARD_P(a, b) PCMCIA_PRODUCT_ ## a ## _ ## b #define PCCARD_C(a, b) PCMCIA_CIS_ ## a ## _ ## b #define PCMCIA_CARD_D(v, p) { PCCARD_S(v, p), PCMCIA_VENDOR_ ## v, \ PCCARD_P(v, p), PCCARD_C(v, p) } #define PCMCIA_CARD(v, p) { PCCARD_S(v, p), PCMCIA_VENDOR_ ## v, \ PCCARD_P(v, p), PCCARD_C(v, p) } /* * Defines to decode the get_funce_disk return value. See the PCMCIA standard * for all the details of what these bits mean. */ #define PFD_I_V_MASK 0x3 #define PFD_I_V_NONE_REQUIRED 0x0 #define PFD_I_V_REQ_MOD_ACC 0x1 #define PFD_I_V_REQ_ACC 0x2 #define PFD_I_V_REQ_ALWYS 0x1 #define PFD_I_S 0x4 /* 0 rotating, 1 silicon */ #define PFD_I_U 0x8 /* SN Uniq? */ #define PFD_I_D 0x10 /* 0 - 1 drive, 1 - 2 drives */ #define PFD_P_P0 0x100 #define PFD_P_P1 0x200 #define PFD_P_P2 0x400 #define PFD_P_P3 0x800 #define PFD_P_N 0x1000 /* 3f7/377 excluded? */ #define PFD_P_E 0x2000 /* Index bit supported? */ #define PFD_P_I 0x4000 /* twincard */ Index: head/sys/dev/sn/if_sn_pccard.c =================================================================== --- head/sys/dev/sn/if_sn_pccard.c (revision 292078) +++ head/sys/dev/sn/if_sn_pccard.c (revision 292079) @@ -1,329 +1,330 @@ /*- * Copyright (c) 1999 M. Warner Losh * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) * * Copyright (c) 1996 by Tatsumi Hosokawa * BSD-nomads, Tokyo, Japan. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" typedef int sn_get_enaddr_t(device_t dev, u_char *eaddr); typedef int sn_activate_t(device_t dev); struct sn_sw { int type; #define SN_NORMAL 1 #define SN_MEGAHERTZ 2 #define SN_OSITECH 3 #define SN_OSI_SOD 4 #define SN_MOTO_MARINER 5 char *typestr; sn_get_enaddr_t *get_mac; sn_activate_t *activate; }; static sn_get_enaddr_t sn_pccard_normal_get_mac; static sn_activate_t sn_pccard_normal_activate; const static struct sn_sw sn_normal_sw = { SN_NORMAL, "plain", sn_pccard_normal_get_mac, sn_pccard_normal_activate }; static sn_get_enaddr_t sn_pccard_megahertz_get_mac; static sn_activate_t sn_pccard_megahertz_activate; const static struct sn_sw sn_mhz_sw = { SN_MEGAHERTZ, "Megahertz", sn_pccard_megahertz_get_mac, sn_pccard_megahertz_activate }; static const struct sn_product { struct pccard_product prod; const struct sn_sw *sw; } sn_pccard_products[] = { { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw }, { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw }, /* { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */ { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw }, { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw}, { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw}, /* { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */ /* { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */ /* { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */ /* { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */ /* { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */ { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw }, { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw }, { { NULL } } }; static const struct sn_product * sn_pccard_lookup(device_t dev) { return ((const struct sn_product *) pccard_product_lookup(dev, (const struct pccard_product *)sn_pccard_products, sizeof(sn_pccard_products[0]), NULL)); } static int sn_pccard_probe(device_t dev) { const struct sn_product *pp; if ((pp = sn_pccard_lookup(dev)) != NULL) { if (pp->prod.pp_name != NULL) device_set_desc(dev, pp->prod.pp_name); return 0; } return EIO; } static int sn_pccard_ascii_enaddr(const char *str, u_char *enet) { uint8_t digit; int i; memset(enet, 0, ETHER_ADDR_LEN); for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { if (str[i] >= '0' && str[i] <= '9') digit |= str[i] - '0'; else if (str[i] >= 'a' && str[i] <= 'f') digit |= (str[i] - 'a') + 10; else if (str[i] >= 'A' && str[i] <= 'F') digit |= (str[i] - 'A') + 10; else return (0); /* Bogus digit!! */ /* Compensate for ordering of digits. */ if (i & 1) { enet[i >> 1] = digit; digit = 0; } else digit <<= 4; } return (1); } static int sn_pccard_normal_get_mac(device_t dev, u_char *eaddr) { int i, sum; const char *cisstr; pccard_get_ether(dev, eaddr); for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= eaddr[i]; if (sum == 0) { pccard_get_cis3_str(dev, &cisstr); if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) sum = sn_pccard_ascii_enaddr(cisstr, eaddr); } if (sum == 0) { pccard_get_cis4_str(dev, &cisstr); if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) sum = sn_pccard_ascii_enaddr(cisstr, eaddr); } return sum; } static int sn_pccard_normal_activate(device_t dev) { int err; err = sn_activate(dev); if (err) sn_deactivate(dev); return (err); } static int sn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp) { uint8_t *enaddr = argp; int i; uint8_t buffer[ETHER_ADDR_LEN * 2]; /* Code 0x81 is Megahertz' special cis node contianing the MAC */ if (tuple->code != 0x81) return (0); /* Make sure this is a sane node, as ASCII digits */ if (tuple->length != ETHER_ADDR_LEN * 2 + 1) return (0); /* Copy the MAC ADDR and return success if decoded */ for (i = 0; i < ETHER_ADDR_LEN * 2; i++) buffer[i] = pccard_tuple_read_1(tuple, i); return (sn_pccard_ascii_enaddr(buffer, enaddr)); } static int sn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr) { if (sn_pccard_normal_get_mac(dev, eaddr)) return 1; /* * If that fails, try the special CIS tuple 0x81 that the * '3288 and '3336 cards have. That tuple specifies an ASCII * string, ala CIS3 or CIS4 in the 'normal' cards. */ return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr)); } static int sn_pccard_megahertz_activate(device_t dev) { int err; struct sn_softc *sc = device_get_softc(dev); u_long start; err = sn_activate(dev); if (err) { sn_deactivate(dev); return (err); } /* * CIS resource is the modem one, so save it away. */ sc->modem_rid = sc->port_rid; sc->modem_res = sc->port_res; /* * The MHz XJEM/CCEM series of cards just need to have any * old resource allocated for the ethernet side of things, * provided bit 0x80 isn't set in the address. That bit is * evidentially reserved for modem function and is how the * card steers the addresses internally. */ sc->port_res = NULL; start = 0; do { sc->port_rid = 1; sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE); if (sc->port_res == NULL) break; if (!(rman_get_start(sc->port_res) & 0x80)) break; start = rman_get_start(sc->port_res) + SMC_IO_EXTENT; bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, sc->port_res); } while (start < 0xff80); if (sc->port_res == NULL) { sn_deactivate(dev); return ENOMEM; } return 0; } static int sn_pccard_attach(device_t dev) { struct sn_softc *sc = device_get_softc(dev); u_char eaddr[ETHER_ADDR_LEN]; int i, err; uint16_t w; u_char sum; const struct sn_product *pp; pp = sn_pccard_lookup(dev); sum = pp->sw->get_mac(dev, eaddr); /* Allocate resources so we can program the ether addr */ sc->dev = dev; err = pp->sw->activate(dev); if (err != 0) return (err); if (sum) { printf("Programming sn card's addr\n"); SMC_SELECT_BANK(sc, 1); for (i = 0; i < 3; i++) { w = (uint16_t)eaddr[i * 2] | (((uint16_t)eaddr[i * 2 + 1]) << 8); CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w); } } err = sn_attach(dev); if (err) sn_deactivate(dev); return (err); } static device_method_t sn_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, sn_pccard_probe), DEVMETHOD(device_attach, sn_pccard_attach), DEVMETHOD(device_detach, sn_detach), { 0, 0 } }; static driver_t sn_pccard_driver = { "sn", sn_pccard_methods, sizeof(struct sn_softc), }; extern devclass_t sn_devclass; DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0); MODULE_DEPEND(sn, ether, 1, 1, 1); +PCCARD_PNP_INFO(sn_pccard_products); Index: head/sys/dev/snc/if_snc_pccard.c =================================================================== --- head/sys/dev/snc/if_snc_pccard.c (revision 292078) +++ head/sys/dev/snc/if_snc_pccard.c (revision 292079) @@ -1,163 +1,164 @@ /*- * Copyright (c) 1995, David Greenman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); /* * National Semiconductor DP8393X SONIC Driver * * This is the PC Card attachment on FreeBSD * written by Motomichi Matsuzaki and * Hiroshi Yamashita */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product snc_pccard_products[] = { PCMCIA_CARD(NEC, PC9801N_J02), PCMCIA_CARD(NEC, PC9801N_J02R), { NULL } }; /* * PC Card (PCMCIA) specific code. */ static int snc_pccard_probe(device_t); static int snc_pccard_attach(device_t); static int snc_pccard_detach(device_t); static device_method_t snc_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, snc_pccard_probe), DEVMETHOD(device_attach, snc_pccard_attach), DEVMETHOD(device_detach, snc_pccard_detach), { 0, 0 } }; static driver_t snc_pccard_driver = { "snc", snc_pccard_methods, sizeof(struct snc_softc) }; DRIVER_MODULE(snc, pccard, snc_pccard_driver, snc_devclass, 0, 0); MODULE_DEPEND(snc, ether, 1, 1, 1); +PCCARD_PNP_INFO(snc_pccard_products); /* * snc_pccard_detach - detach this instance from the device. */ static int snc_pccard_detach(device_t dev) { struct snc_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; if (sc->gone) { device_printf(dev, "already unloaded\n"); return (0); } SNC_LOCK(sc); sncshutdown(sc); SNC_UNLOCK(sc); callout_drain(&sc->sc_timer); ether_ifdetach(ifp); sc->gone = 1; bus_teardown_intr(dev, sc->irq, sc->irq_handle); snc_release_resources(dev); mtx_destroy(&sc->sc_lock); return (0); } /* * Probe the pccard. */ static int snc_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, snc_pccard_products, sizeof(snc_pccard_products[0]), NULL)) == NULL) return (EIO); if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return (0); } static int snc_pccard_attach(device_t dev) { struct snc_softc *sc = device_get_softc(dev); int error; /* * Not sure that this belongs here or in snc_pccard_attach */ if ((error = snc_alloc_port(dev, 0)) != 0) goto err; if ((error = snc_alloc_memory(dev, 0)) != 0) goto err; if ((error = snc_alloc_irq(dev, 0, 0)) != 0) goto err; if ((error = snc_probe(dev, SNEC_TYPE_PNP)) != 0) goto err; /* This interface is always enabled. */ sc->sc_enabled = 1; /* pccard_get_ether(dev, ether_addr); */ if ((error = snc_attach(dev)) != 0) goto err; return 0; err:; snc_release_resources(dev); return error; } Index: head/sys/dev/stg/tmc18c30_pccard.c =================================================================== --- head/sys/dev/stg/tmc18c30_pccard.c (revision 292078) +++ head/sys/dev/stg/tmc18c30_pccard.c (revision 292079) @@ -1,138 +1,139 @@ /* $NecBSD: tmc18c30_pisa.c,v 1.22 1998/11/26 01:59:21 honda Exp $ */ /* $NetBSD$ */ /*- * [Ported for FreeBSD] * Copyright (c) 2000 * Noriaki Mitsunaga, Mitsuru Iwasaki and Takanori Watanabe. * All rights reserved. * [NetBSD for NEC PC-98 series] * Copyright (c) 1996, 1997, 1998 * NetBSD/pc98 porting staff. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Naofumi HONDA. All rights reserved. * Copyright (c) 1996, 1997, 1998 * Kouichi Matsuda. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static const struct pccard_product stg_products[] = { PCMCIA_CARD(FUTUREDOMAIN, SCSI2GO), PCMCIA_CARD(IBM, SCSICARD), PCMCIA_CARD(RATOC, REX5536), PCMCIA_CARD(RATOC, REX5536AM), PCMCIA_CARD(RATOC, REX5536M), { NULL } }; /* * Additional code for FreeBSD new-bus PC Card frontend */ static int stg_pccard_probe(device_t dev) { const struct pccard_product *pp; if ((pp = pccard_product_lookup(dev, stg_products, sizeof(stg_products[0]), NULL)) != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return (BUS_PROBE_DEFAULT); } return(EIO); } static int stg_pccard_attach(device_t dev) { struct stg_softc *sc = device_get_softc(dev); int error; sc->port_rid = 0; sc->irq_rid = 0; error = stg_alloc_resource(dev); if (error) { return(error); } if (stg_probe(dev) == 0) { stg_release_resource(dev); return(ENXIO); } error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, stg_intr, sc, &sc->stg_intrhand); if (error) { stg_release_resource(dev); return(error); } if (stg_attach(dev) == 0) { stg_release_resource(dev); return(ENXIO); } return(0); } static device_method_t stg_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, stg_pccard_probe), DEVMETHOD(device_attach, stg_pccard_attach), DEVMETHOD(device_detach, stg_detach), { 0, 0 } }; static driver_t stg_pccard_driver = { "stg", stg_pccard_methods, sizeof(struct stg_softc), }; DRIVER_MODULE(stg, pccard, stg_pccard_driver, stg_devclass, 0, 0); MODULE_DEPEND(stg, scsi_low, 1, 1, 1); +PCCARD_PNP_INFO(stg_pccard_products); Index: head/sys/dev/uart/uart_bus_pccard.c =================================================================== --- head/sys/dev/uart/uart_bus_pccard.c (revision 292078) +++ head/sys/dev/uart/uart_bus_pccard.c (revision 292079) @@ -1,100 +1,104 @@ /*- * Copyright (c) 2001 M. Warner Losh. All rights reserved. * Copyright (c) 2003 Norikatsu Shigemura, Takenori Watanabe All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" static int uart_pccard_probe(device_t dev); static int uart_pccard_attach(device_t dev); static device_method_t uart_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_pccard_probe), DEVMETHOD(device_attach, uart_pccard_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; +static uint32_t uart_pccard_function = PCCARD_FUNCTION_SERIAL; + static driver_t uart_pccard_driver = { uart_driver_name, uart_pccard_methods, sizeof(struct uart_softc), }; static int uart_pccard_probe(device_t dev) { int error; uint32_t fcn; fcn = PCCARD_FUNCTION_UNSPEC; error = pccard_get_function(dev, &fcn); if (error != 0) return (error); /* * If a serial card, we are likely the right driver. However, * some serial cards are better serviced by other drivers, so * allow other drivers to claim it, if they want. */ - if (fcn == PCCARD_FUNCTION_SERIAL) + if (fcn == uart_pccard_function) return (BUS_PROBE_GENERIC); return (ENXIO); } static int uart_pccard_attach(device_t dev) { struct uart_softc *sc; int error; sc = device_get_softc(dev); sc->sc_class = &uart_ns8250_class; error = uart_bus_probe(dev, 0, 0, 0, 0); if (error > 0) return (error); return (uart_bus_attach(dev)); } DRIVER_MODULE(uart, pccard, uart_pccard_driver, uart_devclass, 0, 0); +MODULE_PNP_INFO("U32:function_type;", pccard, uart, &uart_pccard_function, + sizeof(uart_pccard_function), 1); Index: head/sys/dev/wi/if_wi_pccard.c =================================================================== --- head/sys/dev/wi/if_wi_pccard.c (revision 292078) +++ head/sys/dev/wi/if_wi_pccard.c (revision 292079) @@ -1,202 +1,203 @@ /*- * Copyright (c) 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. * * Written by Bill Paul * Electrical Engineering Department * Columbia University, New York City */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" static int wi_pccard_probe(device_t); static int wi_pccard_attach(device_t); static device_method_t wi_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, wi_pccard_probe), DEVMETHOD(device_attach, wi_pccard_attach), DEVMETHOD(device_detach, wi_detach), DEVMETHOD(device_shutdown, wi_shutdown), { 0, 0 } }; static driver_t wi_pccard_driver = { "wi", wi_pccard_methods, sizeof(struct wi_softc) }; DRIVER_MODULE(wi, pccard, wi_pccard_driver, wi_devclass, 0, 0); MODULE_DEPEND(wi, wlan, 1, 1, 1); static const struct pccard_product wi_pccard_products[] = { PCMCIA_CARD(3COM, 3CRWE737A), PCMCIA_CARD(3COM, 3CRWE777A), PCMCIA_CARD(ACTIONTEC, PRISM), PCMCIA_CARD(ADAPTEC2, ANW8030), PCMCIA_CARD(ADDTRON, AWP100), PCMCIA_CARD(AIRVAST, WN_100B), PCMCIA_CARD(AIRVAST, WN_100), PCMCIA_CARD(ALLIEDTELESIS, WR211PCM), PCMCIA_CARD(ARTEM, ONAIR), PCMCIA_CARD(ASUS, WL100), PCMCIA_CARD(BAY, EMOBILITY_11B), PCMCIA_CARD(BROMAX, IWN), PCMCIA_CARD(BROMAX, IWN3), PCMCIA_CARD(BROMAX, WCF11), PCMCIA_CARD(BUFFALO, WLI_CF_S11G), PCMCIA_CARD(BUFFALO, WLI_PCM_S11), PCMCIA_CARD(COMPAQ, NC5004), PCMCIA_CARD(CONTEC, FX_DS110_PCC), PCMCIA_CARD(COREGA, WIRELESS_LAN_PCC_11), PCMCIA_CARD(COREGA, WIRELESS_LAN_PCCA_11), PCMCIA_CARD(COREGA, WIRELESS_LAN_PCCB_11), PCMCIA_CARD(COREGA, WIRELESS_LAN_PCCL_11), PCMCIA_CARD(DLINK, DWL650H), PCMCIA_CARD(ELSA, XI300_IEEE), PCMCIA_CARD(ELSA, XI325_IEEE), PCMCIA_CARD(ELSA, APDL325_IEEE), PCMCIA_CARD(ELSA, XI330_IEEE), PCMCIA_CARD(ELSA, XI800_IEEE), PCMCIA_CARD(ELSA, WIFI_FLASH), PCMCIA_CARD(EMTAC, WLAN), PCMCIA_CARD(ERICSSON, WIRELESSLAN), PCMCIA_CARD(GEMTEK, WLAN), PCMCIA_CARD(HWN, AIRWAY80211), PCMCIA_CARD(INTEL, PRO_WLAN_2011), PCMCIA_CARD(INTERSIL, ISL37100P), PCMCIA_CARD(INTERSIL, ISL37110P), PCMCIA_CARD(INTERSIL, ISL37300P), PCMCIA_CARD(INTERSIL2, PRISM2), PCMCIA_CARD(IODATA2, WCF12), PCMCIA_CARD(IODATA2, WNB11PCM), PCMCIA_CARD(FUJITSU, WL110), PCMCIA_CARD(LUCENT, WAVELAN_IEEE), PCMCIA_CARD(MICROSOFT, MN_520), PCMCIA_CARD(NOKIA, C020_WLAN), PCMCIA_CARD(NOKIA, C110_WLAN), PCMCIA_CARD(PLANEX, GWNS11H), PCMCIA_CARD(PROXIM, HARMONY), PCMCIA_CARD(PROXIM, RANGELANDS_8430), PCMCIA_CARD(SAMSUNG, SWL_2000N), PCMCIA_CARD(SIEMENS, SS1021), PCMCIA_CARD(SIEMENS, SS1021A), PCMCIA_CARD(SIMPLETECH, SPECTRUM24_ALT), PCMCIA_CARD(SOCKET, LP_WLAN_CF), PCMCIA_CARD(TDK, LAK_CD011WL), { NULL } }; +PCCARD_PNP_INFO(wi_pccard_products); static int wi_pccard_probe(device_t dev) { const struct pccard_product *pp; u_int32_t fcn = PCCARD_FUNCTION_UNSPEC; int error; /* Make sure we're a network driver */ error = pccard_get_function(dev, &fcn); if (error != 0) return error; if (fcn != PCCARD_FUNCTION_NETWORK) return ENXIO; pp = pccard_product_lookup(dev, wi_pccard_products, sizeof(wi_pccard_products[0]), NULL); if (pp != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); return 0; } return ENXIO; } static int wi_pccard_attach(device_t dev) { struct wi_softc *sc; int error; sc = device_get_softc(dev); sc->wi_gone = 0; sc->wi_bus_type = WI_BUS_PCCARD; error = wi_alloc(dev, 0); if (error == 0) { /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); error = wi_attach(dev); if (error != 0) wi_free(dev); } return error; } Index: head/sys/dev/xe/if_xe_pccard.c =================================================================== --- head/sys/dev/xe/if_xe_pccard.c (revision 292078) +++ head/sys/dev/xe/if_xe_pccard.c (revision 292079) @@ -1,388 +1,389 @@ /*- * Copyright (c) 2002 Takeshi Shibagaki * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* xe pccard interface driver */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "card_if.h" #include "pccarddevs.h" /* * Debug logging levels - set with hw.xe.debug sysctl * 0 = None * 1 = More hardware details, probe/attach progress * 2 = Most function calls, ioctls and media selection progress * 3 = Everything - interrupts, packets in/out and multicast address setup */ #define XE_DEBUG #ifdef XE_DEBUG extern int xe_debug; #define DEVPRINTF(level, arg) if (xe_debug >= (level)) device_printf arg #define DPRINTF(level, arg) if (xe_debug >= (level)) printf arg #else #define DEVPRINTF(level, arg) #define DPRINTF(level, arg) #endif #define XE_CARD_TYPE_FLAGS_NO 0x0 #define XE_CARD_TYPE_FLAGS_CE2 0x1 #define XE_CARD_TYPE_FLAGS_MOHAWK 0x2 #define XE_CARD_TYPE_FLAGS_DINGO 0x4 #define XE_PROD_ETHER_MASK 0x0100 #define XE_PROD_MODEM_MASK 0x1000 #define XE_BOGUS_MAC_OFFSET 0x90 /* MAC vendor prefix used by most Xircom cards is 00:80:c7 */ #define XE_MAC_ADDR_0 0x00 #define XE_MAC_ADDR_1 0x80 #define XE_MAC_ADDR_2 0xc7 /* Some (all?) REM56 cards have vendor prefix 00:10:a4 */ #define XE_REM56_MAC_ADDR_0 0x00 #define XE_REM56_MAC_ADDR_1 0x10 #define XE_REM56_MAC_ADDR_2 0xa4 struct xe_pccard_product { struct pccard_product product; uint16_t prodext; uint16_t flags; }; static const struct xe_pccard_product xe_pccard_products[] = { { PCMCIA_CARD_D(COMPAQ, CPQ550), 0x43, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(COMPAQ2, CPQ_10_100), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, { PCMCIA_CARD_D(INTEL, EEPRO100), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, { PCMCIA_CARD_D(INTEL, PRO100LAN56), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, { PCMCIA_CARD_D(RACORE, ACCTON_EN2226),0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, { PCMCIA_CARD_D(XIRCOM, CE), 0x41, XE_CARD_TYPE_FLAGS_NO }, { PCMCIA_CARD_D(XIRCOM, CE2), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CE2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CE2_2), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CE2_2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CE3), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, { PCMCIA_CARD_D(XIRCOM, CEM), 0x41, XE_CARD_TYPE_FLAGS_NO }, { PCMCIA_CARD_D(XIRCOM, CEM2), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CEM28), 0x43, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CEM33), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CEM33_2), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, { PCMCIA_CARD_D(XIRCOM, CEM56), 0x45, XE_CARD_TYPE_FLAGS_DINGO }, { PCMCIA_CARD_D(XIRCOM, CEM56_2), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, { PCMCIA_CARD_D(XIRCOM, REM56), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, { PCMCIA_CARD_D(XIRCOM, REM10), 0x47, XE_CARD_TYPE_FLAGS_DINGO }, { PCMCIA_CARD_D(XIRCOM, XEM5600), 0x56, XE_CARD_TYPE_FLAGS_DINGO }, { { NULL }, 0, 0 } }; /* * Fixing for CEM2, CEM3 and CEM56/REM56 cards. These need some magic to * enable the Ethernet function, which isn't mentioned anywhere in the CIS. * Despite the register names, most of this isn't Dingo-specific. */ static int xe_cemfix(device_t dev) { struct xe_softc *sc = device_get_softc(dev); int ioport; DEVPRINTF(2, (dev, "cemfix\n")); DEVPRINTF(1, (dev, "CEM I/O port 0x%0lx, size 0x%0lx\n", bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid))); pccard_attr_write_1(dev, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL | DINGO_ECOR_INT_ENABLE | DINGO_ECOR_IOB_ENABLE | DINGO_ECOR_ETH_ENABLE); ioport = bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid); pccard_attr_write_1(dev, DINGO_EBAR0, ioport & 0xff); pccard_attr_write_1(dev, DINGO_EBAR1, (ioport >> 8) & 0xff); if (sc->dingo) { pccard_attr_write_1(dev, DINGO_DCOR0, DINGO_DCOR0_SF_INT); pccard_attr_write_1(dev, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL | DINGO_DCOR1_EEDIO); pccard_attr_write_1(dev, DINGO_DCOR2, 0x00); pccard_attr_write_1(dev, DINGO_DCOR3, 0x00); pccard_attr_write_1(dev, DINGO_DCOR4, 0x00); } /* success! */ return (0); } static int xe_pccard_product_match(device_t dev, const struct pccard_product* ent, int vpfmatch) { const struct xe_pccard_product* xpp; uint16_t prodext; if (vpfmatch == 0) return (0); xpp = (const struct xe_pccard_product*)ent; pccard_get_prodext(dev, &prodext); if (xpp->prodext != prodext) vpfmatch = 0; else vpfmatch++; return (vpfmatch); } static const struct xe_pccard_product * xe_pccard_get_product(device_t dev) { return ((const struct xe_pccard_product *)pccard_product_lookup(dev, (const struct pccard_product *)xe_pccard_products, sizeof(xe_pccard_products[0]), xe_pccard_product_match)); } /* * Fixing for CE2-class cards with bogus CIS entry for MAC address. */ static int xe_pccard_mac(const struct pccard_tuple *tuple, void *argp) { uint8_t *enaddr = argp, test; int i; /* Code 0x89 is Xircom special cis node contianing the MAC */ if (tuple->code != 0x89) return (0); /* Make sure this is a sane node */ if (tuple->length != ETHER_ADDR_LEN + 2) return (0); test = pccard_tuple_read_1(tuple, 0); if (test != PCCARD_TPLFE_TYPE_LAN_NID) return (0); test = pccard_tuple_read_1(tuple, 1); if (test != ETHER_ADDR_LEN) return (0); /* Copy the MAC ADDR and return success */ for (i = 0; i < ETHER_ADDR_LEN; i++) enaddr[i] = pccard_tuple_read_1(tuple, i + 2); return (1); } static int xe_bad_mac(uint8_t *enaddr) { int i; uint8_t sum; for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) sum |= enaddr[i]; return (sum == 0); } /* * PCMCIA attach routine. * Identify the device. Called from the bus driver when the card is * inserted or otherwise powers up. */ static int xe_pccard_attach(device_t dev) { struct xe_softc *scp = device_get_softc(dev); uint32_t vendor,product; uint16_t prodext; const char* vendor_str = NULL; const char* product_str = NULL; const char* cis4_str = NULL; const char *cis3_str=NULL; const struct xe_pccard_product *xpp; int err; DEVPRINTF(2, (dev, "pccard_attach\n")); pccard_get_vendor(dev, &vendor); pccard_get_product(dev, &product); pccard_get_prodext(dev, &prodext); pccard_get_vendor_str(dev, &vendor_str); pccard_get_product_str(dev, &product_str); pccard_get_cis3_str(dev, &cis3_str); pccard_get_cis4_str(dev, &cis4_str); DEVPRINTF(1, (dev, "vendor = 0x%04x\n", vendor)); DEVPRINTF(1, (dev, "product = 0x%04x\n", product)); DEVPRINTF(1, (dev, "prodext = 0x%02x\n", prodext)); DEVPRINTF(1, (dev, "vendor_str = %s\n", vendor_str)); DEVPRINTF(1, (dev, "product_str = %s\n", product_str)); DEVPRINTF(1, (dev, "cis3_str = %s\n", cis3_str)); DEVPRINTF(1, (dev, "cis4_str = %s\n", cis4_str)); xpp = xe_pccard_get_product(dev); if (xpp == NULL) return (ENXIO); /* Set various card ID fields in softc */ scp->vendor = vendor_str; scp->card_type = product_str; if (xpp->flags & XE_CARD_TYPE_FLAGS_CE2) scp->ce2 = 1; if (xpp->flags & XE_CARD_TYPE_FLAGS_MOHAWK) scp->mohawk = 1; if (xpp->flags & XE_CARD_TYPE_FLAGS_DINGO) { scp->dingo = 1; scp->mohawk = 1; } if (xpp->product.pp_product & XE_PROD_MODEM_MASK) scp->modem = 1; /* Get MAC address */ pccard_get_ether(dev, scp->enaddr); /* Deal with bogus MAC address */ if (xe_bad_mac(scp->enaddr) && !pccard_cis_scan(dev, xe_pccard_mac, scp->enaddr)) { device_printf(dev, "Unable to find MAC address for your %s card\n", device_get_desc(dev)); return (ENXIO); } if ((err = xe_activate(dev)) != 0) return (err); /* Hack RealPorts into submission */ if (scp->modem && xe_cemfix(dev) < 0) { device_printf(dev, "Unable to fix your %s combo card\n", device_get_desc(dev)); xe_deactivate(dev); return (ENXIO); } if ((err = xe_attach(dev))) { device_printf(dev, "xe_attach() failed! (%d)\n", err); xe_deactivate(dev); return (err); } return (0); } /* * The device entry is being removed, probably because someone ejected the * card. The interface should have been brought down manually before calling * this function; if not you may well lose packets. In any case, I shut down * the card and the interface, and hope for the best. */ static int xe_pccard_detach(device_t dev) { struct xe_softc *sc = device_get_softc(dev); DEVPRINTF(2, (dev, "pccard_detach\n")); XE_LOCK(sc); xe_stop(sc); XE_UNLOCK(sc); callout_drain(&sc->media_timer); callout_drain(&sc->wdog_timer); ether_ifdetach(sc->ifp); xe_deactivate(dev); mtx_destroy(&sc->lock); return (0); } static int xe_pccard_probe(device_t dev) { const struct xe_pccard_product *xpp; DEVPRINTF(2, (dev, "pccard_probe\n")); /* * Xircom cards aren't proper MFC cards, so we have to take all * cards that match, not just ones that are network. */ /* If we match something in the table, it is our device. */ if ((xpp = xe_pccard_get_product(dev)) == NULL) return (ENXIO); /* Set card name for logging later */ if (xpp->product.pp_name != NULL) device_set_desc(dev, xpp->product.pp_name); /* Reject known but unsupported cards */ if (xpp->flags & XE_CARD_TYPE_FLAGS_NO) { device_printf(dev, "Sorry, your %s card is not supported :(\n", device_get_desc(dev)); return (ENXIO); } return (0); } static device_method_t xe_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xe_pccard_probe), DEVMETHOD(device_attach, xe_pccard_attach), DEVMETHOD(device_detach, xe_pccard_detach), { 0, 0 } }; static driver_t xe_pccard_driver = { "xe", xe_pccard_methods, sizeof(struct xe_softc), }; devclass_t xe_devclass; DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0); +PCCARD_PNP_INFO(xe_pccard_products); Index: head/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c =================================================================== --- head/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c (revision 292078) +++ head/sys/netgraph/bluetooth/drivers/bt3c/ng_bt3c_pccard.c (revision 292079) @@ -1,1225 +1,1225 @@ /* * ng_bt3c_pccard.c */ /*- * Copyright (c) 2001-2002 Maksim Yevmenkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: ng_bt3c_pccard.c,v 1.5 2003/04/01 18:15:21 max Exp $ * $FreeBSD$ * * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX * * Based on information obrained from: Jose Orlando Pereira * and disassembled w2k driver. * * XXX XXX XX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pccarddevs.h" #include #include #include #include #include #include #include /* Netgraph methods */ static ng_constructor_t ng_bt3c_constructor; static ng_shutdown_t ng_bt3c_shutdown; static ng_newhook_t ng_bt3c_newhook; static ng_connect_t ng_bt3c_connect; static ng_disconnect_t ng_bt3c_disconnect; static ng_rcvmsg_t ng_bt3c_rcvmsg; static ng_rcvdata_t ng_bt3c_rcvdata; /* PCMCIA driver methods */ static int bt3c_pccard_probe (device_t); static int bt3c_pccard_attach (device_t); static int bt3c_pccard_detach (device_t); static void bt3c_intr (void *); static void bt3c_receive (bt3c_softc_p); static void bt3c_swi_intr (void *); static void bt3c_forward (node_p, hook_p, void *, int); static void bt3c_send (node_p, hook_p, void *, int); static void bt3c_download_firmware (bt3c_softc_p, char const *, int); #define bt3c_set_address(sc, address) \ do { \ bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_L, ((address) & 0xff)); \ bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_ADDR_H, (((address) >> 8) & 0xff)); \ } while (0) #define bt3c_read_data(sc, data) \ do { \ (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_L); \ (data) |= ((bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_DATA_H) & 0xff) << 8); \ } while (0) #define bt3c_write_data(sc, data) \ do { \ bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_L, ((data) & 0xff)); \ bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_DATA_H, (((data) >> 8) & 0xff)); \ } while (0) #define bt3c_read_control(sc, data) \ do { \ (data) = bus_space_read_1((sc)->iot, (sc)->ioh, BT3C_CONTROL); \ } while (0) #define bt3c_write_control(sc, data) \ do { \ bus_space_write_1((sc)->iot, (sc)->ioh, BT3C_CONTROL, (data)); \ } while (0) #define bt3c_read(sc, address, data) \ do { \ bt3c_set_address((sc), (address)); \ bt3c_read_data((sc), (data)); \ } while(0) #define bt3c_write(sc, address, data) \ do { \ bt3c_set_address((sc), (address)); \ bt3c_write_data((sc), (data)); \ } while(0) static MALLOC_DEFINE(M_BT3C, "bt3c", "bt3c data structures"); /**************************************************************************** **************************************************************************** ** Netgraph specific **************************************************************************** ****************************************************************************/ /* * Netgraph node type */ /* Queue length */ static const struct ng_parse_struct_field ng_bt3c_node_qlen_type_fields[] = { { "queue", &ng_parse_int32_type, }, { "qlen", &ng_parse_int32_type, }, { NULL, } }; static const struct ng_parse_type ng_bt3c_node_qlen_type = { &ng_parse_struct_type, &ng_bt3c_node_qlen_type_fields }; /* Stat info */ static const struct ng_parse_struct_field ng_bt3c_node_stat_type_fields[] = { { "pckts_recv", &ng_parse_uint32_type, }, { "bytes_recv", &ng_parse_uint32_type, }, { "pckts_sent", &ng_parse_uint32_type, }, { "bytes_sent", &ng_parse_uint32_type, }, { "oerrors", &ng_parse_uint32_type, }, { "ierrors", &ng_parse_uint32_type, }, { NULL, } }; static const struct ng_parse_type ng_bt3c_node_stat_type = { &ng_parse_struct_type, &ng_bt3c_node_stat_type_fields }; static const struct ng_cmdlist ng_bt3c_cmdlist[] = { { NGM_BT3C_COOKIE, NGM_BT3C_NODE_GET_STATE, "get_state", NULL, &ng_parse_uint16_type }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_SET_DEBUG, "set_debug", &ng_parse_uint16_type, NULL }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_GET_DEBUG, "get_debug", NULL, &ng_parse_uint16_type }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_GET_QLEN, "get_qlen", NULL, &ng_bt3c_node_qlen_type }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_SET_QLEN, "set_qlen", &ng_bt3c_node_qlen_type, NULL }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_GET_STAT, "get_stat", NULL, &ng_bt3c_node_stat_type }, { NGM_BT3C_COOKIE, NGM_BT3C_NODE_RESET_STAT, "reset_stat", NULL, NULL }, { 0, } }; static struct ng_type typestruct = { .version = NG_ABI_VERSION, .name = NG_BT3C_NODE_TYPE, .constructor = ng_bt3c_constructor, .rcvmsg = ng_bt3c_rcvmsg, .shutdown = ng_bt3c_shutdown, .newhook = ng_bt3c_newhook, .connect = ng_bt3c_connect, .rcvdata = ng_bt3c_rcvdata, .disconnect = ng_bt3c_disconnect, .cmdlist = ng_bt3c_cmdlist }; /* * Netgraph node constructor. Do not allow to create node of this type. */ static int ng_bt3c_constructor(node_p node) { return (EINVAL); } /* ng_bt3c_constructor */ /* * Netgraph node destructor. Destroy node only when device has been detached */ static int ng_bt3c_shutdown(node_p node) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); /* Let old node go */ NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); /* Create new fresh one if we are not going down */ if (sc == NULL) goto out; /* Create new Netgraph node */ if (ng_make_node_common(&typestruct, &sc->node) != 0) { device_printf(sc->dev, "Could not create Netgraph node\n"); sc->node = NULL; goto out; } /* Name new Netgraph node */ if (ng_name_node(sc->node, device_get_nameunit(sc->dev)) != 0) { device_printf(sc->dev, "Could not name Netgraph node\n"); NG_NODE_UNREF(sc->node); sc->node = NULL; goto out; } NG_NODE_SET_PRIVATE(sc->node, sc); out: return (0); } /* ng_bt3c_shutdown */ /* * Create new hook. There can only be one. */ static int ng_bt3c_newhook(node_p node, hook_p hook, char const *name) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); if (strcmp(name, NG_BT3C_HOOK) != 0) return (EINVAL); if (sc->hook != NULL) return (EISCONN); sc->hook = hook; return (0); } /* ng_bt3c_newhook */ /* * Connect hook. Say YEP, that's OK with me. */ static int ng_bt3c_connect(hook_p hook) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); if (hook != sc->hook) { sc->hook = NULL; return (EINVAL); } /* set the hook into queueing mode (for incoming (from wire) packets) */ NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); return (0); } /* ng_bt3c_connect */ /* * Disconnect hook */ static int ng_bt3c_disconnect(hook_p hook) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); /* * We need to check for sc != NULL because we can be called from * bt3c_pccard_detach() via ng_rmnode_self() */ if (sc != NULL) { if (hook != sc->hook) return (EINVAL); IF_DRAIN(&sc->inq); IF_DRAIN(&sc->outq); sc->hook = NULL; } return (0); } /* ng_bt3c_disconnect */ /* * Process control message */ static int ng_bt3c_rcvmsg(node_p node, item_p item, hook_p lasthook) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct ng_mesg *msg = NULL, *rsp = NULL; int error = 0; if (sc == NULL) { NG_FREE_ITEM(item); return (EHOSTDOWN); } NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_GENERIC_COOKIE: switch (msg->header.cmd) { case NGM_TEXT_STATUS: NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); if (rsp == NULL) error = ENOMEM; else snprintf(rsp->data, NG_TEXTRESPONSE, "Hook: %s\n" \ "Flags: %#x\n" \ "Debug: %d\n" \ "State: %d\n" \ "IncmQ: [len:%d,max:%d]\n" \ "OutgQ: [len:%d,max:%d]\n", (sc->hook != NULL)? NG_BT3C_HOOK : "", sc->flags, sc->debug, sc->state, _IF_QLEN(&sc->inq), /* XXX */ sc->inq.ifq_maxlen, /* XXX */ _IF_QLEN(&sc->outq), /* XXX */ sc->outq.ifq_maxlen /* XXX */ ); break; default: error = EINVAL; break; } break; case NGM_BT3C_COOKIE: switch (msg->header.cmd) { case NGM_BT3C_NODE_GET_STATE: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_state_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else *((ng_bt3c_node_state_ep *)(rsp->data)) = sc->state; break; case NGM_BT3C_NODE_SET_DEBUG: if (msg->header.arglen != sizeof(ng_bt3c_node_debug_ep)) error = EMSGSIZE; else sc->debug = *((ng_bt3c_node_debug_ep *)(msg->data)); break; case NGM_BT3C_NODE_GET_DEBUG: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_debug_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else *((ng_bt3c_node_debug_ep *)(rsp->data)) = sc->debug; break; case NGM_BT3C_NODE_GET_QLEN: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_qlen_ep), M_NOWAIT); if (rsp == NULL) { error = ENOMEM; break; } switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { case NGM_BT3C_NODE_IN_QUEUE: ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = NGM_BT3C_NODE_IN_QUEUE; ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = sc->inq.ifq_maxlen; break; case NGM_BT3C_NODE_OUT_QUEUE: ((ng_bt3c_node_qlen_ep *)(rsp->data))->queue = NGM_BT3C_NODE_OUT_QUEUE; ((ng_bt3c_node_qlen_ep *)(rsp->data))->qlen = sc->outq.ifq_maxlen; break; default: NG_FREE_MSG(rsp); error = EINVAL; break; } break; case NGM_BT3C_NODE_SET_QLEN: if (msg->header.arglen != sizeof(ng_bt3c_node_qlen_ep)){ error = EMSGSIZE; break; } if (((ng_bt3c_node_qlen_ep *)(msg->data))->qlen <= 0) { error = EINVAL; break; } switch (((ng_bt3c_node_qlen_ep *)(msg->data))->queue) { case NGM_BT3C_NODE_IN_QUEUE: sc->inq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) (msg->data))->qlen; /* XXX */ break; case NGM_BT3C_NODE_OUT_QUEUE: sc->outq.ifq_maxlen = ((ng_bt3c_node_qlen_ep *) (msg->data))->qlen; /* XXX */ break; default: error = EINVAL; break; } break; case NGM_BT3C_NODE_GET_STAT: NG_MKRESPONSE(rsp, msg, sizeof(ng_bt3c_node_stat_ep), M_NOWAIT); if (rsp == NULL) error = ENOMEM; else bcopy(&sc->stat, rsp->data, sizeof(ng_bt3c_node_stat_ep)); break; case NGM_BT3C_NODE_RESET_STAT: NG_BT3C_STAT_RESET(sc->stat); break; case NGM_BT3C_NODE_DOWNLOAD_FIRMWARE: if (msg->header.arglen < sizeof(ng_bt3c_firmware_block_ep)) error = EMSGSIZE; else bt3c_download_firmware(sc, msg->data, msg->header.arglen); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, rsp); NG_FREE_MSG(msg); return (error); } /* ng_bt3c_rcvmsg */ /* * Process data */ static int ng_bt3c_rcvdata(hook_p hook, item_p item) { bt3c_softc_p sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct mbuf *m = NULL; int error = 0; if (sc == NULL) { error = EHOSTDOWN; goto out; } if (hook != sc->hook) { error = EINVAL; goto out; } NGI_GET_M(item, m); IF_LOCK(&sc->outq); if (_IF_QFULL(&sc->outq)) { NG_BT3C_ERR(sc->dev, "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len); NG_BT3C_STAT_OERROR(sc->stat); NG_FREE_M(m); } else _IF_ENQUEUE(&sc->outq, m); IF_UNLOCK(&sc->outq); error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */); out: NG_FREE_ITEM(item); return (error); } /* ng_bt3c_rcvdata */ /**************************************************************************** **************************************************************************** ** PCMCIA driver specific **************************************************************************** ****************************************************************************/ /* * PC Card (PCMCIA) probe routine */ +static struct pccard_product const bt3c_pccard_products[] = { + PCMCIA_CARD(3COM, 3CRWB609), + { NULL, } +}; + static int bt3c_pccard_probe(device_t dev) { - static struct pccard_product const bt3c_pccard_products[] = { - PCMCIA_CARD(3COM, 3CRWB609), - { NULL, } - }; - struct pccard_product const *pp = NULL; pp = pccard_product_lookup(dev, bt3c_pccard_products, sizeof(bt3c_pccard_products[0]), NULL); if (pp == NULL) return (ENXIO); device_set_desc(dev, pp->pp_name); return (0); } /* bt3c_pccard_probe */ /* * PC Card (PCMCIA) attach routine */ static int bt3c_pccard_attach(device_t dev) { bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); /* Allocate I/O ports */ sc->iobase_rid = 0; sc->iobase = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->iobase_rid, 0, ~0, 8, RF_ACTIVE); if (sc->iobase == NULL) { device_printf(dev, "Could not allocate I/O ports\n"); goto bad; } sc->iot = rman_get_bustag(sc->iobase); sc->ioh = rman_get_bushandle(sc->iobase); /* Allocate IRQ */ sc->irq_rid = 0; sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_ACTIVE); if (sc->irq == NULL) { device_printf(dev, "Could not allocate IRQ\n"); goto bad; } sc->irq_cookie = NULL; if (bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, NULL, bt3c_intr, sc, &sc->irq_cookie) != 0) { device_printf(dev, "Could not setup ISR\n"); goto bad; } /* Attach handler to TTY SWI thread */ sc->ith = NULL; if (swi_add(&tty_intr_event, device_get_nameunit(dev), bt3c_swi_intr, sc, SWI_TTY, 0, &sc->ith) < 0) { device_printf(dev, "Could not setup SWI ISR\n"); goto bad; } /* Create Netgraph node */ if (ng_make_node_common(&typestruct, &sc->node) != 0) { device_printf(dev, "Could not create Netgraph node\n"); sc->node = NULL; goto bad; } /* Name Netgraph node */ if (ng_name_node(sc->node, device_get_nameunit(dev)) != 0) { device_printf(dev, "Could not name Netgraph node\n"); NG_NODE_UNREF(sc->node); sc->node = NULL; goto bad; } sc->dev = dev; sc->debug = NG_BT3C_WARN_LEVEL; sc->inq.ifq_maxlen = sc->outq.ifq_maxlen = BT3C_DEFAULTQLEN; mtx_init(&sc->inq.ifq_mtx, "BT3C inq", NULL, MTX_DEF); mtx_init(&sc->outq.ifq_mtx, "BT3C outq", NULL, MTX_DEF); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; NG_NODE_SET_PRIVATE(sc->node, sc); return (0); bad: if (sc->ith != NULL) { swi_remove(sc->ith); sc->ith = NULL; } if (sc->irq != NULL) { if (sc->irq_cookie != NULL) bus_teardown_intr(dev, sc->irq, sc->irq_cookie); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); sc->irq = NULL; sc->irq_rid = 0; } if (sc->iobase != NULL) { bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); sc->iobase = NULL; sc->iobase_rid = 0; } return (ENXIO); } /* bt3c_pccacd_attach */ /* * PC Card (PCMCIA) detach routine */ static int bt3c_pccard_detach(device_t dev) { bt3c_softc_p sc = (bt3c_softc_p) device_get_softc(dev); if (sc == NULL) return (0); swi_remove(sc->ith); sc->ith = NULL; bus_teardown_intr(dev, sc->irq, sc->irq_cookie); bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq); sc->irq_cookie = NULL; sc->irq = NULL; sc->irq_rid = 0; bus_release_resource(dev, SYS_RES_IOPORT, sc->iobase_rid, sc->iobase); sc->iobase = NULL; sc->iobase_rid = 0; if (sc->node != NULL) { NG_NODE_SET_PRIVATE(sc->node, NULL); ng_rmnode_self(sc->node); sc->node = NULL; } NG_FREE_M(sc->m); IF_DRAIN(&sc->inq); IF_DRAIN(&sc->outq); mtx_destroy(&sc->inq.ifq_mtx); mtx_destroy(&sc->outq.ifq_mtx); return (0); } /* bt3c_pccacd_detach */ /* * Interrupt service routine's */ static void bt3c_intr(void *context) { bt3c_softc_p sc = (bt3c_softc_p) context; u_int16_t control, status; if (sc == NULL || sc->ith == NULL) { printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE); return; } bt3c_read_control(sc, control); if ((control & 0x80) == 0) return; bt3c_read(sc, 0x7001, status); NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status); if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) { NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status); return; } /* Receive complete */ if (status & 0x0001) bt3c_receive(sc); /* Record status and schedule SWI */ sc->status |= status; swi_sched(sc->ith, 0); /* Complete interrupt */ bt3c_write(sc, 0x7001, 0x0000); bt3c_write_control(sc, control); } /* bt3c_intr */ /* * Receive data */ static void bt3c_receive(bt3c_softc_p sc) { u_int16_t i, count, c; /* Receive data from the card */ bt3c_read(sc, 0x7006, count); NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count); bt3c_set_address(sc, 0x7480); for (i = 0; i < count; i++) { /* Allocate new mbuf if needed */ if (sc->m == NULL) { sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; MGETHDR(sc->m, M_NOWAIT, MT_DATA); if (sc->m == NULL) { NG_BT3C_ERR(sc->dev, "Could not get mbuf\n"); NG_BT3C_STAT_IERROR(sc->stat); break; /* XXX lost of sync */ } if (!(MCLGET(sc->m, M_NOWAIT))) { NG_FREE_M(sc->m); NG_BT3C_ERR(sc->dev, "Could not get cluster\n"); NG_BT3C_STAT_IERROR(sc->stat); break; /* XXX lost of sync */ } sc->m->m_len = sc->m->m_pkthdr.len = 0; } /* Read and append character to mbuf */ bt3c_read_data(sc, c); if (sc->m->m_pkthdr.len >= MCLBYTES) { NG_BT3C_ERR(sc->dev, "Oversized frame\n"); NG_FREE_M(sc->m); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; /* XXX lost of sync */ } mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c; sc->m->m_pkthdr.len ++; NG_BT3C_INFO(sc->dev, "Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len); if (sc->m->m_pkthdr.len < sc->want) continue; /* wait for more */ switch (sc->state) { /* Got packet indicator */ case NG_BT3C_W4_PKT_IND: NG_BT3C_INFO(sc->dev, "Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *)); sc->state = NG_BT3C_W4_PKT_HDR; /* * Since packet indicator included in the packet * header just set sc->want to sizeof(packet header). */ switch (*mtod(sc->m, u_int8_t *)) { case NG_HCI_ACL_DATA_PKT: sc->want = sizeof(ng_hci_acldata_pkt_t); break; case NG_HCI_SCO_DATA_PKT: sc->want = sizeof(ng_hci_scodata_pkt_t); break; case NG_HCI_EVENT_PKT: sc->want = sizeof(ng_hci_event_pkt_t); break; default: NG_BT3C_ERR(sc->dev, "Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *)); NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(sc->m); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; } break; /* Got packet header */ case NG_BT3C_W4_PKT_HDR: sc->state = NG_BT3C_W4_PKT_DATA; switch (*mtod(sc->m, u_int8_t *)) { case NG_HCI_ACL_DATA_PKT: c = le16toh(mtod(sc->m, ng_hci_acldata_pkt_t *)->length); break; case NG_HCI_SCO_DATA_PKT: c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length; break; case NG_HCI_EVENT_PKT: c = mtod(sc->m, ng_hci_event_pkt_t *)->length; break; default: KASSERT(0, ("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *))); break; } NG_BT3C_INFO(sc->dev, "Got packet header, packet type=%#x, got so far %d, payload size=%d\n", *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len, c); if (c > 0) { sc->want += c; break; } /* else FALLTHROUGH and deliver frame */ /* XXX is this true? should we deliver empty frame? */ /* Got packet data */ case NG_BT3C_W4_PKT_DATA: NG_BT3C_INFO(sc->dev, "Got full packet, packet type=%#x, packet size=%d\n", *mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len); NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len); NG_BT3C_STAT_PCKTS_RECV(sc->stat); IF_LOCK(&sc->inq); if (_IF_QFULL(&sc->inq)) { NG_BT3C_ERR(sc->dev, "Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len); NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(sc->m); } else { _IF_ENQUEUE(&sc->inq, sc->m); sc->m = NULL; } IF_UNLOCK(&sc->inq); sc->state = NG_BT3C_W4_PKT_IND; sc->want = 1; break; default: KASSERT(0, ("Invalid node state=%d", sc->state)); break; } } bt3c_write(sc, 0x7006, 0x0000); } /* bt3c_receive */ /* * SWI interrupt handler * Netgraph part is handled via ng_send_fn() to avoid race with hook * connection/disconnection */ static void bt3c_swi_intr(void *context) { bt3c_softc_p sc = (bt3c_softc_p) context; u_int16_t data; /* Receive complete */ if (sc->status & 0x0001) { sc->status &= ~0x0001; /* XXX is it safe? */ if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0) NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n"); } /* Send complete */ if (sc->status & 0x0002) { sc->status &= ~0x0002; /* XXX is it safe */ if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0) NG_BT3C_ALERT(sc->dev, "Could not send frames!\n"); } /* Antenna position */ if (sc->status & 0x0020) { sc->status &= ~0x0020; /* XXX is it safe */ bt3c_read(sc, 0x7002, data); data &= 0x10; if (data) sc->flags |= BT3C_ANTENNA_OUT; else sc->flags &= ~BT3C_ANTENNA_OUT; NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN"); } } /* bt3c_swi_intr */ /* * Send all incoming frames to the upper layer */ static void bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct mbuf *m = NULL; int error; if (sc == NULL) return; if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { for (;;) { IF_DEQUEUE(&sc->inq, m); if (m == NULL) break; NG_SEND_DATA_ONLY(error, sc->hook, m); if (error != 0) NG_BT3C_STAT_IERROR(sc->stat); } } else { IF_LOCK(&sc->inq); for (;;) { _IF_DEQUEUE(&sc->inq, m); if (m == NULL) break; NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(m); } IF_UNLOCK(&sc->inq); } } /* bt3c_forward */ /* * Send more data to the device. Must be called when node is locked */ static void bt3c_send(node_p node, hook_p hook, void *arg, int completed) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct mbuf *m = NULL; int i, wrote, len; if (sc == NULL) return; if (completed) sc->flags &= ~BT3C_XMIT; if (sc->flags & BT3C_XMIT) return; bt3c_set_address(sc, 0x7080); for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { IF_DEQUEUE(&sc->outq, m); if (m == NULL) break; while (m != NULL) { len = min((BT3C_FIFO_SIZE - wrote), m->m_len); for (i = 0; i < len; i++) bt3c_write_data(sc, m->m_data[i]); wrote += len; m->m_data += len; m->m_len -= len; if (m->m_len > 0) break; m = m_free(m); } if (m != NULL) { IF_PREPEND(&sc->outq, m); break; } NG_BT3C_STAT_PCKTS_SENT(sc->stat); } if (wrote > 0) { NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote); bt3c_write(sc, 0x7005, wrote); sc->flags |= BT3C_XMIT; } } /* bt3c_send */ /* * Download chip firmware */ static void bt3c_download_firmware(bt3c_softc_p sc, char const *firmware, int firmware_size) { ng_bt3c_firmware_block_ep const *block = NULL; u_int16_t const *data = NULL; int i, size; u_int8_t c; /* Reset */ device_printf(sc->dev, "Reseting the card...\n"); bt3c_write(sc, 0x8040, 0x0404); bt3c_write(sc, 0x8040, 0x0400); DELAY(1); bt3c_write(sc, 0x8040, 0x0404); DELAY(17); /* Download firmware */ device_printf(sc->dev, "Starting firmware download process...\n"); for (size = 0; size < firmware_size; ) { block = (ng_bt3c_firmware_block_ep const *)(firmware + size); data = (u_int16_t const *)(block + 1); if (bootverbose) device_printf(sc->dev, "Download firmware block, " \ "address=%#08x, size=%d words, aligment=%d\n", block->block_address, block->block_size, block->block_alignment); bt3c_set_address(sc, block->block_address); for (i = 0; i < block->block_size; i++) bt3c_write_data(sc, data[i]); size += (sizeof(*block) + (block->block_size * 2) + block->block_alignment); } DELAY(17); device_printf(sc->dev, "Firmware download process complete\n"); /* Boot */ device_printf(sc->dev, "Starting the card...\n"); bt3c_set_address(sc, 0x3000); bt3c_read_control(sc, c); bt3c_write_control(sc, (c | 0x40)); DELAY(17); /* Clear registers */ device_printf(sc->dev, "Clearing card registers...\n"); bt3c_write(sc, 0x7006, 0x0000); bt3c_write(sc, 0x7005, 0x0000); bt3c_write(sc, 0x7001, 0x0000); DELAY(1000); } /* bt3c_download_firmware */ /**************************************************************************** **************************************************************************** ** Driver module **************************************************************************** ****************************************************************************/ /* * PC Card (PCMCIA) driver */ static device_method_t bt3c_pccard_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bt3c_pccard_probe), DEVMETHOD(device_attach, bt3c_pccard_attach), DEVMETHOD(device_detach, bt3c_pccard_detach), { 0, 0 } }; static driver_t bt3c_pccard_driver = { NG_BT3C_NODE_TYPE, bt3c_pccard_methods, sizeof(bt3c_softc_t) }; static devclass_t bt3c_devclass; /* * Load/Unload the driver module */ static int bt3c_modevent(module_t mod, int event, void *data) { int error; switch (event) { case MOD_LOAD: error = ng_newtype(&typestruct); if (error != 0) printf("%s: Could not register Netgraph node type, " \ "error=%d\n", NG_BT3C_NODE_TYPE, error); break; case MOD_UNLOAD: error = ng_rmtype(&typestruct); break; default: error = EOPNOTSUPP; break; } return (error); } /* bt3c_modevent */ DRIVER_MODULE(bt3c, pccard, bt3c_pccard_driver, bt3c_devclass, bt3c_modevent,0); MODULE_VERSION(ng_bt3c, NG_BLUETOOTH_VERSION); MODULE_DEPEND(ng_bt3c, netgraph, NG_ABI_VERSION, NG_ABI_VERSION,NG_ABI_VERSION); - +PCCARD_PNP_INFO(bt3c_pccard_products);