1191762Simp/*- 2191762Simp * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting 3191762Simp * All rights reserved. 4191762Simp * 5191762Simp * Redistribution and use in source and binary forms, with or without 6191762Simp * modification, are permitted provided that the following conditions 7191762Simp * are met: 8191762Simp * 1. Redistributions of source code must retain the above copyright 9191762Simp * notice, this list of conditions and the following disclaimer, 10191762Simp * without modification. 11191762Simp * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12191762Simp * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13191762Simp * redistribution must be conditioned upon including a substantially 14191762Simp * similar Disclaimer requirement for further binary redistribution. 15191762Simp * 16191762Simp * NO WARRANTY 17191762Simp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18191762Simp * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19191762Simp * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20191762Simp * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21191762Simp * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22191762Simp * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23191762Simp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24191762Simp * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25191762Simp * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26191762Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27191762Simp * THE POSSIBILITY OF SUCH DAMAGES. 28191762Simp */ 29191762Simp 30191762Simp#include <sys/cdefs.h> 31191762Simp__FBSDID("$FreeBSD$"); 32191762Simp 33191762Simp/* 34191762Simp * PCI/Cardbus front-end for the Broadcom Wireless LAN controller driver. 35191762Simp */ 36191762Simp 37191762Simp#include <sys/param.h> 38191762Simp#include <sys/systm.h> 39191762Simp#include <sys/module.h> 40191762Simp#include <sys/kernel.h> 41191762Simp#include <sys/lock.h> 42191762Simp#include <sys/mutex.h> 43191762Simp#include <sys/errno.h> 44191762Simp 45191762Simp#include <machine/bus.h> 46191762Simp#include <machine/resource.h> 47191762Simp#include <sys/bus.h> 48191762Simp#include <sys/rman.h> 49191762Simp 50191762Simp#include <sys/socket.h> 51191762Simp 52191762Simp#include <net/if.h> 53191762Simp#include <net/if_media.h> 54191762Simp#include <net/if_arp.h> 55191762Simp 56191762Simp#include <net80211/ieee80211_var.h> 57191762Simp#include <net80211/ieee80211_radiotap.h> 58191762Simp#include <net80211/ieee80211_amrr.h> 59191762Simp 60191762Simp#include <dev/pci/pcivar.h> 61191762Simp#include <dev/pci/pcireg.h> 62191762Simp 63191762Simp#include <dev/bwi/if_bwivar.h> 64191762Simp#include <dev/bwi/if_bwireg.h> 65191762Simp#include <dev/bwi/bitops.h> 66191762Simp 67191762Simp/* 68191762Simp * PCI glue. 69191762Simp */ 70191762Simp 71191762Simpstruct bwi_pci_softc { 72191762Simp struct bwi_softc sc_sc; 73191762Simp}; 74191762Simp 75191762Simp#define BS_BAR 0x10 76191762Simp#define PCIR_RETRY_TIMEOUT 0x41 77191762Simp 78191762Simpstatic const struct bwi_dev { 79191762Simp uint16_t vid; 80191762Simp uint16_t did; 81191762Simp const char *desc; 82191762Simp} bwi_devices[] = { 83192277Simp { PCI_VENDOR_BROADCOM, 0x4301,"Broadcom BCM4301 802.11b Wireless Lan" }, 84192277Simp { PCI_VENDOR_BROADCOM, 0x4307,"Broadcom BCM4307 802.11b Wireless Lan" }, 85192277Simp { PCI_VENDOR_BROADCOM, 0x4311,"Broadcom BCM4311 802.11b/g Wireless Lan" }, 86192277Simp { PCI_VENDOR_BROADCOM, 0x4312,"Broadcom BCM4312 802.11a/b/g Wireless Lan" }, 87192277Simp { PCI_VENDOR_BROADCOM, 0x4313,"Broadcom BCM4312 802.11a Wireless Lan" }, 88192277Simp { PCI_VENDOR_BROADCOM, 0x4320,"Broadcom BCM4306 802.11b/g Wireless Lan"}, 89192277Simp { PCI_VENDOR_BROADCOM, 0x4321,"Broadcom BCM4306 802.11a Wireless Lan"}, 90192277Simp { PCI_VENDOR_BROADCOM, 0x4325,"Broadcom BCM4306 802.11b/g Wireless Lan"}, 91192277Simp { PCI_VENDOR_BROADCOM, 0x4324,"Broadcom BCM4309 802.11a/b/g Wireless Lan" }, 92192277Simp { PCI_VENDOR_BROADCOM, 0x4318,"Broadcom BCM4318 802.11b/g Wireless Lan" }, 93192277Simp { PCI_VENDOR_BROADCOM, 0x4319,"Broadcom BCM4318 802.11a/b/g Wireless Lan" }, 94209892Sweongyo { PCI_VENDOR_BROADCOM, 0x431a,"Broadcom BCM4318 802.11a Wireless Lan" }, 95209892Sweongyo { 0, 0, NULL } 96191762Simp}; 97191762Simp 98191762Simpstatic int 99191762Simpbwi_pci_probe(device_t dev) 100191762Simp{ 101191762Simp const struct bwi_dev *b; 102191762Simp uint16_t did, vid; 103191762Simp 104191762Simp did = pci_get_device(dev); 105191762Simp vid = pci_get_vendor(dev); 106191762Simp 107191762Simp for (b = bwi_devices; b->desc != NULL; ++b) { 108191762Simp if (b->did == did && b->vid == vid) { 109191762Simp device_set_desc(dev, b->desc); 110191762Simp return BUS_PROBE_DEFAULT; 111191762Simp } 112191762Simp } 113191762Simp return ENXIO; 114191762Simp} 115191762Simp 116191762Simpstatic int 117191762Simpbwi_pci_attach(device_t dev) 118191762Simp{ 119191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 120191762Simp struct bwi_softc *sc = &psc->sc_sc; 121191762Simp int error = ENXIO; 122191762Simp 123191762Simp sc->sc_dev = dev; 124191762Simp 125191762Simp /* 126191762Simp * Enable bus mastering. 127191762Simp */ 128191762Simp pci_enable_busmaster(dev); 129191762Simp 130191762Simp /* 131191762Simp * Setup memory-mapping of PCI registers. 132191762Simp */ 133191762Simp sc->sc_mem_rid = BWI_PCIR_BAR; 134191762Simp sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 135191762Simp &sc->sc_mem_rid, RF_ACTIVE); 136191762Simp if (sc->sc_mem_res == NULL) { 137191762Simp device_printf(dev, "cannot map register space\n"); 138191762Simp goto bad; 139191762Simp } 140191762Simp sc->sc_mem_bt = rman_get_bustag(sc->sc_mem_res); 141191762Simp sc->sc_mem_bh = rman_get_bushandle(sc->sc_mem_res); 142191762Simp /* 143191762Simp * Mark device invalid so any interrupts (shared or otherwise) 144191762Simp * that arrive before the card is setup are discarded. 145191762Simp */ 146191762Simp sc->sc_invalid = 1; 147191762Simp 148191762Simp /* 149191762Simp * Arrange interrupt line. 150191762Simp */ 151191762Simp sc->sc_irq_rid = 0; 152191762Simp sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 153191762Simp &sc->sc_irq_rid, 154191762Simp RF_SHAREABLE|RF_ACTIVE); 155191762Simp if (sc->sc_irq_res == NULL) { 156191762Simp device_printf(dev, "could not map interrupt\n"); 157191762Simp goto bad1; 158191762Simp } 159191762Simp if (bus_setup_intr(dev, sc->sc_irq_res, 160191762Simp INTR_TYPE_NET | INTR_MPSAFE, 161191762Simp NULL, bwi_intr, sc, &sc->sc_irq_handle)) { 162191762Simp device_printf(dev, "could not establish interrupt\n"); 163191762Simp goto bad2; 164191762Simp } 165191762Simp 166191762Simp /* Get more PCI information */ 167191762Simp sc->sc_pci_did = pci_get_device(dev); 168191762Simp sc->sc_pci_revid = pci_get_revid(dev); 169191762Simp sc->sc_pci_subvid = pci_get_subvendor(dev); 170191762Simp sc->sc_pci_subdid = pci_get_subdevice(dev); 171191762Simp 172191762Simp error = bwi_attach(sc); 173191762Simp if (error == 0) /* success */ 174191762Simp return 0; 175191762Simp 176191762Simp bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 177191762Simpbad2: 178191762Simp bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 179191762Simpbad1: 180191762Simp bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_mem_res); 181191762Simpbad: 182191762Simp return (error); 183191762Simp} 184191762Simp 185191762Simpstatic int 186191762Simpbwi_pci_detach(device_t dev) 187191762Simp{ 188191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 189191762Simp struct bwi_softc *sc = &psc->sc_sc; 190191762Simp 191191762Simp /* check if device was removed */ 192191762Simp sc->sc_invalid = !bus_child_present(dev); 193191762Simp 194191762Simp bwi_detach(sc); 195191762Simp 196191762Simp bus_generic_detach(dev); 197191762Simp bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 198191762Simp bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 199191762Simp 200191762Simp bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_mem_res); 201191762Simp 202191762Simp return (0); 203191762Simp} 204191762Simp 205191762Simpstatic int 206191762Simpbwi_pci_shutdown(device_t dev) 207191762Simp{ 208191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 209191762Simp 210191762Simp bwi_shutdown(&psc->sc_sc); 211191762Simp return (0); 212191762Simp} 213191762Simp 214191762Simpstatic int 215191762Simpbwi_pci_suspend(device_t dev) 216191762Simp{ 217191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 218191762Simp 219191762Simp bwi_suspend(&psc->sc_sc); 220191762Simp 221191762Simp return (0); 222191762Simp} 223191762Simp 224191762Simpstatic int 225191762Simpbwi_pci_resume(device_t dev) 226191762Simp{ 227191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 228191762Simp 229191762Simp bwi_resume(&psc->sc_sc); 230191762Simp 231191762Simp return (0); 232191762Simp} 233191762Simp 234191762Simpstatic device_method_t bwi_pci_methods[] = { 235191762Simp /* Device interface */ 236191762Simp DEVMETHOD(device_probe, bwi_pci_probe), 237191762Simp DEVMETHOD(device_attach, bwi_pci_attach), 238191762Simp DEVMETHOD(device_detach, bwi_pci_detach), 239191762Simp DEVMETHOD(device_shutdown, bwi_pci_shutdown), 240191762Simp DEVMETHOD(device_suspend, bwi_pci_suspend), 241191762Simp DEVMETHOD(device_resume, bwi_pci_resume), 242191762Simp 243191762Simp { 0,0 } 244191762Simp}; 245191762Simpstatic driver_t bwi_driver = { 246191762Simp "bwi", 247191762Simp bwi_pci_methods, 248191762Simp sizeof (struct bwi_pci_softc) 249191762Simp}; 250191762Simpstatic devclass_t bwi_devclass; 251192146SimpDRIVER_MODULE(bwi, pci, bwi_driver, bwi_devclass, 0, 0); 252192146SimpMODULE_DEPEND(bwi, wlan, 1, 1, 1); /* 802.11 media layer */ 253192146SimpMODULE_DEPEND(bwi, firmware, 1, 1, 1); /* firmware support */ 254192146SimpMODULE_DEPEND(bwi, wlan_amrr, 1, 1, 1); 255