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 37235338Sadrian#include "opt_wlan.h" 38235338Sadrian 39191762Simp#include <sys/param.h> 40191762Simp#include <sys/systm.h> 41191762Simp#include <sys/module.h> 42191762Simp#include <sys/kernel.h> 43191762Simp#include <sys/lock.h> 44191762Simp#include <sys/mutex.h> 45191762Simp#include <sys/errno.h> 46191762Simp 47191762Simp#include <machine/bus.h> 48191762Simp#include <machine/resource.h> 49191762Simp#include <sys/bus.h> 50191762Simp#include <sys/rman.h> 51191762Simp 52191762Simp#include <sys/socket.h> 53191762Simp 54191762Simp#include <net/if.h> 55191762Simp#include <net/if_media.h> 56191762Simp#include <net/if_arp.h> 57191762Simp 58191762Simp#include <net80211/ieee80211_var.h> 59191762Simp#include <net80211/ieee80211_radiotap.h> 60191762Simp#include <net80211/ieee80211_amrr.h> 61191762Simp 62191762Simp#include <dev/pci/pcivar.h> 63191762Simp#include <dev/pci/pcireg.h> 64191762Simp 65191762Simp#include <dev/bwi/if_bwivar.h> 66191762Simp#include <dev/bwi/if_bwireg.h> 67191762Simp#include <dev/bwi/bitops.h> 68191762Simp 69191762Simp/* 70191762Simp * PCI glue. 71191762Simp */ 72191762Simp 73191762Simpstruct bwi_pci_softc { 74191762Simp struct bwi_softc sc_sc; 75191762Simp}; 76191762Simp 77191762Simp#define BS_BAR 0x10 78191762Simp#define PCIR_RETRY_TIMEOUT 0x41 79191762Simp 80191762Simpstatic const struct bwi_dev { 81191762Simp uint16_t vid; 82191762Simp uint16_t did; 83191762Simp const char *desc; 84191762Simp} bwi_devices[] = { 85192277Simp { PCI_VENDOR_BROADCOM, 0x4301,"Broadcom BCM4301 802.11b Wireless Lan" }, 86192277Simp { PCI_VENDOR_BROADCOM, 0x4307,"Broadcom BCM4307 802.11b Wireless Lan" }, 87192277Simp { PCI_VENDOR_BROADCOM, 0x4311,"Broadcom BCM4311 802.11b/g Wireless Lan" }, 88192277Simp { PCI_VENDOR_BROADCOM, 0x4312,"Broadcom BCM4312 802.11a/b/g Wireless Lan" }, 89192277Simp { PCI_VENDOR_BROADCOM, 0x4313,"Broadcom BCM4312 802.11a Wireless Lan" }, 90192277Simp { PCI_VENDOR_BROADCOM, 0x4320,"Broadcom BCM4306 802.11b/g Wireless Lan"}, 91192277Simp { PCI_VENDOR_BROADCOM, 0x4321,"Broadcom BCM4306 802.11a Wireless Lan"}, 92192277Simp { PCI_VENDOR_BROADCOM, 0x4325,"Broadcom BCM4306 802.11b/g Wireless Lan"}, 93192277Simp { PCI_VENDOR_BROADCOM, 0x4324,"Broadcom BCM4309 802.11a/b/g Wireless Lan" }, 94192277Simp { PCI_VENDOR_BROADCOM, 0x4318,"Broadcom BCM4318 802.11b/g Wireless Lan" }, 95192277Simp { PCI_VENDOR_BROADCOM, 0x4319,"Broadcom BCM4318 802.11a/b/g Wireless Lan" }, 96209892Sweongyo { PCI_VENDOR_BROADCOM, 0x431a,"Broadcom BCM4318 802.11a Wireless Lan" }, 97209892Sweongyo { 0, 0, NULL } 98191762Simp}; 99191762Simp 100191762Simpstatic int 101191762Simpbwi_pci_probe(device_t dev) 102191762Simp{ 103191762Simp const struct bwi_dev *b; 104191762Simp uint16_t did, vid; 105191762Simp 106191762Simp did = pci_get_device(dev); 107191762Simp vid = pci_get_vendor(dev); 108191762Simp 109191762Simp for (b = bwi_devices; b->desc != NULL; ++b) { 110191762Simp if (b->did == did && b->vid == vid) { 111191762Simp device_set_desc(dev, b->desc); 112191762Simp return BUS_PROBE_DEFAULT; 113191762Simp } 114191762Simp } 115191762Simp return ENXIO; 116191762Simp} 117191762Simp 118191762Simpstatic int 119191762Simpbwi_pci_attach(device_t dev) 120191762Simp{ 121191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 122191762Simp struct bwi_softc *sc = &psc->sc_sc; 123191762Simp int error = ENXIO; 124191762Simp 125191762Simp sc->sc_dev = dev; 126191762Simp 127191762Simp /* 128191762Simp * Enable bus mastering. 129191762Simp */ 130191762Simp pci_enable_busmaster(dev); 131191762Simp 132191762Simp /* 133191762Simp * Setup memory-mapping of PCI registers. 134191762Simp */ 135191762Simp sc->sc_mem_rid = BWI_PCIR_BAR; 136191762Simp sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 137191762Simp &sc->sc_mem_rid, RF_ACTIVE); 138191762Simp if (sc->sc_mem_res == NULL) { 139191762Simp device_printf(dev, "cannot map register space\n"); 140191762Simp goto bad; 141191762Simp } 142191762Simp sc->sc_mem_bt = rman_get_bustag(sc->sc_mem_res); 143191762Simp sc->sc_mem_bh = rman_get_bushandle(sc->sc_mem_res); 144191762Simp /* 145191762Simp * Mark device invalid so any interrupts (shared or otherwise) 146191762Simp * that arrive before the card is setup are discarded. 147191762Simp */ 148191762Simp sc->sc_invalid = 1; 149191762Simp 150191762Simp /* 151191762Simp * Arrange interrupt line. 152191762Simp */ 153191762Simp sc->sc_irq_rid = 0; 154191762Simp sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 155191762Simp &sc->sc_irq_rid, 156191762Simp RF_SHAREABLE|RF_ACTIVE); 157191762Simp if (sc->sc_irq_res == NULL) { 158191762Simp device_printf(dev, "could not map interrupt\n"); 159191762Simp goto bad1; 160191762Simp } 161191762Simp if (bus_setup_intr(dev, sc->sc_irq_res, 162191762Simp INTR_TYPE_NET | INTR_MPSAFE, 163191762Simp NULL, bwi_intr, sc, &sc->sc_irq_handle)) { 164191762Simp device_printf(dev, "could not establish interrupt\n"); 165191762Simp goto bad2; 166191762Simp } 167191762Simp 168191762Simp /* Get more PCI information */ 169191762Simp sc->sc_pci_did = pci_get_device(dev); 170191762Simp sc->sc_pci_revid = pci_get_revid(dev); 171191762Simp sc->sc_pci_subvid = pci_get_subvendor(dev); 172191762Simp sc->sc_pci_subdid = pci_get_subdevice(dev); 173191762Simp 174191762Simp error = bwi_attach(sc); 175191762Simp if (error == 0) /* success */ 176191762Simp return 0; 177191762Simp 178191762Simp bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 179191762Simpbad2: 180191762Simp bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 181191762Simpbad1: 182191762Simp bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_mem_res); 183191762Simpbad: 184191762Simp return (error); 185191762Simp} 186191762Simp 187191762Simpstatic int 188191762Simpbwi_pci_detach(device_t dev) 189191762Simp{ 190191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 191191762Simp struct bwi_softc *sc = &psc->sc_sc; 192191762Simp 193191762Simp /* check if device was removed */ 194191762Simp sc->sc_invalid = !bus_child_present(dev); 195191762Simp 196191762Simp bwi_detach(sc); 197191762Simp 198191762Simp bus_generic_detach(dev); 199191762Simp bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_handle); 200191762Simp bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 201191762Simp 202191762Simp bus_release_resource(dev, SYS_RES_MEMORY, BS_BAR, sc->sc_mem_res); 203191762Simp 204191762Simp return (0); 205191762Simp} 206191762Simp 207191762Simpstatic int 208191762Simpbwi_pci_shutdown(device_t dev) 209191762Simp{ 210191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 211191762Simp 212191762Simp bwi_shutdown(&psc->sc_sc); 213191762Simp return (0); 214191762Simp} 215191762Simp 216191762Simpstatic int 217191762Simpbwi_pci_suspend(device_t dev) 218191762Simp{ 219191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 220191762Simp 221191762Simp bwi_suspend(&psc->sc_sc); 222191762Simp 223191762Simp return (0); 224191762Simp} 225191762Simp 226191762Simpstatic int 227191762Simpbwi_pci_resume(device_t dev) 228191762Simp{ 229191762Simp struct bwi_pci_softc *psc = device_get_softc(dev); 230191762Simp 231191762Simp bwi_resume(&psc->sc_sc); 232191762Simp 233191762Simp return (0); 234191762Simp} 235191762Simp 236191762Simpstatic device_method_t bwi_pci_methods[] = { 237191762Simp /* Device interface */ 238191762Simp DEVMETHOD(device_probe, bwi_pci_probe), 239191762Simp DEVMETHOD(device_attach, bwi_pci_attach), 240191762Simp DEVMETHOD(device_detach, bwi_pci_detach), 241191762Simp DEVMETHOD(device_shutdown, bwi_pci_shutdown), 242191762Simp DEVMETHOD(device_suspend, bwi_pci_suspend), 243191762Simp DEVMETHOD(device_resume, bwi_pci_resume), 244191762Simp 245191762Simp { 0,0 } 246191762Simp}; 247191762Simpstatic driver_t bwi_driver = { 248191762Simp "bwi", 249191762Simp bwi_pci_methods, 250191762Simp sizeof (struct bwi_pci_softc) 251191762Simp}; 252191762Simpstatic devclass_t bwi_devclass; 253192146SimpDRIVER_MODULE(bwi, pci, bwi_driver, bwi_devclass, 0, 0); 254192146SimpMODULE_DEPEND(bwi, wlan, 1, 1, 1); /* 802.11 media layer */ 255192146SimpMODULE_DEPEND(bwi, firmware, 1, 1, 1); /* firmware support */ 256192146SimpMODULE_DEPEND(bwi, wlan_amrr, 1, 1, 1); 257