1139749Simp/*- 293611Simp * Copyright (c) 1997, 1998, 1999 393611Simp * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 493611Simp * 593611Simp * Redistribution and use in source and binary forms, with or without 693611Simp * modification, are permitted provided that the following conditions 793611Simp * are met: 893611Simp * 1. Redistributions of source code must retain the above copyright 993611Simp * notice, this list of conditions and the following disclaimer. 1093611Simp * 2. Redistributions in binary form must reproduce the above copyright 1193611Simp * notice, this list of conditions and the following disclaimer in the 1293611Simp * documentation and/or other materials provided with the distribution. 1393611Simp * 3. All advertising materials mentioning features or use of this software 1493611Simp * must display the following acknowledgement: 1593611Simp * This product includes software developed by Bill Paul. 1693611Simp * 4. Neither the name of the author nor the names of any co-contributors 1793611Simp * may be used to endorse or promote products derived from this software 1893611Simp * without specific prior written permission. 1993611Simp * 2093611Simp * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2193611Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2293611Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2393611Simp * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2493611Simp * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2593611Simp * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2693611Simp * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2793611Simp * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2893611Simp * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2993611Simp * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3093611Simp * THE POSSIBILITY OF SUCH DAMAGE. 3195754Simp * 3295754Simp * $FreeBSD$ 3393611Simp */ 3493611Simp 3593611Simp/* 3693611Simp * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. 3793611Simp * 3893611Simp * Written by Bill Paul <wpaul@ctr.columbia.edu> 3993611Simp * Electrical Engineering Department 4093611Simp * Columbia University, New York City 4193611Simp */ 4293611Simp 4393611Simp#include <sys/param.h> 4493611Simp#include <sys/kernel.h> 4593611Simp#include <sys/socket.h> 4695534Simp#include <sys/systm.h> 4793611Simp#include <sys/module.h> 4893611Simp#include <sys/bus.h> 4993611Simp 5093611Simp#include <machine/bus.h> 5193611Simp#include <machine/resource.h> 5293611Simp#include <sys/rman.h> 5393611Simp 54119287Simp#include <dev/pci/pcireg.h> 55119287Simp#include <dev/pci/pcivar.h> 5693611Simp 5793611Simp#include <net/if.h> 5893611Simp#include <net/if_arp.h> 5993611Simp#include <net/ethernet.h> 6093611Simp#include <net/if_media.h> 6193611Simp#include <net/if_types.h> 6293611Simp 63116951Ssam#include <net80211/ieee80211_var.h> 64119784Ssam#include <net80211/ieee80211_radiotap.h> 65116951Ssam 6693611Simp#include <dev/wi/if_wavelan_ieee.h> 67119784Ssam#include <dev/wi/if_wireg.h> 6893611Simp#include <dev/wi/if_wivar.h> 6993611Simp 7093611Simpstatic int wi_pci_probe(device_t); 7193611Simpstatic int wi_pci_attach(device_t); 72109259Smdoddstatic int wi_pci_suspend(device_t); 73109259Smdoddstatic int wi_pci_resume(device_t); 7493611Simp 7593611Simpstatic device_method_t wi_pci_methods[] = { 7693611Simp /* Device interface */ 7793611Simp DEVMETHOD(device_probe, wi_pci_probe), 7893611Simp DEVMETHOD(device_attach, wi_pci_attach), 79109323Ssam DEVMETHOD(device_detach, wi_detach), 8093611Simp DEVMETHOD(device_shutdown, wi_shutdown), 81109259Smdodd DEVMETHOD(device_suspend, wi_pci_suspend), 82109259Smdodd DEVMETHOD(device_resume, wi_pci_resume), 8393611Simp 8493611Simp { 0, 0 } 8593611Simp}; 8693611Simp 8793611Simpstatic driver_t wi_pci_driver = { 8893611Simp "wi", 8993611Simp wi_pci_methods, 9093611Simp sizeof(struct wi_softc) 9193611Simp}; 9293611Simp 9393611Simpstatic struct { 9493611Simp unsigned int vendor,device; 9593611Simp int bus_type; 9693611Simp char *desc; 9793611Simp} pci_ids[] = { 9895603Simp /* Sorted by description */ 9995559Simp {0x10b7, 0x7770, WI_BUS_PCI_PLX, "3Com Airconnect"}, 10095603Simp {0x16ab, 0x1101, WI_BUS_PCI_PLX, "GLPRISM2 WaveLAN"}, 101118679Smarcel {0x1260, 0x3872, WI_BUS_PCI_NATIVE, "Intersil Prism3"}, 10295603Simp {0x1260, 0x3873, WI_BUS_PCI_NATIVE, "Intersil Prism2.5"}, 10395603Simp {0x16ab, 0x1102, WI_BUS_PCI_PLX, "Linksys WDT11"}, 10495603Simp {0x1385, 0x4100, WI_BUS_PCI_PLX, "Netgear MA301"}, 10595603Simp {0x1638, 0x1100, WI_BUS_PCI_PLX, "PRISM2STA WaveLAN"}, 10695559Simp {0x111a, 0x1023, WI_BUS_PCI_PLX, "Siemens SpeedStream"}, 107112360Simp {0x10b5, 0x9050, WI_BUS_PCI_PLX, "SMC 2602W"}, 10898220Snsayer {0x16ec, 0x3685, WI_BUS_PCI_PLX, "US Robotics 2415"}, 109117768Simp {0x4033, 0x7001, WI_BUS_PCI_PLX, "Addtron AWA-100 PCI"}, 11093611Simp {0, 0, 0, NULL} 11193611Simp}; 11293611Simp 113113506SmdoddDRIVER_MODULE(wi, pci, wi_pci_driver, wi_devclass, 0, 0); 114113506SmdoddMODULE_DEPEND(wi, pci, 1, 1, 1); 115113506SmdoddMODULE_DEPEND(wi, wlan, 1, 1, 1); 11693611Simp 11793611Simpstatic int 11893611Simpwi_pci_probe(dev) 11993611Simp device_t dev; 12093611Simp{ 12193611Simp struct wi_softc *sc; 12293611Simp int i; 12393611Simp 12493611Simp sc = device_get_softc(dev); 12593611Simp for(i=0; pci_ids[i].vendor != 0; i++) { 12693611Simp if ((pci_get_vendor(dev) == pci_ids[i].vendor) && 12793611Simp (pci_get_device(dev) == pci_ids[i].device)) { 12893611Simp sc->wi_bus_type = pci_ids[i].bus_type; 12993611Simp device_set_desc(dev, pci_ids[i].desc); 130142880Simp return (BUS_PROBE_DEFAULT); 13193611Simp } 13293611Simp } 13393611Simp return(ENXIO); 13493611Simp} 13593611Simp 13693611Simpstatic int 13793611Simpwi_pci_attach(device_t dev) 13893611Simp{ 13993611Simp struct wi_softc *sc; 140254263Sscottl u_int32_t command; 14193611Simp u_int16_t reg; 14293611Simp int error; 14393611Simp int timeout; 14493611Simp 14593611Simp sc = device_get_softc(dev); 14693611Simp 14793611Simp if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { 14893611Simp error = wi_alloc(dev, WI_PCI_IORES); 14993611Simp if (error) 15093611Simp return (error); 15193611Simp 15293611Simp /* Make sure interrupts are disabled. */ 15393611Simp CSR_WRITE_2(sc, WI_INT_EN, 0); 15493611Simp CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 15593611Simp 15693611Simp /* We have to do a magic PLX poke to enable interrupts */ 15793611Simp sc->local_rid = WI_PCI_LOCALRES; 158127135Snjl sc->local = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 159127135Snjl &sc->local_rid, RF_ACTIVE); 16093611Simp sc->wi_localtag = rman_get_bustag(sc->local); 16193611Simp sc->wi_localhandle = rman_get_bushandle(sc->local); 16293611Simp command = bus_space_read_4(sc->wi_localtag, sc->wi_localhandle, 16393611Simp WI_LOCAL_INTCSR); 16493611Simp command |= WI_LOCAL_INTEN; 16593611Simp bus_space_write_4(sc->wi_localtag, sc->wi_localhandle, 16693611Simp WI_LOCAL_INTCSR, command); 16793611Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->local_rid, 16893611Simp sc->local); 16993611Simp sc->local = NULL; 17093611Simp 17193611Simp sc->mem_rid = WI_PCI_MEMRES; 172127135Snjl sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 173127135Snjl &sc->mem_rid, RF_ACTIVE); 17493611Simp if (sc->mem == NULL) { 17593611Simp device_printf(dev, "couldn't allocate memory\n"); 17693611Simp wi_free(dev); 17793611Simp return (ENXIO); 17893611Simp } 17993611Simp sc->wi_bmemtag = rman_get_bustag(sc->mem); 18093611Simp sc->wi_bmemhandle = rman_get_bushandle(sc->mem); 18193611Simp 18293611Simp /* 18393611Simp * Write COR to enable PC card 18493611Simp * This is a subset of the protocol that the pccard bus code 185181209Simp * would do. In theory, we should parse the CIS to find the 186181209Simp * COR offset. In practice, the COR_OFFSET is always 0x3e0. 18793611Simp */ 18893611Simp CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE); 18993611Simp reg = CSM_READ_1(sc, WI_COR_OFFSET); 19093611Simp if (reg != WI_COR_VALUE) { 19193611Simp device_printf(dev, "CSM_READ_1(WI_COR_OFFSET) " 19293611Simp "wanted %d, got %d\n", WI_COR_VALUE, reg); 19393611Simp wi_free(dev); 19493611Simp return (ENXIO); 19593611Simp } 19693611Simp } else { 19793611Simp error = wi_alloc(dev, WI_PCI_LMEMRES); 19893611Simp if (error) 19993611Simp return (error); 20093611Simp 201181209Simp CSR_WRITE_2(sc, WI_PCICOR_OFF, WI_PCICOR_RESET); 20293611Simp DELAY(250000); 20393611Simp 204181209Simp CSR_WRITE_2(sc, WI_PCICOR_OFF, 0x0000); 20593611Simp DELAY(500000); 20693611Simp 20793611Simp timeout=2000000; 20893611Simp while ((--timeout > 0) && 20993611Simp (CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) 21093611Simp DELAY(10); 21193611Simp 21293611Simp if (timeout == 0) { 213181209Simp device_printf(dev, "couldn't reset prism pci core.\n"); 21493611Simp wi_free(dev); 21593611Simp return(ENXIO); 21693611Simp } 21793611Simp } 21893611Simp 21993611Simp CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC); 22093611Simp reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF); 22193611Simp if (reg != WI_PRISM2STA_MAGIC) { 22293611Simp device_printf(dev, 22393611Simp "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) " 22493611Simp "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg); 22593611Simp wi_free(dev); 22693611Simp return (ENXIO); 22793611Simp } 22893611Simp 229109323Ssam error = wi_attach(dev); 23093611Simp if (error != 0) 231116205Simp wi_free(dev); 232116205Simp return (error); 23393611Simp} 234109259Smdodd 235109259Smdoddstatic int 236109323Ssamwi_pci_suspend(device_t dev) 237109259Smdodd{ 238138571Ssam struct wi_softc *sc = device_get_softc(dev); 239109259Smdodd 240178354Ssam wi_stop(sc, 1); 241109259Smdodd 242109259Smdodd return (0); 243109259Smdodd} 244109259Smdodd 245109259Smdoddstatic int 246109323Ssamwi_pci_resume(device_t dev) 247109259Smdodd{ 248138571Ssam struct wi_softc *sc = device_get_softc(dev); 249178354Ssam struct ifnet *ifp = sc->sc_ifp; 250109259Smdodd 251109259Smdodd if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) 252109259Smdodd return (0); 253109259Smdodd 254109259Smdodd if (ifp->if_flags & IFF_UP) { 255118068Sjdp ifp->if_init(ifp->if_softc); 256148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 257118068Sjdp ifp->if_start(ifp); 258109259Smdodd } 259109259Smdodd 260109259Smdodd return (0); 261109259Smdodd} 262