if_ndis_pci.c revision 126780
1/* 2 * Copyright (c) 2003 3 * Bill Paul <wpaul@windriver.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pci.c 126780 2004-03-09 18:39:40Z wpaul $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/sockio.h> 39#include <sys/mbuf.h> 40#include <sys/malloc.h> 41#include <sys/kernel.h> 42#include <sys/socket.h> 43#include <sys/queue.h> 44#include <sys/sysctl.h> 45 46#include <net/if.h> 47#include <net/if_arp.h> 48#include <net/ethernet.h> 49#include <net/if_dl.h> 50#include <net/if_media.h> 51 52#include <net/bpf.h> 53 54#include <machine/bus_memio.h> 55#include <machine/bus_pio.h> 56#include <machine/bus.h> 57#include <machine/resource.h> 58#include <sys/bus.h> 59#include <sys/rman.h> 60 61#include <net80211/ieee80211_var.h> 62#include <net80211/ieee80211_ioctl.h> 63 64#include <dev/wi/if_wavelan_ieee.h> 65 66#include <dev/pci/pcireg.h> 67#include <dev/pci/pcivar.h> 68 69#include <compat/ndis/pe_var.h> 70#include <compat/ndis/resource_var.h> 71#include <compat/ndis/ntoskrnl_var.h> 72#include <compat/ndis/ndis_var.h> 73#include <compat/ndis/cfg_var.h> 74#include <dev/if_ndis/if_ndisvar.h> 75 76#include "ndis_driver_data.h" 77 78#ifdef NDIS_PCI_DEV_TABLE 79 80MODULE_DEPEND(ndis, pci, 1, 1, 1); 81MODULE_DEPEND(ndis, ether, 1, 1, 1); 82MODULE_DEPEND(ndis, wlan, 1, 1, 1); 83MODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 84 85/* 86 * Various supported device vendors/types and their names. 87 * These are defined in the ndis_driver_data.h file. 88 */ 89static struct ndis_pci_type ndis_devs[] = { 90#ifdef NDIS_PCI_DEV_TABLE 91 NDIS_PCI_DEV_TABLE 92#endif 93 { 0, 0, 0, NULL } 94}; 95 96static int ndis_probe_pci (device_t); 97static int ndis_attach_pci (device_t); 98extern int ndis_attach (device_t); 99extern int ndis_shutdown (device_t); 100extern int ndis_detach (device_t); 101extern int ndis_suspend (device_t); 102extern int ndis_resume (device_t); 103 104extern struct mtx_pool *ndis_mtxpool; 105 106static device_method_t ndis_methods[] = { 107 /* Device interface */ 108 DEVMETHOD(device_probe, ndis_probe_pci), 109 DEVMETHOD(device_attach, ndis_attach_pci), 110 DEVMETHOD(device_detach, ndis_detach), 111 DEVMETHOD(device_shutdown, ndis_shutdown), 112 DEVMETHOD(device_suspend, ndis_suspend), 113 DEVMETHOD(device_resume, ndis_resume), 114 115 { 0, 0 } 116}; 117 118static driver_t ndis_driver = { 119#ifdef NDIS_DEVNAME 120 NDIS_DEVNAME, 121#else 122 "ndis", 123#endif 124 ndis_methods, 125 sizeof(struct ndis_softc) 126}; 127 128static devclass_t ndis_devclass; 129 130#ifdef NDIS_MODNAME 131#define NDIS_MODNAME_OVERRIDE_PCI(x) \ 132 DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, 0, 0) 133#define NDIS_MODNAME_OVERRIDE_CARDBUS(x) \ 134 DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, 0, 0) 135NDIS_MODNAME_OVERRIDE_PCI(NDIS_MODNAME); 136NDIS_MODNAME_OVERRIDE_CARDBUS(NDIS_MODNAME); 137#else 138DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0); 139DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, 0, 0); 140#endif 141 142/* 143 * Probe for an NDIS device. Check the PCI vendor and device 144 * IDs against our list and return a device name if we find a match. 145 */ 146static int 147ndis_probe_pci(dev) 148 device_t dev; 149{ 150 struct ndis_pci_type *t; 151 152 t = ndis_devs; 153 154 while(t->ndis_name != NULL) { 155 if ((pci_get_vendor(dev) == t->ndis_vid) && 156 (pci_get_device(dev) == t->ndis_did) && 157 ((pci_read_config(dev, PCIR_SUBVEND_0, 4) == 158 t->ndis_subsys) || t->ndis_subsys == 0)) { 159 device_set_desc(dev, t->ndis_name); 160 return(0); 161 } 162 t++; 163 } 164 165 return(ENXIO); 166} 167 168/* 169 * Attach the interface. Allocate softc structures, do ifmedia 170 * setup and ethernet/BPF attach. 171 */ 172static int 173ndis_attach_pci(dev) 174 device_t dev; 175{ 176 struct ndis_softc *sc; 177 int unit, error = 0, rid; 178 struct ndis_pci_type *t; 179 int devidx = 0, defidx = 0; 180 struct resource_list *rl; 181 struct resource_list_entry *rle; 182 183 sc = device_get_softc(dev); 184 unit = device_get_unit(dev); 185 sc->ndis_dev = dev; 186 187 /* 188 * Map control/status registers. 189 */ 190 191 pci_enable_busmaster(dev); 192 193 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 194 if (rl != NULL) { 195 SLIST_FOREACH(rle, rl, link) { 196 switch (rle->type) { 197 case SYS_RES_IOPORT: 198 sc->ndis_io_rid = rle->rid; 199 sc->ndis_res_io = bus_alloc_resource(dev, 200 SYS_RES_IOPORT, &sc->ndis_io_rid, 201 0, ~0, 1, RF_ACTIVE); 202 if (sc->ndis_res_io == NULL) { 203 device_printf(dev, 204 "couldn't map iospace\n"); 205 error = ENXIO; 206 goto fail; 207 } 208 break; 209 case SYS_RES_MEMORY: 210 if (sc->ndis_res_altmem != NULL && 211 sc->ndis_res_mem != NULL) { 212 device_printf(dev, 213 "too many memory resources\n"); 214 error = ENXIO; 215 goto fail; 216 } 217 if (rle->rid == PCIR_BAR(2)) { 218 sc->ndis_altmem_rid = rle->rid; 219 sc->ndis_res_altmem = 220 bus_alloc_resource(dev, 221 SYS_RES_MEMORY, 222 &sc->ndis_altmem_rid, 223 0, ~0, 1, RF_ACTIVE); 224 if (sc->ndis_res_altmem == NULL) { 225 device_printf(dev, 226 "couldn't map alt " 227 "memory\n"); 228 error = ENXIO; 229 goto fail; 230 } 231 } else { 232 sc->ndis_mem_rid = rle->rid; 233 sc->ndis_res_mem = 234 bus_alloc_resource(dev, 235 SYS_RES_MEMORY, 236 &sc->ndis_mem_rid, 237 0, ~0, 1, RF_ACTIVE); 238 if (sc->ndis_res_mem == NULL) { 239 device_printf(dev, 240 "couldn't map memory\n"); 241 error = ENXIO; 242 goto fail; 243 } 244 } 245 break; 246 case SYS_RES_IRQ: 247 rid = rle->rid; 248 sc->ndis_irq = bus_alloc_resource(dev, 249 SYS_RES_IRQ, &rid, 0, ~0, 1, 250 RF_SHAREABLE | RF_ACTIVE); 251 if (sc->ndis_irq == NULL) { 252 device_printf(dev, 253 "couldn't map interrupt\n"); 254 error = ENXIO; 255 goto fail; 256 } 257 break; 258 default: 259 break; 260 } 261 sc->ndis_rescnt++; 262 } 263 } 264 265 /* 266 * If the BIOS did not set up an interrupt for this device, 267 * the resource traversal code above will fail to set up 268 * an IRQ resource. This is usually a bad thing, so try to 269 * force the allocation of an interrupt here. If one was 270 * not assigned to us by the BIOS, bus_alloc_resource() 271 * should route one for us. 272 */ 273 if (sc->ndis_irq == NULL) { 274 rid = 0; 275 sc->ndis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, 276 &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); 277 if (sc->ndis_irq == NULL) { 278 device_printf(dev, "couldn't route interrupt\n"); 279 error = ENXIO; 280 goto fail; 281 } 282 sc->ndis_rescnt++; 283 } 284 285 /* 286 * Allocate the parent bus DMA tag appropriate for PCI. 287 */ 288#define NDIS_NSEG_NEW 32 289 error = bus_dma_tag_create(NULL, /* parent */ 290 1, 0, /* alignment, boundary */ 291 BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ 292 BUS_SPACE_MAXADDR, /* highaddr */ 293 NULL, NULL, /* filter, filterarg */ 294 MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */ 295 BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 296 BUS_DMA_ALLOCNOW, /* flags */ 297 NULL, NULL, /* lockfunc, lockarg */ 298 &sc->ndis_parent_tag); 299 300 if (error) 301 goto fail; 302 303 sc->ndis_iftype = PCIBus; 304 305 /* Figure out exactly which device we matched. */ 306 307 t = ndis_devs; 308 309 while(t->ndis_name != NULL) { 310 if ((pci_get_vendor(dev) == t->ndis_vid) && 311 (pci_get_device(dev) == t->ndis_did)) { 312 if (t->ndis_subsys == 0) 313 defidx = devidx; 314 else { 315 if (t->ndis_subsys == 316 pci_read_config(dev, PCIR_SUBVEND_0, 4)) 317 break; 318 } 319 } 320 t++; 321 devidx++; 322 } 323 324 if (ndis_devs[devidx].ndis_name == NULL) 325 sc->ndis_devidx = defidx; 326 else 327 sc->ndis_devidx = devidx; 328 329 error = ndis_attach(dev); 330 331fail: 332 return(error); 333} 334 335#endif /* NDIS_PCI_DEV_TABLE */ 336