1 /* $OpenBSD: if_bwi_cardbus.c,v 1.9 2009/03/29 21:53:52 sthen Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Marcus Glocker <mglocker@openbsd.org> 5 * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* 21 * Cardbus front-end for the Broadcom AirForce 22 */ 23 24 #include "bpfilter.h" 25 26 #include <sys/param.h> 27 #include <sys/mbuf.h> 28 #include <sys/socket.h> 29 #include <sys/systm.h> 30 #include <sys/timeout.h> 31 32 #include <net/if.h> 33 #include <net/if_media.h> 34 35 #include <netinet/in.h> 36 #include <netinet/if_ether.h> 37 38 #include <net80211/ieee80211_var.h> 39 #include <net80211/ieee80211_amrr.h> 40 #include <net80211/ieee80211_radiotap.h> 41 42 #include <dev/pci/pcireg.h> 43 #include <dev/pci/pcivar.h> 44 #include <dev/pci/pcidevs.h> 45 46 #include <dev/cardbus/cardbusvar.h> 47 48 #include <dev/ic/bwivar.h> 49 50 struct bwi_cardbus_softc { 51 struct bwi_softc csc_bwi; 52 53 /* cardbus specific goo */ 54 cardbus_devfunc_t csc_ct; 55 cardbustag_t csc_tag; 56 void *csc_ih; 57 58 bus_size_t csc_mapsize; 59 pcireg_t csc_bar_val; 60 int csc_intrline; 61 }; 62 63 int bwi_cardbus_match(struct device *, void *, void*); 64 void bwi_cardbus_attach(struct device *, struct device *, void *); 65 int bwi_cardbus_detach(struct device *, int); 66 void bwi_cardbus_setup(struct bwi_cardbus_softc *); 67 int bwi_cardbus_enable(struct bwi_softc *); 68 void bwi_cardbus_disable(struct bwi_softc *); 69 void bwi_cardbus_conf_write(void *, uint32_t, uint32_t); 70 uint32_t bwi_cardbus_conf_read(void *, uint32_t); 71 72 struct cfattach bwi_cardbus_ca = { 73 sizeof (struct bwi_cardbus_softc), bwi_cardbus_match, 74 bwi_cardbus_attach, bwi_cardbus_detach 75 }; 76 77 static const struct cardbus_matchid bwi_cardbus_devices[] = { 78 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4303 }, 79 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306 }, 80 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4306_2 }, 81 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4307 }, 82 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4309 }, 83 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4318 }, 84 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM4319 }, 85 { PCI_VENDOR_BROADCOM, PCI_PRODUCT_BROADCOM_BCM43XG } 86 }; 87 88 int 89 bwi_cardbus_match(struct device *parent, void *match, void *aux) 90 { 91 return (cardbus_matchbyid(aux, bwi_cardbus_devices, 92 sizeof (bwi_cardbus_devices) / sizeof (bwi_cardbus_devices[0]))); 93 } 94 95 void 96 bwi_cardbus_attach(struct device *parent, struct device *self, void *aux) 97 { 98 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 99 struct cardbus_attach_args *ca = aux; 100 struct bwi_softc *sc = &csc->csc_bwi; 101 cardbus_devfunc_t ct = ca->ca_ct; 102 cardbusreg_t reg; 103 bus_addr_t base; 104 int error; 105 106 sc->sc_dmat = ca->ca_dmat; 107 csc->csc_ct = ct; 108 csc->csc_tag = ca->ca_tag; 109 csc->csc_intrline = ca->ca_intrline; 110 111 /* power management hooks */ 112 sc->sc_enable = bwi_cardbus_enable; 113 sc->sc_disable = bwi_cardbus_disable; 114 //sc->sc_power = bwi_cardbus_power; 115 116 /* map control/status registers */ 117 error = Cardbus_mapreg_map(ct, CARDBUS_BASE0_REG, 118 CARDBUS_MAPREG_TYPE_MEM, 0, &sc->sc_mem_bt, 119 &sc->sc_mem_bh, &base, &csc->csc_mapsize); 120 if (error != 0) { 121 printf(": can't map mem space\n"); 122 return; 123 } 124 csc->csc_bar_val = base | CARDBUS_MAPREG_TYPE_MEM; 125 126 /* set up the PCI configuration registers */ 127 bwi_cardbus_setup(csc); 128 129 printf(": irq %d", csc->csc_intrline); 130 131 /* we need to access Cardbus config space from the driver */ 132 sc->sc_conf_read = bwi_cardbus_conf_read; 133 sc->sc_conf_write = bwi_cardbus_conf_write; 134 135 reg = (sc->sc_conf_read)(sc, PCI_SUBSYS_ID_REG); 136 137 sc->sc_pci_revid = PCI_REVISION(ca->ca_class); 138 sc->sc_pci_did = PCI_PRODUCT(ca->ca_id); 139 sc->sc_pci_subvid = PCI_VENDOR(reg); 140 sc->sc_pci_subdid = PCI_PRODUCT(reg); 141 142 error = bwi_attach(sc); 143 if (error != 0) 144 bwi_cardbus_detach(&sc->sc_dev, 0); 145 146 Cardbus_function_disable(ct); 147 } 148 149 int 150 bwi_cardbus_detach(struct device *self, int flags) 151 { 152 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 153 struct bwi_softc *sc = &csc->csc_bwi; 154 cardbus_devfunc_t ct = csc->csc_ct; 155 cardbus_chipset_tag_t cc = ct->ct_cc; 156 cardbus_function_tag_t cf = ct->ct_cf; 157 int error; 158 159 error = bwi_detach(sc); 160 if (error != 0) 161 return (error); 162 163 /* unhook the interrupt handler */ 164 if (csc->csc_ih != NULL) { 165 cardbus_intr_disestablish(cc, cf, csc->csc_ih); 166 csc->csc_ih = NULL; 167 } 168 169 /* release bus space and close window */ 170 Cardbus_mapreg_unmap(ct, CARDBUS_BASE0_REG, sc->sc_mem_bt, 171 sc->sc_mem_bh, csc->csc_mapsize); 172 173 return (0); 174 } 175 176 void 177 bwi_cardbus_setup(struct bwi_cardbus_softc *csc) 178 { 179 cardbus_devfunc_t ct = csc->csc_ct; 180 cardbus_chipset_tag_t cc = ct->ct_cc; 181 cardbus_function_tag_t cf = ct->ct_cf; 182 pcireg_t reg; 183 184 /* program the BAR */ 185 cardbus_conf_write(cc, cf, csc->csc_tag, CARDBUS_BASE0_REG, 186 csc->csc_bar_val); 187 188 /* make sure the right access type is on the cardbus bridge */ 189 (*cf->cardbus_ctrl)(cc, CARDBUS_MEM_ENABLE); 190 (*cf->cardbus_ctrl)(cc, CARDBUS_BM_ENABLE); 191 192 /* enable the appropriate bits in the PCI CSR */ 193 reg = cardbus_conf_read(cc, cf, csc->csc_tag, 194 CARDBUS_COMMAND_STATUS_REG); 195 reg |= CARDBUS_COMMAND_MASTER_ENABLE | CARDBUS_COMMAND_MEM_ENABLE; 196 cardbus_conf_write(cc, cf, csc->csc_tag, CARDBUS_COMMAND_STATUS_REG, 197 reg); 198 } 199 200 int 201 bwi_cardbus_enable(struct bwi_softc *sc) 202 { 203 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc; 204 cardbus_devfunc_t ct = csc->csc_ct; 205 cardbus_chipset_tag_t cc = ct->ct_cc; 206 cardbus_function_tag_t cf = ct->ct_cf; 207 208 /* power on the socket */ 209 Cardbus_function_enable(ct); 210 211 /* setup the PCI configuration registers */ 212 bwi_cardbus_setup(csc); 213 214 /* map and establish the interrupt handler */ 215 csc->csc_ih = cardbus_intr_establish(cc, cf, csc->csc_intrline, IPL_NET, 216 bwi_intr, sc, sc->sc_dev.dv_xname); 217 if (csc->csc_ih == NULL) { 218 printf("%s: could not establish interrupt at %d\n", 219 sc->sc_dev.dv_xname, csc->csc_intrline); 220 Cardbus_function_disable(ct); 221 return (1); 222 } 223 224 return (0); 225 } 226 227 void 228 bwi_cardbus_disable(struct bwi_softc *sc) 229 { 230 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)sc; 231 cardbus_devfunc_t ct = csc->csc_ct; 232 cardbus_chipset_tag_t cc = ct->ct_cc; 233 cardbus_function_tag_t cf = ct->ct_cf; 234 235 /* unhook the interrupt handler */ 236 cardbus_intr_disestablish(cc, cf, csc->csc_ih); 237 csc->csc_ih = NULL; 238 239 /* power down the socket */ 240 Cardbus_function_disable(ct); 241 } 242 243 void 244 bwi_cardbus_conf_write(void *self, uint32_t reg, uint32_t val) 245 { 246 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 247 cardbus_devfunc_t ct = csc->csc_ct; 248 cardbus_chipset_tag_t cc = ct->ct_cc; 249 cardbus_function_tag_t cf = ct->ct_cf; 250 251 cardbus_conf_write(cc, cf, csc->csc_tag, reg, val); 252 } 253 254 uint32_t 255 bwi_cardbus_conf_read(void *self, uint32_t reg) 256 { 257 struct bwi_cardbus_softc *csc = (struct bwi_cardbus_softc *)self; 258 cardbus_devfunc_t ct = csc->csc_ct; 259 cardbus_chipset_tag_t cc = ct->ct_cc; 260 cardbus_function_tag_t cf = ct->ct_cf; 261 262 return (cardbus_conf_read(cc, cf, csc->csc_tag, reg)); 263 } 264