if_wi_pccard.c revision 101245
142575Speter/* 2261363Sgshapiro * Copyright (c) 1997, 1998, 1999 364562Sgshapiro * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 442575Speter * 542575Speter * Redistribution and use in source and binary forms, with or without 642575Speter * modification, are permitted provided that the following conditions 742575Speter * are met: 842575Speter * 1. Redistributions of source code must retain the above copyright 942575Speter * notice, this list of conditions and the following disclaimer. 1042575Speter * 2. Redistributions in binary form must reproduce the above copyright 1164562Sgshapiro * notice, this list of conditions and the following disclaimer in the 1242575Speter * documentation and/or other materials provided with the distribution. 13266692Sgshapiro * 3. All advertising materials mentioning features or use of this software 1490792Sgshapiro * must display the following acknowledgement: 15110560Sgshapiro * This product includes software developed by Bill Paul. 16110560Sgshapiro * 4. Neither the name of the author nor the names of any co-contributors 1777349Sgshapiro * may be used to endorse or promote products derived from this software 1890792Sgshapiro * without specific prior written permission. 1990792Sgshapiro * 2090792Sgshapiro * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2190792Sgshapiro * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2290792Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2390792Sgshapiro * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24168515Sgshapiro * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2564562Sgshapiro * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2677349Sgshapiro * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2777349Sgshapiro * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2877349Sgshapiro * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2977349Sgshapiro * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3077349Sgshapiro * THE POSSIBILITY OF SUCH DAMAGE. 3177349Sgshapiro */ 3277349Sgshapiro 3377349Sgshapiro/* 3477349Sgshapiro * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD. 3577349Sgshapiro * 3677349Sgshapiro * Written by Bill Paul <wpaul@ctr.columbia.edu> 3777349Sgshapiro * Electrical Engineering Department 3890792Sgshapiro * Columbia University, New York City 3990792Sgshapiro */ 4077349Sgshapiro 4177349Sgshapiro#include "opt_wi.h" 4277349Sgshapiro 4377349Sgshapiro#include <sys/param.h> 4490792Sgshapiro#include <sys/kernel.h> 45141858Sgshapiro#include <sys/socket.h> 4642575Speter#include <sys/systm.h> 4742575Speter#include <sys/module.h> 4890792Sgshapiro#include <sys/bus.h> 4942575Speter 5042575Speter#include <machine/bus.h> 5142575Speter#include <machine/resource.h> 5242575Speter#include <sys/rman.h> 5342575Speter 5442575Speter#include <net/if.h> 5542575Speter#include <net/if_arp.h> 5642575Speter#include <net/ethernet.h> 5742575Speter#include <net/if_dl.h> 5842575Speter#include <net/if_media.h> 5942575Speter#include <net/if_types.h> 6042575Speter#include <net/if_ieee80211.h> 6142575Speter 6242575Speter#include <dev/pccard/pccardvar.h> 6342575Speter#if __FreeBSD_version >= 500000 6490792Sgshapiro#include <dev/pccard/pccarddevs.h> 6564562Sgshapiro#endif 6642575Speter 6764562Sgshapiro#include <dev/wi/if_wavelan_ieee.h> 6842575Speter#include <dev/wi/wi_hostap.h> 6942575Speter#include <dev/wi/if_wivar.h> 7090792Sgshapiro#include <dev/wi/if_wireg.h> 7142575Speter#ifdef WI_SYMBOL_FIRMWARE 7242575Speter#include <dev/wi/spectrum24t_cf.h> 73168515Sgshapiro#endif 7442575Speter 7542575Speter#include "card_if.h" 7642575Speter 7742575Speter#if !defined(lint) 7842575Speterstatic const char rcsid[] = 7942575Speter "$FreeBSD: head/sys/dev/wi/if_wi_pccard.c 101245 2002-08-03 00:19:58Z imp $"; 8042575Speter#endif 8142575Speter 8242575Speterstatic int wi_pccard_probe(device_t); 8342575Speterstatic int wi_pccard_attach(device_t); 8442575Speter 8542575Speter#ifdef WI_SYMBOL_FIRMWARE 8642575Speter/* support to download firmware for symbol CF card */ 8742575Speterstatic int wi_pcmcia_load_firm(struct wi_softc *, const void *, int, const void *, int); 8842575Speterstatic int wi_pcmcia_write_firm(struct wi_softc *, const void *, int, const void *, int); 8942575Speterstatic int wi_pcmcia_set_hcr(struct wi_softc *, int); 9042575Speter#endif 9142575Speter 92110560Sgshapiro#if __FreeBSD_version < 500000 93110560Sgshapirostatic device_method_t wi_pccard_methods[] = { 94110560Sgshapiro /* Device interface */ 95110560Sgshapiro DEVMETHOD(device_probe, wi_pccard_probe), 96110560Sgshapiro DEVMETHOD(device_attach, wi_pccard_attach), 97110560Sgshapiro DEVMETHOD(device_detach, wi_generic_detach), 9842575Speter DEVMETHOD(device_shutdown, wi_shutdown), 9964562Sgshapiro 100168515Sgshapiro { 0, 0 } 10142575Speter}; 10290792Sgshapiro 103168515Sgshapiro#else 10442575Speterstatic int wi_pccard_match(device_t); 10542575Speter 106168515Sgshapirostatic device_method_t wi_pccard_methods[] = { 10742575Speter /* Device interface */ 10864562Sgshapiro DEVMETHOD(device_probe, pccard_compat_probe), 10943730Speter DEVMETHOD(device_attach, pccard_compat_attach), 11042575Speter DEVMETHOD(device_detach, wi_generic_detach), 11142575Speter DEVMETHOD(device_shutdown, wi_shutdown), 11242575Speter 11342575Speter /* Card interface */ 11471345Sgshapiro DEVMETHOD(card_compat_match, wi_pccard_match), 11542575Speter DEVMETHOD(card_compat_probe, wi_pccard_probe), 11671345Sgshapiro DEVMETHOD(card_compat_attach, wi_pccard_attach), 11771345Sgshapiro 11871345Sgshapiro { 0, 0 } 11971345Sgshapiro}; 12071345Sgshapiro 12171345Sgshapiro#endif 12271345Sgshapiro 12371345Sgshapirostatic driver_t wi_pccard_driver = { 12471345Sgshapiro "wi", 12542575Speter wi_pccard_methods, 12664562Sgshapiro sizeof(struct wi_softc) 12742575Speter}; 12871345Sgshapiro 12971345SgshapiroDRIVER_MODULE(if_wi, pccard, wi_pccard_driver, wi_devclass, 0, 0); 13090792Sgshapiro 13171345Sgshapiro#if __FreeBSD_version >= 500000 13271345Sgshapirostatic const struct pccard_product wi_pccard_products[] = { 13390792Sgshapiro PCMCIA_CARD(3COM, 3CRWE737A, 0), 13490792Sgshapiro PCMCIA_CARD(3COM, 3CRWE777A, 0), 13542575Speter PCMCIA_CARD(ACTIONTEC, HWC01170, 0), 13642575Speter PCMCIA_CARD(ADDTRON, AWP100, 0), 13742575Speter PCMCIA_CARD(BUFFALO, WLI_PCM_S11, 0), 13842575Speter PCMCIA_CARD(BUFFALO, WLI_CF_S11G, 0), 13942575Speter PCMCIA_CARD(COMPAQ, NC5004, 0), 14042575Speter PCMCIA_CARD(CONTEC, FX_DS110_PCC, 0), 14142575Speter PCMCIA_CARD(COREGA, WIRELESS_LAN_PCC_11, 0), 14264562Sgshapiro PCMCIA_CARD(COREGA, WIRELESS_LAN_PCCA_11, 0), 14390792Sgshapiro PCMCIA_CARD(COREGA, WIRELESS_LAN_PCCB_11, 0), 14442575Speter PCMCIA_CARD(ELSA, XI300_IEEE, 0), 14542575Speter PCMCIA_CARD(ELSA, XI325_IEEE, 0), 14642575Speter PCMCIA_CARD(ELSA, XI800_IEEE, 0), 14742575Speter PCMCIA_CARD(EMTAC, WLAN, 0), 14842575Speter PCMCIA_CARD(ERICSSON, WIRELESSLAN, 0), 14942575Speter PCMCIA_CARD(GEMTEK, WLAN, 0), 15064562Sgshapiro PCMCIA_CARD(HWN, AIRWAY80211, 0), 15190792Sgshapiro PCMCIA_CARD(INTEL, PRO_WLAN_2011, 0), 15242575Speter PCMCIA_CARD(INTERSIL, PRISM2, 0), 15342575Speter PCMCIA_CARD(IODATA2, WNB11PCM, 0), 15442575Speter PCMCIA_CARD(LINKSYS2, IWN, 0), 15590792Sgshapiro PCMCIA_CARD(LINKSYS2, IWN2, 0), 15642575Speter /* Now that we do PRISM detection, I don't think we need these - imp */ 15742575Speter PCMCIA_CARD2(LUCENT, WAVELAN_IEEE, NANOSPEED_PRISM2, 0), 15890792Sgshapiro PCMCIA_CARD2(LUCENT, WAVELAN_IEEE, NEC_CMZ_RT_WP, 0), 15942575Speter PCMCIA_CARD2(LUCENT, WAVELAN_IEEE, NTT_ME_WLAN, 0), 16042575Speter PCMCIA_CARD2(LUCENT, WAVELAN_IEEE, SMC_2632W, 0), 16142575Speter /* Must be after other LUCENT ones because it is less specific */ 16242575Speter PCMCIA_CARD(LUCENT, WAVELAN_IEEE, 0), 16342575Speter PCMCIA_CARD(NETGEAR2, MA401RA, 0), 16442575Speter PCMCIA_CARD(NOKIA, C110_WLAN, 0), 16542575Speter PCMCIA_CARD(PROXIM, RANGELANDS_8430, 0), 16642575Speter PCMCIA_CARD(SAMSUNG, SWL_2000N, 0), 16742575Speter PCMCIA_CARD(SIMPLETECH, SPECTRUM24_ALT, 0), 16842575Speter PCMCIA_CARD(SOCKET, LP_WLAN_CF, 0), 16942575Speter PCMCIA_CARD(SYMBOL, LA4100, 0), 17042575Speter PCMCIA_CARD(TDK, LAK_CD011WL, 0), 17142575Speter { NULL } 17242575Speter}; 17342575Speter 17442575Speterstatic int 17590792Sgshapirowi_pccard_match(dev) 17664562Sgshapiro device_t dev; 17742575Speter{ 17842575Speter const struct pccard_product *pp; 17942575Speter 18042575Speter if ((pp = pccard_product_lookup(dev, wi_pccard_products, 18142575Speter sizeof(wi_pccard_products[0]), NULL)) != NULL) { 18242575Speter device_set_desc(dev, pp->pp_name); 18342575Speter return 0; 18442575Speter } 18542575Speter return ENXIO; 18642575Speter} 18742575Speter#endif 18871345Sgshapiro 18971345Sgshapirostatic int 19064562Sgshapirowi_pccard_probe(dev) 19142575Speter device_t dev; 19242575Speter{ 19342575Speter struct wi_softc *sc; 19442575Speter int error; 19542575Speter 19642575Speter sc = device_get_softc(dev); 19742575Speter sc->wi_gone = 0; 19842575Speter sc->wi_bus_type = WI_BUS_PCCARD; 19990792Sgshapiro 20042575Speter error = wi_alloc(dev, 0); 20142575Speter if (error) 20242575Speter return (error); 20390792Sgshapiro 20442575Speter wi_free(dev); 20542575Speter 20690792Sgshapiro /* Make sure interrupts are disabled. */ 20742575Speter CSR_WRITE_2(sc, WI_INT_EN, 0); 20842575Speter CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); 20942575Speter 21042575Speter return (0); 21142575Speter} 21242575Speter 21342575Speterstatic int 21442575Speterwi_pccard_attach(device_t dev) 21542575Speter{ 21642575Speter struct wi_softc *sc; 21742575Speter int error; 21842575Speter uint32_t vendor; 21942575Speter uint32_t product; 22042575Speter 22142575Speter sc = device_get_softc(dev); 22290792Sgshapiro 22342575Speter error = wi_alloc(dev, 0); 22442575Speter if (error) { 22542575Speter device_printf(dev, "wi_alloc() failed! (%d)\n", error); 22690792Sgshapiro return (error); 22742575Speter } 22890792Sgshapiro 22942575Speter /* 23042575Speter * The cute little Symbol LA4100-series CF cards need to have 23142575Speter * code downloaded to them. 23264562Sgshapiro */ 23342575Speter pccard_get_vendor(dev, &vendor); 23442575Speter pccard_get_product(dev, &product); 23542575Speter if (vendor == PCMCIA_VENDOR_SYMBOL && 23642575Speter product == PCMCIA_PRODUCT_SYMBOL_LA4100) { 23742575Speter#ifdef WI_SYMBOL_FIRMWARE 23842575Speter if (wi_pcmcia_load_firm(sc, 23942575Speter spectrum24t_primsym, sizeof(spectrum24t_primsym), 24042575Speter spectrum24t_secsym, sizeof(spectrum24t_secsym))) { 24142575Speter device_printf(dev, "couldn't load firmware\n"); 24264562Sgshapiro } 24364562Sgshapiro#else 24490792Sgshapiro device_printf(dev, 24564562Sgshapiro "Symbol LA4100 needs 'option WI_SYMBOL_FIRMWARE'\n"); 24664562Sgshapiro return (ENXIO); 247141858Sgshapiro#endif 24864562Sgshapiro } 24977349Sgshapiro 25077349Sgshapiro return (wi_generic_attach(dev)); 25177349Sgshapiro} 25277349Sgshapiro 25377349Sgshapiro#ifdef WI_SYMBOL_FIRMWARE 25477349Sgshapiro 25577349Sgshapiro/* 25664562Sgshapiro * Special routines to download firmware for Symbol CF card. 25764562Sgshapiro * XXX: This should be modified generic into any PRISM-2 based card. 25864562Sgshapiro */ 25942575Speter 26042575Speter#define WI_SBCF_PDIADDR 0x3100 26142575Speter 26242575Speter/* unaligned load little endian */ 26342575Speter#define GETLE32(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24)) 26464562Sgshapiro#define GETLE16(p) ((p)[0] | ((p)[1]<<8)) 26590792Sgshapiro 26690792Sgshapirostatic int 26790792Sgshapirowi_pcmcia_load_firm(struct wi_softc *sc, const void *primsym, int primlen, 26890792Sgshapiro const void *secsym, int seclen) 26942575Speter{ 27042575Speter uint8_t ebuf[256]; 27142575Speter int i; 27242575Speter 27342575Speter /* load primary code and run it */ 27442575Speter wi_pcmcia_set_hcr(sc, WI_HCR_EEHOLD); 27590792Sgshapiro if (wi_pcmcia_write_firm(sc, primsym, primlen, NULL, 0)) 27664562Sgshapiro return EIO; 27764562Sgshapiro wi_pcmcia_set_hcr(sc, WI_HCR_RUN); 27864562Sgshapiro for (i = 0; ; i++) { 27964562Sgshapiro if (i == 10) 28064562Sgshapiro return ETIMEDOUT; 28164562Sgshapiro tsleep(sc, PWAIT, "wiinit", 1); 28264562Sgshapiro if (CSR_READ_2(sc, WI_CNTL) == WI_CNTL_AUX_ENA_STAT) 28364562Sgshapiro break; 28464562Sgshapiro /* write the magic key value to unlock aux port */ 28564562Sgshapiro CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0); 28664562Sgshapiro CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1); 28790792Sgshapiro CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2); 28890792Sgshapiro CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL); 28964562Sgshapiro } 29064562Sgshapiro 29190792Sgshapiro /* issue read EEPROM command: XXX copied from wi_cmd() */ 29290792Sgshapiro CSR_WRITE_2(sc, WI_PARAM0, 0); 29342575Speter CSR_WRITE_2(sc, WI_PARAM1, 0); 29442575Speter CSR_WRITE_2(sc, WI_PARAM2, 0); 29542575Speter CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE); 29642575Speter for (i = 0; i < WI_TIMEOUT; i++) { 29764562Sgshapiro if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD) 29842575Speter break; 29964562Sgshapiro DELAY(1); 30042575Speter } 30190792Sgshapiro CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); 30290792Sgshapiro 30342575Speter CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ); 304249729Sgshapiro CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ); 30542575Speter CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA, 30690792Sgshapiro (uint16_t *)ebuf, sizeof(ebuf) / 2); 30764562Sgshapiro if (GETLE16(ebuf) > sizeof(ebuf)) 30842575Speter return EIO; 30990792Sgshapiro if (wi_pcmcia_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf))) 31042575Speter return EIO; 31142575Speter return 0; 31290792Sgshapiro} 31342575Speter 31490792Sgshapirostatic int 31542575Speterwi_pcmcia_write_firm(struct wi_softc *sc, const void *buf, int buflen, 31642575Speter const void *ebuf, int ebuflen) 31742575Speter{ 31842575Speter const uint8_t *p, *ep, *q, *eq; 31942575Speter char *tp; 32042575Speter uint32_t addr, id, eid; 32142575Speter int i, len, elen, nblk, pdrlen; 322168515Sgshapiro 32342575Speter /* 32442575Speter * Parse the header of the firmware image. 32564562Sgshapiro */ 32642575Speter p = buf; 32742575Speter ep = p + buflen; 32842575Speter while (p < ep && *p++ != ' '); /* FILE: */ 32964562Sgshapiro while (p < ep && *p++ != ' '); /* filename */ 33042575Speter while (p < ep && *p++ != ' '); /* type of the firmware */ 33164562Sgshapiro nblk = strtoul(p, &tp, 10); 33242575Speter p = tp; 33390792Sgshapiro pdrlen = strtoul(p + 1, &tp, 10); 33442575Speter p = tp; 33542575Speter while (p < ep && *p++ != 0x1a); /* skip rest of header */ 33642575Speter 33764562Sgshapiro /* 33842575Speter * Block records: address[4], length[2], data[length]; 33942575Speter */ 34042575Speter for (i = 0; i < nblk; i++) { 34142575Speter addr = GETLE32(p); p += 4; 34242575Speter len = GETLE16(p); p += 2; 34342575Speter CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ); 34464562Sgshapiro CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ); 34542575Speter CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA, 34642575Speter (const uint16_t *)p, len / 2); 34742575Speter p += len; 34864562Sgshapiro } 34942575Speter 35090792Sgshapiro /* 35164562Sgshapiro * PDR: id[4], address[4], length[4]; 35242575Speter */ 35342575Speter for (i = 0; i < pdrlen; ) { 35442575Speter id = GETLE32(p); p += 4; i += 4; 35590792Sgshapiro addr = GETLE32(p); p += 4; i += 4; 35664562Sgshapiro len = GETLE32(p); p += 4; i += 4; 35742575Speter /* replace PDR entry with the values from EEPROM, if any */ 35842575Speter for (q = ebuf, eq = q + ebuflen; q < eq; q += elen * 2) { 35942575Speter elen = GETLE16(q); q += 2; 36042575Speter eid = GETLE16(q); q += 2; 36164562Sgshapiro elen--; /* elen includes eid */ 36290792Sgshapiro if (eid == 0) 36364562Sgshapiro break; 36464562Sgshapiro if (eid != id) 36564562Sgshapiro continue; 36690792Sgshapiro CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ); 36790792Sgshapiro CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ); 36890792Sgshapiro CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA, 36990792Sgshapiro (const uint16_t *)q, len / 2); 37090792Sgshapiro break; 37164562Sgshapiro } 37264562Sgshapiro } 37364562Sgshapiro return 0; 37464562Sgshapiro} 37564562Sgshapiro 37664562Sgshapirostatic int 37790792Sgshapirowi_pcmcia_set_hcr(struct wi_softc *sc, int mode) 37890792Sgshapiro{ 37990792Sgshapiro uint16_t hcr; 38064562Sgshapiro 38190792Sgshapiro CSR_WRITE_2(sc, WI_COR, WI_COR_RESET); 38290792Sgshapiro tsleep(sc, PWAIT, "wiinit", 1); 38390792Sgshapiro hcr = CSR_READ_2(sc, WI_HCR); 38490792Sgshapiro hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE); 38564562Sgshapiro CSR_WRITE_2(sc, WI_HCR, hcr); 38690792Sgshapiro tsleep(sc, PWAIT, "wiinit", 1); 38742575Speter CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE); 38842575Speter tsleep(sc, PWAIT, "wiinit", 1); 38990792Sgshapiro return 0; 39090792Sgshapiro} 39190792Sgshapiro#endif 39290792Sgshapiro