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