if_ndis_pccard.c revision 129972
1121986Sjhb/* 2121986Sjhb * Copyright (c) 2003 3121986Sjhb * Bill Paul <wpaul@windriver.com>. All rights reserved. 4121986Sjhb * 5121986Sjhb * Redistribution and use in source and binary forms, with or without 6121986Sjhb * modification, are permitted provided that the following conditions 7121986Sjhb * are met: 8121986Sjhb * 1. Redistributions of source code must retain the above copyright 9121986Sjhb * notice, this list of conditions and the following disclaimer. 10121986Sjhb * 2. Redistributions in binary form must reproduce the above copyright 11121986Sjhb * notice, this list of conditions and the following disclaimer in the 12121986Sjhb * documentation and/or other materials provided with the distribution. 13121986Sjhb * 3. All advertising materials mentioning features or use of this software 14121986Sjhb * must display the following acknowledgement: 15121986Sjhb * This product includes software developed by Bill Paul. 16121986Sjhb * 4. Neither the name of the author nor the names of any co-contributors 17121986Sjhb * may be used to endorse or promote products derived from this software 18121986Sjhb * without specific prior written permission. 19121986Sjhb * 20121986Sjhb * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21121986Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22121986Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23121986Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24121986Sjhb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25121986Sjhb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26121986Sjhb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27121986Sjhb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28121986Sjhb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29121986Sjhb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30121986Sjhb * THE POSSIBILITY OF SUCH DAMAGE. 31121986Sjhb */ 32121986Sjhb 33121986Sjhb#include <sys/cdefs.h> 34121986Sjhb__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pccard.c 129972 2004-06-01 23:27:36Z wpaul $"); 35121986Sjhb 36167240Sjhb#include <sys/ctype.h> 37121986Sjhb#include <sys/param.h> 38167240Sjhb#include <sys/systm.h> 39121986Sjhb#include <sys/kernel.h> 40148538Sjhb#include <sys/module.h> 41121986Sjhb#include <sys/socket.h> 42167240Sjhb#include <sys/queue.h> 43167240Sjhb#include <sys/sysctl.h> 44167240Sjhb 45121986Sjhb#include <net/if.h> 46121986Sjhb#include <net/if_arp.h> 47121986Sjhb#include <net/if_media.h> 48214631Sjhb 49121986Sjhb#include <machine/bus.h> 50121986Sjhb#include <machine/resource.h> 51121986Sjhb#include <sys/bus.h> 52167747Sjhb#include <sys/rman.h> 53121986Sjhb 54121986Sjhb#include <net80211/ieee80211_var.h> 55121986Sjhb 56121986Sjhb#include <compat/ndis/pe_var.h> 57121986Sjhb#include <compat/ndis/resource_var.h> 58121986Sjhb#include <compat/ndis/ntoskrnl_var.h> 59121986Sjhb#include <compat/ndis/ndis_var.h> 60151979Sjhb#include <compat/ndis/cfg_var.h> 61151979Sjhb#include <dev/if_ndis/if_ndisvar.h> 62151979Sjhb 63151979Sjhb#include <dev/pccard/pccardvar.h> 64121986Sjhb#include "card_if.h" 65151897Srwatson 66121986Sjhb#include "ndis_driver_data.h" 67121986Sjhb 68151979Sjhb#ifdef NDIS_PCMCIA_DEV_TABLE 69151979Sjhb 70151979SjhbMODULE_DEPEND(ndis, pccard, 1, 1, 1); 71151979SjhbMODULE_DEPEND(ndis, ether, 1, 1, 1); 72151979SjhbMODULE_DEPEND(ndis, wlan, 1, 1, 1); 73151979SjhbMODULE_DEPEND(ndis, ndisapi, 1, 1, 1); 74151979Sjhb 75152461Sandre/* 76152461Sandre * Various supported device vendors/types and their names. 77152461Sandre * These are defined in the ndis_driver_data.h file. 78152461Sandre */ 79121986Sjhbstatic struct ndis_pccard_type ndis_devs[] = { 80121986Sjhb#ifdef NDIS_PCMCIA_DEV_TABLE 81121986Sjhb NDIS_PCMCIA_DEV_TABLE 82121986Sjhb#endif 83151979Sjhb { NULL, NULL, NULL } 84122124Sjhb}; 85122124Sjhb 86156124Sjhbstatic int ndis_probe_pccard (device_t); 87122124Sjhbstatic int ndis_attach_pccard (device_t); 88122124Sjhbextern int ndis_attach (device_t); 89122124Sjhbextern int ndis_shutdown (device_t); 90130980Sjhbextern int ndis_detach (device_t); 91157541Sjhbextern int ndis_suspend (device_t); 92121986Sjhbextern int ndis_resume (device_t); 93121986Sjhb 94121986Sjhbstatic int my_strcasecmp (const char *, const char *, int); 95121986Sjhb 96121986Sjhbextern struct mtx_pool *ndis_mtxpool; 97121986Sjhb 98121986Sjhbstatic device_method_t ndis_methods[] = { 99121986Sjhb /* Device interface */ 100121986Sjhb DEVMETHOD(device_probe, ndis_probe_pccard), 101167747Sjhb DEVMETHOD(device_attach, ndis_attach_pccard), 102121986Sjhb DEVMETHOD(device_detach, ndis_detach), 103121986Sjhb DEVMETHOD(device_shutdown, ndis_shutdown), 104121986Sjhb DEVMETHOD(device_suspend, ndis_suspend), 105121986Sjhb DEVMETHOD(device_resume, ndis_resume), 106121986Sjhb 107121986Sjhb { 0, 0 } 108130980Sjhb}; 109151979Sjhb 110121986Sjhbstatic driver_t ndis_driver = { 111133017Sscottl#ifdef NDIS_DEVNAME 112121986Sjhb NDIS_DEVNAME, 113121986Sjhb#else 114169391Sjhb "ndis", 115121986Sjhb#endif 116121986Sjhb ndis_methods, 117128931Sjhb sizeof(struct ndis_softc) 118128931Sjhb}; 119163219Sjhb 120195249Sjhbstatic devclass_t ndis_devclass; 121129964Sjhb 122121986Sjhb#ifdef NDIS_MODNAME 123129097Sjhb#define NDIS_MODNAME_OVERRIDE_PCMCIA(x) \ 124121986Sjhb DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, 0, 0) 125121986SjhbNDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME); 126169391Sjhb#else 127169391SjhbDRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, 0, 0); 128156124Sjhb#endif 129121986Sjhb 130156124Sjhbstatic int my_strcasecmp(s1, s2, len) 131156124Sjhb const char *s1; 132156124Sjhb const char *s2; 133248085Smarius int len; 134148538Sjhb{ 135148538Sjhb int i; 136148538Sjhb 137148538Sjhb for (i = 0; i < len; i++) { 138148538Sjhb if (toupper(s1[i]) != toupper(s2[i])) 139133017Sscottl return(0); 140133017Sscottl } 141133017Sscottl 142133017Sscottl return(1); 143133017Sscottl} 144133017Sscottl 145121986Sjhb 146121986Sjhb/* 147121986Sjhb * Probe for an NDIS device. Check the PCI vendor and device 148121986Sjhb * IDs against our list and return a device name if we find a match. 149121986Sjhb */ 150121986Sjhbstatic int 151121986Sjhbndis_probe_pccard(dev) 152121986Sjhb device_t dev; 153121986Sjhb{ 154121986Sjhb struct ndis_pccard_type *t; 155121986Sjhb const char *prodstr, *vendstr; 156121986Sjhb int error; 157121986Sjhb 158121986Sjhb t = ndis_devs; 159121986Sjhb 160121986Sjhb error = pccard_get_product_str(dev, &prodstr); 161121986Sjhb if (error) 162121986Sjhb return(error); 163130980Sjhb error = pccard_get_vendor_str(dev, &vendstr); 164130980Sjhb if (error) 165130980Sjhb return(error); 166130980Sjhb 167130980Sjhb while(t->ndis_name != NULL) { 168130980Sjhb if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) && 169130980Sjhb my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) { 170130980Sjhb device_set_desc(dev, t->ndis_name); 171130980Sjhb return(0); 172130980Sjhb } 173130980Sjhb t++; 174130980Sjhb } 175130980Sjhb 176130980Sjhb return(ENXIO); 177130980Sjhb} 178130980Sjhb 179121986Sjhb/* 180151979Sjhb * Attach the interface. Allocate softc structures, do ifmedia 181130980Sjhb * setup and ethernet/BPF attach. 182130980Sjhb */ 183151979Sjhbstatic int 184151979Sjhbndis_attach_pccard(dev) 185130980Sjhb device_t dev; 186130980Sjhb{ 187151979Sjhb struct ndis_softc *sc; 188130980Sjhb int unit, error = 0, rid; 189130980Sjhb struct ndis_pccard_type *t; 190151979Sjhb int devidx = 0; 191130980Sjhb const char *prodstr, *vendstr; 192130980Sjhb 193151979Sjhb sc = device_get_softc(dev); 194130980Sjhb unit = device_get_unit(dev); 195130980Sjhb sc->ndis_dev = dev; 196130980Sjhb 197130980Sjhb sc->ndis_io_rid = 0; 198151979Sjhb sc->ndis_res_io = bus_alloc_resource(dev, 199130980Sjhb SYS_RES_IOPORT, &sc->ndis_io_rid, 200130980Sjhb 0, ~0, 1, RF_ACTIVE); 201130980Sjhb if (sc->ndis_res_io == NULL) { 202130980Sjhb device_printf(dev, 203121986Sjhb "couldn't map iospace\n"); 204121986Sjhb error = ENXIO; 205121986Sjhb goto fail; 206121986Sjhb } 207121986Sjhb sc->ndis_rescnt++; 208121986Sjhb 209121986Sjhb rid = 0; 210121986Sjhb sc->ndis_irq = bus_alloc_resource(dev, 211157541Sjhb SYS_RES_IRQ, &rid, 0, ~0, 1, 212121986Sjhb RF_SHAREABLE | RF_ACTIVE); 213121986Sjhb if (sc->ndis_irq == NULL) { 214121986Sjhb device_printf(dev, 215121986Sjhb "couldn't map interrupt\n"); 216121986Sjhb error = ENXIO; 217121986Sjhb goto fail; 218121986Sjhb } 219121986Sjhb sc->ndis_rescnt++; 220133017Sscottl 221121986Sjhb sc->ndis_iftype = PCMCIABus; 222121986Sjhb 223121986Sjhb /* Figure out exactly which device we matched. */ 224121986Sjhb 225121986Sjhb t = ndis_devs; 226121986Sjhb 227121986Sjhb error = pccard_get_product_str(dev, &prodstr); 228157541Sjhb if (error) 229121986Sjhb return(error); 230121986Sjhb error = pccard_get_vendor_str(dev, &vendstr); 231121986Sjhb if (error) 232121986Sjhb return(error); 233133017Sscottl 234133017Sscottl while(t->ndis_name != NULL) { 235133017Sscottl if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) && 236133017Sscottl my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) 237121986Sjhb break; 238121986Sjhb t++; 239121986Sjhb devidx++; 240121986Sjhb } 241121986Sjhb 242121986Sjhb sc->ndis_devidx = devidx; 243122148Sjhb 244133017Sscottl error = ndis_attach(dev); 245121986Sjhb 246121986Sjhbfail: 247121986Sjhb return(error); 248129964Sjhb} 249129964Sjhb 250129964Sjhb#endif /* NDIS_PCI_DEV_TABLE */ 251129964Sjhb 252129964Sjhb#define NDIS_AM_RID 3 253129964Sjhb 254129964Sjhbint 255129964Sjhbndis_alloc_amem(arg) 256129964Sjhb void *arg; 257151979Sjhb{ 258151979Sjhb struct ndis_softc *sc; 259151979Sjhb int error, rid; 260151979Sjhb 261208915Sjhb if (arg == NULL) 262151979Sjhb return(EINVAL); 263151979Sjhb 264129964Sjhb sc = arg; 265129964Sjhb rid = NDIS_AM_RID; 266129964Sjhb sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 267129964Sjhb &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 268129964Sjhb 269129964Sjhb if (sc->ndis_res_am == NULL) { 270129964Sjhb device_printf(sc->ndis_dev, 271129964Sjhb "failed to allocate attribute memory\n"); 272129964Sjhb return(ENXIO); 273129964Sjhb } 274156124Sjhb 275156124Sjhb error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 276129964Sjhb sc->ndis_dev, rid, 0, NULL); 277129964Sjhb 278129964Sjhb if (error) { 279129964Sjhb device_printf(sc->ndis_dev, 280129964Sjhb "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 281129964Sjhb return(error); 282129964Sjhb } 283129964Sjhb 284129964Sjhb error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 285129964Sjhb sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 286129964Sjhb 287129964Sjhb if (error) { 288151979Sjhb device_printf(sc->ndis_dev, 289151979Sjhb "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 290129964Sjhb return(error); 291148538Sjhb } 292129964Sjhb 293129964Sjhb return(0); 294151979Sjhb} 295129964Sjhb