1 1.26 thorpej /* $NetBSD: if_ral_cardbus.c,v 1.26 2022/09/25 17:33:19 thorpej Exp $ */ 2 1.5 rpaulo /* $OpenBSD: if_ral_cardbus.c,v 1.6 2006/01/09 20:03:31 damien Exp $ */ 3 1.1 drochner 4 1.1 drochner /*- 5 1.5 rpaulo * Copyright (c) 2005, 2006 6 1.1 drochner * Damien Bergamini <damien.bergamini (at) free.fr> 7 1.1 drochner * 8 1.1 drochner * Permission to use, copy, modify, and distribute this software for any 9 1.1 drochner * purpose with or without fee is hereby granted, provided that the above 10 1.1 drochner * copyright notice and this permission notice appear in all copies. 11 1.1 drochner * 12 1.1 drochner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 1.1 drochner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 1.1 drochner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 1.1 drochner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 1.1 drochner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 1.1 drochner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 1.1 drochner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 1.1 drochner */ 20 1.1 drochner 21 1.1 drochner /* 22 1.5 rpaulo * CardBus front-end for the Ralink RT2560/RT2561/RT2561S/RT2661 driver. 23 1.1 drochner */ 24 1.1 drochner #include <sys/cdefs.h> 25 1.26 thorpej __KERNEL_RCSID(0, "$NetBSD: if_ral_cardbus.c,v 1.26 2022/09/25 17:33:19 thorpej Exp $"); 26 1.1 drochner 27 1.1 drochner 28 1.1 drochner #include <sys/param.h> 29 1.1 drochner #include <sys/sockio.h> 30 1.1 drochner #include <sys/mbuf.h> 31 1.1 drochner #include <sys/kernel.h> 32 1.1 drochner #include <sys/socket.h> 33 1.1 drochner #include <sys/systm.h> 34 1.5 rpaulo #include <sys/callout.h> 35 1.1 drochner #include <sys/device.h> 36 1.1 drochner 37 1.9 ad #include <sys/bus.h> 38 1.9 ad #include <sys/intr.h> 39 1.1 drochner 40 1.1 drochner #include <net/if.h> 41 1.1 drochner #include <net/if_dl.h> 42 1.5 rpaulo #include <net/if_media.h> 43 1.1 drochner #include <net/if_ether.h> 44 1.1 drochner 45 1.1 drochner #include <netinet/in.h> 46 1.1 drochner 47 1.1 drochner #include <net80211/ieee80211_var.h> 48 1.12 scw #include <net80211/ieee80211_amrr.h> 49 1.1 drochner #include <net80211/ieee80211_rssadapt.h> 50 1.1 drochner #include <net80211/ieee80211_radiotap.h> 51 1.1 drochner 52 1.5 rpaulo #include <dev/ic/rt2560var.h> 53 1.5 rpaulo #include <dev/ic/rt2661var.h> 54 1.1 drochner 55 1.1 drochner #include <dev/pci/pcireg.h> 56 1.1 drochner #include <dev/pci/pcivar.h> 57 1.1 drochner #include <dev/pci/pcidevs.h> 58 1.1 drochner 59 1.1 drochner #include <dev/cardbus/cardbusvar.h> 60 1.1 drochner 61 1.5 rpaulo static struct ral_opns { 62 1.5 rpaulo int (*attach)(void *, int); 63 1.5 rpaulo int (*detach)(void *); 64 1.5 rpaulo int (*intr)(void *); 65 1.5 rpaulo 66 1.5 rpaulo } ral_rt2560_opns = { 67 1.5 rpaulo rt2560_attach, 68 1.5 rpaulo rt2560_detach, 69 1.5 rpaulo rt2560_intr 70 1.5 rpaulo 71 1.5 rpaulo }, ral_rt2661_opns = { 72 1.5 rpaulo rt2661_attach, 73 1.5 rpaulo rt2661_detach, 74 1.5 rpaulo rt2661_intr 75 1.5 rpaulo }; 76 1.5 rpaulo 77 1.1 drochner struct ral_cardbus_softc { 78 1.5 rpaulo union { 79 1.5 rpaulo struct rt2560_softc sc_rt2560; 80 1.5 rpaulo struct rt2661_softc sc_rt2661; 81 1.5 rpaulo } u; 82 1.5 rpaulo #define sc_sc u.sc_rt2560 83 1.1 drochner 84 1.1 drochner /* cardbus specific goo */ 85 1.5 rpaulo struct ral_opns *sc_opns; 86 1.1 drochner cardbus_devfunc_t sc_ct; 87 1.18 dyoung pcitag_t sc_tag; 88 1.1 drochner void *sc_ih; 89 1.1 drochner bus_size_t sc_mapsize; 90 1.1 drochner pcireg_t sc_bar_val; 91 1.1 drochner }; 92 1.1 drochner 93 1.16 cegger int ral_cardbus_match(device_t, cfdata_t, void *); 94 1.16 cegger void ral_cardbus_attach(device_t, device_t, void *); 95 1.16 cegger int ral_cardbus_detach(device_t, int); 96 1.1 drochner 97 1.23 drochner CFATTACH_DECL_NEW(ral_cardbus, sizeof (struct ral_cardbus_softc), 98 1.1 drochner ral_cardbus_match, ral_cardbus_attach, ral_cardbus_detach, NULL); 99 1.1 drochner 100 1.5 rpaulo int ral_cardbus_enable(struct rt2560_softc *); 101 1.5 rpaulo void ral_cardbus_disable(struct rt2560_softc *); 102 1.5 rpaulo void ral_cardbus_power(struct rt2560_softc *, int); 103 1.1 drochner void ral_cardbus_setup(struct ral_cardbus_softc *); 104 1.1 drochner 105 1.1 drochner int 106 1.24 msaitoh ral_cardbus_match(device_t parent, cfdata_t cfdata, void *aux) 107 1.1 drochner { 108 1.25 jakllsch struct cardbus_attach_args *ca = aux; 109 1.1 drochner 110 1.25 jakllsch if (PCI_VENDOR(ca->ca_id) == PCI_VENDOR_RALINK) { 111 1.25 jakllsch switch (PCI_PRODUCT(ca->ca_id)) { 112 1.5 rpaulo case PCI_PRODUCT_RALINK_RT2560: 113 1.5 rpaulo case PCI_PRODUCT_RALINK_RT2561: 114 1.5 rpaulo case PCI_PRODUCT_RALINK_RT2561S: 115 1.5 rpaulo case PCI_PRODUCT_RALINK_RT2661: 116 1.5 rpaulo return 1; 117 1.5 rpaulo default: 118 1.5 rpaulo return 0; 119 1.25 jakllsch } 120 1.25 jakllsch } 121 1.1 drochner 122 1.25 jakllsch return 0; 123 1.1 drochner } 124 1.1 drochner 125 1.1 drochner void 126 1.24 msaitoh ral_cardbus_attach(device_t parent, device_t self, void *aux) 127 1.1 drochner { 128 1.23 drochner struct ral_cardbus_softc *csc = device_private(self); 129 1.5 rpaulo struct rt2560_softc *sc = &csc->sc_sc; 130 1.1 drochner struct cardbus_attach_args *ca = aux; 131 1.1 drochner cardbus_devfunc_t ct = ca->ca_ct; 132 1.14 dholland char devinfo[256]; 133 1.1 drochner bus_addr_t base; 134 1.14 dholland int error, revision; 135 1.14 dholland 136 1.14 dholland pci_devinfo(ca->ca_id, ca->ca_class, 0, devinfo, sizeof(devinfo)); 137 1.14 dholland revision = PCI_REVISION(ca->ca_class); 138 1.14 dholland aprint_normal(": %s (rev. 0x%02x)\n", devinfo, revision); 139 1.1 drochner 140 1.5 rpaulo csc->sc_opns = 141 1.20 dyoung (PCI_PRODUCT(ca->ca_id) == PCI_PRODUCT_RALINK_RT2560) ? 142 1.5 rpaulo &ral_rt2560_opns : &ral_rt2661_opns; 143 1.5 rpaulo 144 1.23 drochner sc->sc_dev = self; 145 1.1 drochner sc->sc_dmat = ca->ca_dmat; 146 1.1 drochner csc->sc_ct = ct; 147 1.1 drochner csc->sc_tag = ca->ca_tag; 148 1.1 drochner 149 1.1 drochner /* power management hooks */ 150 1.1 drochner sc->sc_enable = ral_cardbus_enable; 151 1.1 drochner sc->sc_disable = ral_cardbus_disable; 152 1.1 drochner 153 1.1 drochner /* map control/status registers */ 154 1.20 dyoung error = Cardbus_mapreg_map(ct, PCI_BAR0, 155 1.20 dyoung PCI_MAPREG_TYPE_MEM, 0, &sc->sc_st, &sc->sc_sh, &base, 156 1.1 drochner &csc->sc_mapsize); 157 1.1 drochner if (error != 0) { 158 1.24 msaitoh aprint_error(": could not map memory space\n"); 159 1.1 drochner return; 160 1.1 drochner } 161 1.1 drochner 162 1.20 dyoung csc->sc_bar_val = base | PCI_MAPREG_TYPE_MEM; 163 1.1 drochner 164 1.1 drochner /* set up the PCI configuration registers */ 165 1.1 drochner ral_cardbus_setup(csc); 166 1.1 drochner 167 1.20 dyoung (*csc->sc_opns->attach)(sc, PCI_PRODUCT(ca->ca_id)); 168 1.1 drochner 169 1.1 drochner Cardbus_function_disable(ct); 170 1.1 drochner } 171 1.1 drochner 172 1.1 drochner int 173 1.16 cegger ral_cardbus_detach(device_t self, int flags) 174 1.1 drochner { 175 1.23 drochner struct ral_cardbus_softc *csc = device_private(self); 176 1.5 rpaulo struct rt2560_softc *sc = &csc->sc_sc; 177 1.1 drochner cardbus_devfunc_t ct = csc->sc_ct; 178 1.1 drochner int error; 179 1.1 drochner 180 1.5 rpaulo error = (*csc->sc_opns->detach)(sc); 181 1.1 drochner if (error != 0) 182 1.1 drochner return error; 183 1.1 drochner 184 1.1 drochner /* unhook the interrupt handler */ 185 1.1 drochner if (csc->sc_ih != NULL) { 186 1.21 dyoung Cardbus_intr_disestablish(ct, csc->sc_ih); 187 1.1 drochner csc->sc_ih = NULL; 188 1.1 drochner } 189 1.1 drochner 190 1.1 drochner /* release bus space and close window */ 191 1.20 dyoung Cardbus_mapreg_unmap(ct, PCI_BAR0, sc->sc_st, sc->sc_sh, 192 1.1 drochner csc->sc_mapsize); 193 1.1 drochner 194 1.1 drochner return 0; 195 1.1 drochner } 196 1.1 drochner 197 1.1 drochner int 198 1.5 rpaulo ral_cardbus_enable(struct rt2560_softc *sc) 199 1.1 drochner { 200 1.1 drochner struct ral_cardbus_softc *csc = (struct ral_cardbus_softc *)sc; 201 1.1 drochner cardbus_devfunc_t ct = csc->sc_ct; 202 1.1 drochner 203 1.1 drochner /* power on the socket */ 204 1.1 drochner Cardbus_function_enable(ct); 205 1.1 drochner 206 1.1 drochner /* setup the PCI configuration registers */ 207 1.1 drochner ral_cardbus_setup(csc); 208 1.1 drochner 209 1.1 drochner /* map and establish the interrupt handler */ 210 1.22 drochner csc->sc_ih = Cardbus_intr_establish(ct, IPL_NET, 211 1.5 rpaulo csc->sc_opns->intr, sc); 212 1.1 drochner if (csc->sc_ih == NULL) { 213 1.23 drochner aprint_error_dev(sc->sc_dev, 214 1.13 drochner "could not establish interrupt\n"); 215 1.1 drochner Cardbus_function_disable(ct); 216 1.1 drochner return 1; 217 1.1 drochner } 218 1.1 drochner 219 1.1 drochner return 0; 220 1.1 drochner } 221 1.1 drochner 222 1.1 drochner void 223 1.5 rpaulo ral_cardbus_disable(struct rt2560_softc *sc) 224 1.1 drochner { 225 1.1 drochner struct ral_cardbus_softc *csc = (struct ral_cardbus_softc *)sc; 226 1.1 drochner cardbus_devfunc_t ct = csc->sc_ct; 227 1.1 drochner 228 1.1 drochner /* unhook the interrupt handler */ 229 1.21 dyoung Cardbus_intr_disestablish(ct, csc->sc_ih); 230 1.1 drochner csc->sc_ih = NULL; 231 1.1 drochner 232 1.1 drochner /* power down the socket */ 233 1.1 drochner Cardbus_function_disable(ct); 234 1.1 drochner } 235 1.1 drochner 236 1.1 drochner void 237 1.1 drochner ral_cardbus_setup(struct ral_cardbus_softc *csc) 238 1.1 drochner { 239 1.1 drochner cardbus_devfunc_t ct = csc->sc_ct; 240 1.1 drochner pcireg_t reg; 241 1.1 drochner 242 1.1 drochner /* program the BAR */ 243 1.20 dyoung Cardbus_conf_write(ct, csc->sc_tag, PCI_BAR0, csc->sc_bar_val); 244 1.1 drochner 245 1.1 drochner /* enable the appropriate bits in the PCI CSR */ 246 1.20 dyoung reg = Cardbus_conf_read(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG); 247 1.20 dyoung reg |= PCI_COMMAND_MASTER_ENABLE | PCI_COMMAND_MEM_ENABLE; 248 1.20 dyoung Cardbus_conf_write(ct, csc->sc_tag, PCI_COMMAND_STATUS_REG, reg); 249 1.1 drochner } 250