if_ndis_pccard.c revision 127135
1169689Skan/* 2169689Skan * Copyright (c) 2003 3169689Skan * Bill Paul <wpaul@windriver.com>. All rights reserved. 4169689Skan * 5169689Skan * Redistribution and use in source and binary forms, with or without 6169689Skan * modification, are permitted provided that the following conditions 7169689Skan * are met: 8169689Skan * 1. Redistributions of source code must retain the above copyright 9169689Skan * notice, this list of conditions and the following disclaimer. 10169689Skan * 2. Redistributions in binary form must reproduce the above copyright 11169689Skan * notice, this list of conditions and the following disclaimer in the 12169689Skan * documentation and/or other materials provided with the distribution. 13169689Skan * 3. All advertising materials mentioning features or use of this software 14169689Skan * must display the following acknowledgement: 15169689Skan * This product includes software developed by Bill Paul. 16169689Skan * 4. Neither the name of the author nor the names of any co-contributors 17169689Skan * may be used to endorse or promote products derived from this software 18169689Skan * without specific prior written permission. 19169689Skan * 20169689Skan * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24169689Skan * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25169689Skan * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26169689Skan * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27169689Skan * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28169689Skan * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29169689Skan * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30169689Skan * THE POSSIBILITY OF SUCH DAMAGE. 31169689Skan */ 32169689Skan 33169689Skan#include <sys/cdefs.h> 34169689Skan__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pccard.c 127135 2004-03-17 17:50:55Z njl $"); 35169689Skan 36169689Skan#include <sys/ctype.h> 37169689Skan#include <sys/param.h> 38169689Skan#include <sys/systm.h> 39169689Skan#include <sys/kernel.h> 40169689Skan#include <sys/socket.h> 41169689Skan#include <sys/queue.h> 42169689Skan#include <sys/sysctl.h> 43169689Skan 44169689Skan#include <net/if.h> 45169689Skan#include <net/if_arp.h> 46169689Skan#include <net/if_media.h> 47169689Skan 48169689Skan#include <machine/bus.h> 49169689Skan#include <machine/resource.h> 50169689Skan#include <sys/bus.h> 51169689Skan#include <sys/rman.h> 52169689Skan 53169689Skan#include <net80211/ieee80211_var.h> 54169689Skan 55169689Skan#include <compat/ndis/pe_var.h> 56169689Skan#include <compat/ndis/resource_var.h> 57169689Skan#include <compat/ndis/ntoskrnl_var.h> 58169689Skan#include <compat/ndis/ndis_var.h> 59169689Skan#include <compat/ndis/cfg_var.h> 60169689Skan#include <dev/if_ndis/if_ndisvar.h> 61169689Skan 62169689Skan#include <dev/pccard/pccardvar.h> 63169689Skan#include "card_if.h" 64169689Skan 65169689Skan#include "ndis_driver_data.h" 66169689Skan 67169689Skan#ifdef NDIS_PCMCIA_DEV_TABLE 68169689Skan 69169689SkanMODULE_DEPEND(ndis, pccard, 1, 1, 1); 70169689SkanMODULE_DEPEND(ndis, ether, 1, 1, 1); 71169689SkanMODULE_DEPEND(ndis, wlan, 1, 1, 1); 72169689SkanMODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 73169689Skan 74169689Skan/* 75169689Skan * Various supported device vendors/types and their names. 76169689Skan * These are defined in the ndis_driver_data.h file. 77169689Skan */ 78169689Skanstatic struct ndis_pccard_type ndis_devs[] = { 79169689Skan#ifdef NDIS_PCMCIA_DEV_TABLE 80169689Skan NDIS_PCMCIA_DEV_TABLE 81169689Skan#endif 82169689Skan { NULL, NULL, NULL } 83169689Skan}; 84169689Skan 85169689Skanstatic int ndis_probe_pccard (device_t); 86169689Skanstatic int ndis_attach_pccard (device_t); 87169689Skanextern int ndis_attach (device_t); 88169689Skanextern int ndis_shutdown (device_t); 89169689Skanextern int ndis_detach (device_t); 90169689Skanextern int ndis_suspend (device_t); 91169689Skanextern int ndis_resume (device_t); 92169689Skan 93169689Skanstatic int my_strcasecmp (const char *, const char *, int); 94169689Skan 95169689Skanextern struct mtx_pool *ndis_mtxpool; 96169689Skan 97169689Skanstatic device_method_t ndis_methods[] = { 98169689Skan /* Device interface */ 99169689Skan DEVMETHOD(device_probe, ndis_probe_pccard), 100169689Skan DEVMETHOD(device_attach, ndis_attach_pccard), 101169689Skan DEVMETHOD(device_detach, ndis_detach), 102169689Skan DEVMETHOD(device_shutdown, ndis_shutdown), 103169689Skan DEVMETHOD(device_suspend, ndis_suspend), 104169689Skan DEVMETHOD(device_resume, ndis_resume), 105169689Skan 106169689Skan { 0, 0 } 107169689Skan}; 108169689Skan 109169689Skanstatic driver_t ndis_driver = { 110169689Skan#ifdef NDIS_DEVNAME 111169689Skan NDIS_DEVNAME, 112169689Skan#else 113169689Skan "ndis", 114169689Skan#endif 115169689Skan ndis_methods, 116169689Skan sizeof(struct ndis_softc) 117169689Skan}; 118169689Skan 119169689Skanstatic devclass_t ndis_devclass; 120169689Skan 121169689Skan#ifdef NDIS_MODNAME 122169689Skan#define NDIS_MODNAME_OVERRIDE_PCMCIA(x) \ 123169689Skan DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, 0, 0) 124169689SkanNDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME); 125169689Skan#else 126169689SkanDRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, 0, 0); 127169689Skan#endif 128169689Skan 129169689Skanstatic int my_strcasecmp(s1, s2, len) 130169689Skan const char *s1; 131169689Skan const char *s2; 132169689Skan int len; 133169689Skan{ 134169689Skan int i; 135169689Skan 136169689Skan for (i = 0; i < len; i++) { 137169689Skan if (toupper(s1[i]) != toupper(s2[i])) 138169689Skan return(0); 139169689Skan } 140169689Skan 141169689Skan return(1); 142169689Skan} 143169689Skan 144169689Skan 145169689Skan/* 146169689Skan * Probe for an NDIS device. Check the PCI vendor and device 147169689Skan * IDs against our list and return a device name if we find a match. 148169689Skan */ 149169689Skanstatic int 150169689Skanndis_probe_pccard(dev) 151169689Skan device_t dev; 152169689Skan{ 153169689Skan struct ndis_pccard_type *t; 154169689Skan const char *prodstr, *vendstr; 155169689Skan int error; 156169689Skan 157169689Skan t = ndis_devs; 158169689Skan 159169689Skan error = pccard_get_product_str(dev, &prodstr); 160169689Skan if (error) 161169689Skan return(error); 162169689Skan error = pccard_get_vendor_str(dev, &vendstr); 163169689Skan if (error) 164169689Skan return(error); 165169689Skan 166169689Skan while(t->ndis_name != NULL) { 167169689Skan if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) && 168169689Skan my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) { 169169689Skan device_set_desc(dev, t->ndis_name); 170169689Skan return(0); 171169689Skan } 172169689Skan t++; 173169689Skan } 174169689Skan 175169689Skan return(ENXIO); 176169689Skan} 177169689Skan 178169689Skan/* 179169689Skan * Attach the interface. Allocate softc structures, do ifmedia 180169689Skan * setup and ethernet/BPF attach. 181169689Skan */ 182169689Skanstatic int 183169689Skanndis_attach_pccard(dev) 184169689Skan device_t dev; 185169689Skan{ 186169689Skan struct ndis_softc *sc; 187169689Skan int unit, error = 0, rid; 188169689Skan struct ndis_pccard_type *t; 189169689Skan int devidx = 0; 190169689Skan const char *prodstr, *vendstr; 191169689Skan 192169689Skan sc = device_get_softc(dev); 193169689Skan unit = device_get_unit(dev); 194169689Skan sc->ndis_dev = dev; 195169689Skan 196169689Skan sc->ndis_io_rid = 0; 197169689Skan sc->ndis_res_io = bus_alloc_resource_any(dev, 198169689Skan SYS_RES_IOPORT, &sc->ndis_io_rid, 199169689Skan RF_ACTIVE); 200169689Skan if (sc->ndis_res_io == NULL) { 201169689Skan device_printf(dev, 202169689Skan "couldn't map iospace\n"); 203169689Skan error = ENXIO; 204169689Skan goto fail; 205169689Skan } 206169689Skan sc->ndis_rescnt++; 207169689Skan 208169689Skan rid = 0; 209169689Skan sc->ndis_irq = bus_alloc_resource_any(dev, 210169689Skan SYS_RES_IRQ, &rid, 211169689Skan RF_SHAREABLE | RF_ACTIVE); 212169689Skan if (sc->ndis_irq == NULL) { 213169689Skan device_printf(dev, 214169689Skan "couldn't map interrupt\n"); 215169689Skan error = ENXIO; 216169689Skan goto fail; 217169689Skan } 218169689Skan sc->ndis_rescnt++; 219169689Skan 220169689Skan sc->ndis_iftype = PCMCIABus; 221169689Skan 222169689Skan /* Figure out exactly which device we matched. */ 223169689Skan 224169689Skan t = ndis_devs; 225169689Skan 226169689Skan error = pccard_get_product_str(dev, &prodstr); 227169689Skan if (error) 228169689Skan return(error); 229169689Skan error = pccard_get_vendor_str(dev, &vendstr); 230169689Skan if (error) 231169689Skan return(error); 232169689Skan 233169689Skan while(t->ndis_name != NULL) { 234169689Skan if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) && 235169689Skan my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) 236169689Skan break; 237169689Skan t++; 238169689Skan devidx++; 239169689Skan } 240169689Skan 241169689Skan sc->ndis_devidx = devidx; 242169689Skan 243169689Skan error = ndis_attach(dev); 244169689Skan 245169689Skanfail: 246169689Skan return(error); 247169689Skan} 248169689Skan 249169689Skan#endif /* NDIS_PCI_DEV_TABLE */ 250169689Skan 251169689Skan#define NDIS_AM_RID 3 252169689Skan 253169689Skanint 254169689Skanndis_alloc_amem(arg) 255169689Skan void *arg; 256169689Skan{ 257169689Skan struct ndis_softc *sc; 258169689Skan int error, rid; 259169689Skan 260169689Skan if (arg == NULL) 261169689Skan return(EINVAL); 262169689Skan 263169689Skan sc = arg; 264169689Skan rid = NDIS_AM_RID; 265169689Skan sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 266169689Skan &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 267169689Skan 268169689Skan if (sc->ndis_res_am == NULL) { 269169689Skan device_printf(sc->ndis_dev, 270169689Skan "failed to allocate attribute memory\n"); 271169689Skan return(ENXIO); 272169689Skan } 273169689Skan 274169689Skan error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 275169689Skan sc->ndis_dev, rid, 0, NULL); 276169689Skan 277169689Skan if (error) { 278169689Skan device_printf(sc->ndis_dev, 279169689Skan "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 280169689Skan return(error); 281169689Skan } 282169689Skan 283169689Skan error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 284169689Skan sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 285169689Skan 286169689Skan if (error) { 287169689Skan device_printf(sc->ndis_dev, 288169689Skan "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 289169689Skan return(error); 290169689Skan } 291169689Skan 292169689Skan return(0); 293169689Skan} 294169689Skan