1 /* $NetBSD: if_wi_pci.c,v 1.2 2001/11/13 07:48:45 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Hideaki Imaizumi <hiddy@sfc.wide.ad.jp> 9 * and Ichiro FUKUHARA (ichiro@ichiro.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * PCI bus front-end for the Intersil PCI WaveLan. 42 * Works with Prism2.5 Mini-PCI wavelan. 43 */ 44 45 #include <sys/cdefs.h> 46 __KERNEL_RCSID(0, "$NetBSD: if_wi_pci.c,v 1.2 2001/11/13 07:48:45 lukem Exp $"); 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/mbuf.h> 51 #include <sys/syslog.h> 52 #include <sys/socket.h> 53 #include <sys/device.h> 54 #include <sys/callout.h> 55 56 #include <net/if.h> 57 #include <net/if_ether.h> 58 #include <net/if_media.h> 59 #include <net/if_ieee80211.h> 60 61 #include <machine/bus.h> 62 #include <machine/intr.h> 63 64 #include <dev/pci/pcireg.h> 65 #include <dev/pci/pcivar.h> 66 #include <dev/pci/pcidevs.h> 67 68 #include <dev/ic/wi_ieee.h> 69 #include <dev/ic/wireg.h> 70 #include <dev/ic/wivar.h> 71 72 struct wi_pci_softc { 73 struct wi_softc psc_wi; /* real "wi" softc */ 74 75 /* PCI-specific goo */ 76 pci_intr_handle_t psc_ih; 77 struct pci_attach_args *psc_pa; 78 79 void *sc_powerhook; /* power hook descriptor */ 80 }; 81 82 static int wi_pci_match __P((struct device *, struct cfdata *, void *)); 83 static void wi_pci_attach __P((struct device *, struct device *, void *)); 84 static int wi_pci_enable __P((struct wi_softc *)); 85 static void wi_pci_disable __P((struct wi_softc *)); 86 static void wi_pci_powerhook __P((int, void *)); 87 88 static const struct wi_pci_product 89 *wi_pci_lookup __P((struct pci_attach_args *)); 90 91 struct cfattach wi_pci_ca = { 92 sizeof(struct wi_pci_softc), wi_pci_match, wi_pci_attach 93 }; 94 95 const struct wi_pci_product { 96 pci_vendor_id_t wpp_vendor; /* vendor ID */ 97 pci_product_id_t wpp_product; /* product ID */ 98 const char *wpp_name; /* product name */ 99 } wi_pci_products[] = { 100 { PCI_VENDOR_INTERSIL, PCI_PRODUCT_INTERSIL_MINI_PCI_WLAN, 101 "Intersil Prism2.5" }, 102 { 0, 0, 103 NULL}, 104 }; 105 106 static int 107 wi_pci_enable(sc) 108 struct wi_softc *sc; 109 { 110 struct wi_pci_softc *psc = (struct wi_pci_softc *)sc; 111 112 /* establish the interrupt. */ 113 sc->sc_ih = pci_intr_establish(psc->psc_pa->pa_pc, 114 psc->psc_ih, IPL_NET, wi_intr, sc); 115 if (sc->sc_ih == NULL) { 116 printf("%s: couldn't establish interrupt\n", 117 sc->sc_dev.dv_xname); 118 return (EIO); 119 } 120 sc->sc_pci = 1; 121 122 /* reset HFA3842 MAC core */ 123 wi_pci_reset(sc); 124 125 return (0); 126 } 127 128 static void 129 wi_pci_disable(sc) 130 struct wi_softc *sc; 131 { 132 struct wi_pci_softc *psc = (struct wi_pci_softc *)sc; 133 134 pci_intr_disestablish(psc->psc_pa->pa_pc, sc->sc_ih); 135 } 136 137 static const struct wi_pci_product * 138 wi_pci_lookup(pa) 139 struct pci_attach_args *pa; 140 { 141 const struct wi_pci_product *wpp; 142 143 for (wpp = wi_pci_products; wpp->wpp_name != NULL; wpp++) { 144 if (PCI_VENDOR(pa->pa_id) == wpp->wpp_vendor && 145 PCI_PRODUCT(pa->pa_id) == wpp->wpp_product) 146 return (wpp); 147 } 148 return (NULL); 149 } 150 151 static int 152 wi_pci_match(parent, match, aux) 153 struct device *parent; 154 struct cfdata *match; 155 void *aux; 156 { 157 struct pci_attach_args *pa = aux; 158 159 if (wi_pci_lookup(pa) != NULL) 160 return (1); 161 return (0); 162 } 163 164 static void 165 wi_pci_attach(parent, self, aux) 166 struct device *parent, *self; 167 void *aux; 168 { 169 struct wi_pci_softc *psc = (struct wi_pci_softc *)self; 170 struct wi_softc *sc = &psc->psc_wi; 171 struct pci_attach_args *pa = aux; 172 pci_chipset_tag_t pc = pa->pa_pc; 173 const char *intrstr; 174 const struct wi_pci_product *wpp; 175 pci_intr_handle_t ih; 176 bus_space_tag_t memt; 177 bus_space_handle_t memh; 178 int memh_valid; 179 bus_addr_t busbase; 180 bus_size_t bussize; 181 182 psc->psc_pa = pa; 183 184 memh_valid = !pci_mapreg_map(pa, WI_PCI_CBMA, 185 PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, 186 &memt, &memh, &busbase, &bussize); 187 188 if(memh_valid){ 189 sc->sc_iot = memt; 190 sc->sc_ioh = memh; 191 } 192 else { 193 printf(": unable to map device registers\n"); 194 return; 195 } 196 197 wpp = wi_pci_lookup(pa); 198 if (wpp == NULL) { 199 printf("\n"); 200 panic("wi_pci_attach: impossible"); 201 } 202 203 printf(": %s Wireless Lan\n", wpp->wpp_name); 204 205 sc->sc_pci = 1; 206 sc->sc_enabled = 1; 207 sc->sc_enable = wi_pci_enable; 208 sc->sc_disable = wi_pci_disable; 209 210 /* Enable the card. */ 211 pci_conf_write(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, 212 pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | 213 PCI_COMMAND_MASTER_ENABLE); 214 215 216 /* Map and establish the interrupt. */ 217 if (pci_intr_map(pa, &ih)) { 218 printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname); 219 return; 220 } 221 intrstr = pci_intr_string(pc, ih); 222 223 psc->psc_ih = ih; 224 sc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, wi_intr, sc); 225 if (sc->sc_ih == NULL) { 226 printf("%s: couldn't establish interrupt", 227 sc->sc_dev.dv_xname); 228 if (intrstr != NULL) 229 printf(" at %s", intrstr); 230 printf("\n"); 231 return; 232 } 233 234 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr); 235 236 /* reset HFA3842 MAC core */ 237 wi_pci_reset(sc); 238 239 sc->sc_ifp = &sc->sc_ethercom.ec_if; 240 if (wi_attach(sc) != 0) { 241 printf("%s: failed to attach controller\n", 242 sc->sc_dev.dv_xname); 243 pci_intr_disestablish(pa->pa_pc, sc->sc_ih); 244 return; 245 } 246 247 /* Add a suspend hook to restore PCI config state */ 248 psc->sc_powerhook = powerhook_establish(wi_pci_powerhook, psc); 249 if (psc->sc_powerhook == NULL) 250 printf ("%s: WARNING: unable to establish pci power hook\n", 251 sc->sc_dev.dv_xname); 252 } 253 254 static void 255 wi_pci_powerhook(why, arg) 256 int why; 257 void *arg; 258 { 259 struct wi_pci_softc *psc = arg; 260 struct wi_softc *sc = &psc->psc_wi; 261 262 wi_power(sc, why); 263 } 264