The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/pcmcia/if_wi_pcmcia.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: if_wi_pcmcia.c,v 1.41 2004/01/25 02:42:49 sekiya Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Ichiro FUKUHARA (ichiro@ichiro.org).
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * PCMCIA attachment for Lucent & Intersil WaveLAN PCMCIA card
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: if_wi_pcmcia.c,v 1.41 2004/01/25 02:42:49 sekiya Exp $");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/callout.h>
   49 #include <sys/device.h>
   50 #include <sys/proc.h>
   51 #include <sys/socket.h>
   52 
   53 #include <net/if.h>
   54 #include <net/if_ether.h>
   55 #include <net/if_media.h>
   56 
   57 #include <net80211/ieee80211_var.h>
   58 #include <net80211/ieee80211_compat.h>
   59 #include <net80211/ieee80211_radiotap.h>
   60 #include <net80211/ieee80211_rssadapt.h>
   61 
   62 #include <machine/cpu.h>
   63 #include <machine/bus.h>
   64 #include <machine/intr.h>
   65 
   66 #include <dev/ic/wi_ieee.h>
   67 #include <dev/ic/wireg.h>
   68 #include <dev/ic/wivar.h>
   69 
   70 #include <dev/pcmcia/pcmciareg.h>
   71 #include <dev/pcmcia/pcmciavar.h>
   72 #include <dev/pcmcia/pcmciadevs.h>
   73 
   74 #include <dev/microcode/wi/spectrum24t_cf.h>
   75 
   76 static int      wi_pcmcia_match __P((struct device *, struct cfdata *, void *));
   77 static void     wi_pcmcia_attach __P((struct device *, struct device *, void *));
   78 static int      wi_pcmcia_detach __P((struct device *, int));
   79 static int      wi_pcmcia_enable __P((struct wi_softc *));
   80 static void     wi_pcmcia_disable __P((struct wi_softc *));
   81 static void     wi_pcmcia_powerhook __P((int, void *));
   82 static void     wi_pcmcia_shutdown __P((void *));
   83 
   84 /* support to download firmware for symbol CF card */
   85 static int      wi_pcmcia_load_firm __P((struct wi_softc *, const void *, int, const void *, int));
   86 static int      wi_pcmcia_write_firm __P((struct wi_softc *, const void *, int, const void *, int));
   87 static int      wi_pcmcia_set_hcr __P((struct wi_softc *, int));
   88 
   89 
   90 static const struct wi_pcmcia_product
   91                 *wi_pcmcia_lookup __P((struct pcmcia_attach_args *pa));
   92 
   93 struct wi_pcmcia_softc {
   94         struct wi_softc sc_wi;
   95 
   96         /* PCMCIA-specific */
   97         struct pcmcia_io_handle sc_pcioh;       /* PCMCIA i/o space info */
   98         int sc_io_window;                       /* our i/o window */
   99         struct pcmcia_function *sc_pf;          /* PCMCIA function */
  100         void *sc_powerhook;                     /* power hook descriptor */
  101         void *sc_sdhook;                        /* shutdown hook */
  102         int sc_symbol_cf;                       /* Spectrum24t CF card */
  103 };
  104 
  105 static int wi_pcmcia_find __P((struct wi_pcmcia_softc *,
  106         struct pcmcia_attach_args *, struct pcmcia_config_entry *));
  107 
  108 CFATTACH_DECL(wi_pcmcia, sizeof(struct wi_pcmcia_softc),
  109     wi_pcmcia_match, wi_pcmcia_attach, wi_pcmcia_detach, wi_activate);
  110 
  111 static const struct wi_pcmcia_product {
  112         u_int32_t       pp_vendor;      /* vendor ID */
  113         u_int32_t       pp_product;     /* product ID */
  114         const char      *pp_cisinfo[4]; /* CIS information */
  115         const char      *pp_name;       /* product name */
  116 } wi_pcmcia_products[] = {
  117         { PCMCIA_VENDOR_LUCENT,
  118           PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
  119           PCMCIA_CIS_LUCENT_WAVELAN_IEEE,
  120           PCMCIA_STR_LUCENT_WAVELAN_IEEE },
  121 
  122         { PCMCIA_VENDOR_3COM,
  123           PCMCIA_PRODUCT_3COM_3CRWE737A,
  124           PCMCIA_CIS_3COM_3CRWE737A,
  125           PCMCIA_STR_3COM_3CRWE737A },
  126 
  127         { PCMCIA_VENDOR_COREGA,
  128           PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCC_11,
  129           PCMCIA_CIS_COREGA_WIRELESS_LAN_PCC_11,
  130           PCMCIA_STR_COREGA_WIRELESS_LAN_PCC_11 },
  131 
  132         { PCMCIA_VENDOR_COREGA,
  133           PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCA_11,
  134           PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCA_11,
  135           PCMCIA_STR_COREGA_WIRELESS_LAN_PCCA_11 },
  136 
  137         { PCMCIA_VENDOR_COREGA,
  138           PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCB_11,
  139           PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCB_11,
  140           PCMCIA_STR_COREGA_WIRELESS_LAN_PCCB_11 },
  141 
  142         { PCMCIA_VENDOR_COREGA,
  143           PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_PCCL_11,
  144           PCMCIA_CIS_COREGA_WIRELESS_LAN_PCCL_11,
  145           PCMCIA_STR_COREGA_WIRELESS_LAN_PCCL_11 },
  146 
  147         { PCMCIA_VENDOR_COREGA,
  148           PCMCIA_PRODUCT_COREGA_WIRELESS_LAN_WLCFL_11,
  149           PCMCIA_CIS_COREGA_WIRELESS_LAN_WLCFL_11,
  150           PCMCIA_STR_COREGA_WIRELESS_LAN_WLCFL_11 },
  151 
  152         { PCMCIA_VENDOR_INTEL,
  153           PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011,
  154           PCMCIA_CIS_INTEL_PRO_WLAN_2011,
  155           PCMCIA_STR_INTEL_PRO_WLAN_2011 },
  156 
  157         { PCMCIA_VENDOR_INTERSIL,
  158           PCMCIA_PRODUCT_INTERSIL_PRISM2,
  159           PCMCIA_CIS_INTERSIL_PRISM2,
  160           PCMCIA_STR_INTERSIL_PRISM2 },
  161 
  162         { PCMCIA_VENDOR_SAMSUNG,
  163           PCMCIA_PRODUCT_SAMSUNG_SWL_2000N,
  164           PCMCIA_CIS_SAMSUNG_SWL_2000N,
  165           PCMCIA_STR_SAMSUNG_SWL_2000N },
  166 
  167         { PCMCIA_VENDOR_LUCENT,
  168           PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
  169           PCMCIA_CIS_SMC_2632W,
  170           PCMCIA_STR_SMC_2632W },
  171 
  172         { PCMCIA_VENDOR_LUCENT,
  173           PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
  174           PCMCIA_CIS_NANOSPEED_PRISM2,
  175           PCMCIA_STR_NANOSPEED_PRISM2 },
  176 
  177         { PCMCIA_VENDOR_LINKSYS2,
  178           PCMCIA_PRODUCT_LINKSYS2_IWN,
  179           PCMCIA_CIS_NANOSPEED_PRISM2,
  180           PCMCIA_STR_NANOSPEED_PRISM2 },
  181 
  182         { PCMCIA_VENDOR_ELSA,
  183           PCMCIA_PRODUCT_ELSA_XI300_IEEE,
  184           PCMCIA_CIS_ELSA_XI300_IEEE,
  185           PCMCIA_STR_ELSA_XI300_IEEE },
  186 
  187         { PCMCIA_VENDOR_ELSA,
  188           PCMCIA_PRODUCT_ELSA_XI325_IEEE,
  189           PCMCIA_CIS_ELSA_XI325_IEEE,
  190           PCMCIA_STR_ELSA_XI325_IEEE },
  191 
  192         { PCMCIA_VENDOR_ELSA,
  193           PCMCIA_PRODUCT_ELSA_XI800_IEEE,
  194           PCMCIA_CIS_ELSA_XI800_IEEE,
  195           PCMCIA_STR_ELSA_XI800_IEEE },
  196 
  197         { PCMCIA_VENDOR_COMPAQ,
  198           PCMCIA_PRODUCT_COMPAQ_NC5004,
  199           PCMCIA_CIS_COMPAQ_NC5004,
  200           PCMCIA_STR_COMPAQ_NC5004 },
  201 
  202         { PCMCIA_VENDOR_CONTEC,
  203           PCMCIA_PRODUCT_CONTEC_FX_DS110_PCC,
  204           PCMCIA_CIS_CONTEC_FX_DS110_PCC,
  205           PCMCIA_STR_CONTEC_FX_DS110_PCC },
  206 
  207         { PCMCIA_VENDOR_TDK,
  208           PCMCIA_PRODUCT_TDK_LAK_CD011WL,
  209           PCMCIA_CIS_TDK_LAK_CD011WL,
  210           PCMCIA_STR_TDK_LAK_CD011WL },
  211 
  212         { PCMCIA_VENDOR_LUCENT,
  213           PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
  214           PCMCIA_CIS_NEC_CMZ_RT_WP,
  215           PCMCIA_STR_NEC_CMZ_RT_WP },
  216 
  217         { PCMCIA_VENDOR_LUCENT,
  218           PCMCIA_PRODUCT_LUCENT_WAVELAN_IEEE,
  219           PCMCIA_CIS_NTT_ME_WLAN,
  220           PCMCIA_STR_NTT_ME_WLAN },
  221 
  222         { PCMCIA_VENDOR_IODATA2,
  223           PCMCIA_PRODUCT_IODATA2_WNB11PCM,
  224           PCMCIA_CIS_IODATA2_WNB11PCM,
  225           PCMCIA_STR_IODATA2_WNB11PCM },
  226 
  227         { PCMCIA_VENDOR_IODATA2,
  228           PCMCIA_PRODUCT_IODATA2_WCF12,
  229           PCMCIA_CIS_IODATA2_WCF12,
  230           PCMCIA_STR_IODATA2_WCF12 },
  231 
  232         { PCMCIA_VENDOR_BUFFALO,
  233           PCMCIA_PRODUCT_BUFFALO_WLI_PCM_S11,
  234           PCMCIA_CIS_BUFFALO_WLI_PCM_S11,
  235           PCMCIA_STR_BUFFALO_WLI_PCM_S11 },
  236 
  237         { PCMCIA_VENDOR_BUFFALO,
  238           PCMCIA_PRODUCT_BUFFALO_WLI_CF_S11G,
  239           PCMCIA_CIS_BUFFALO_WLI_CF_S11G,
  240           PCMCIA_STR_BUFFALO_WLI_CF_S11G },
  241 
  242         { PCMCIA_VENDOR_EMTAC,
  243           PCMCIA_PRODUCT_EMTAC_WLAN,
  244           PCMCIA_CIS_EMTAC_WLAN,
  245           PCMCIA_STR_EMTAC_WLAN },
  246 
  247         { PCMCIA_VENDOR_NETGEAR_2,
  248           PCMCIA_PRODUCT_NETGEAR_2_MA401,
  249           PCMCIA_CIS_NETGEAR_2_MA401,
  250           PCMCIA_STR_NETGEAR_2_MA401 },
  251 
  252         { PCMCIA_VENDOR_INTERSIL,
  253           PCMCIA_PRODUCT_GEMTEK_WLAN,
  254           PCMCIA_CIS_GEMTEK_WLAN,
  255           PCMCIA_STR_GEMTEK_WLAN },
  256 
  257         { PCMCIA_VENDOR_SIMPLETECH,
  258           PCMCIA_PRODUCT_SIMPLETECH_SPECTRUM24_ALT,
  259           PCMCIA_CIS_SIMPLETECH_SPECTRUM24_ALT,
  260           PCMCIA_STR_SIMPLETECH_SPECTRUM24_ALT },
  261 
  262         { PCMCIA_VENDOR_ERICSSON,
  263           PCMCIA_PRODUCT_ERICSSON_WIRELESSLAN,
  264           PCMCIA_CIS_ERICSSON_WIRELESSLAN,
  265           PCMCIA_STR_ERICSSON_WIRELESSLAN },
  266 
  267         { PCMCIA_VENDOR_SYMBOL,
  268           PCMCIA_PRODUCT_SYMBOL_LA4100,
  269           PCMCIA_CIS_SYMBOL_LA4100,
  270           PCMCIA_STR_SYMBOL_LA4100 },
  271 
  272         { PCMCIA_VENDOR_LINKSYS2,
  273           PCMCIA_PRODUCT_LINKSYS2_IWN3,
  274           PCMCIA_CIS_LINKSYS2_IWN3,
  275           PCMCIA_STR_LINKSYS2_IWN3 },
  276 
  277         { PCMCIA_VENDOR_LINKSYS2,
  278           PCMCIA_PRODUCT_LINKSYS2_WCF11,
  279           PCMCIA_CIS_LINKSYS2_WCF11,
  280           PCMCIA_STR_LINKSYS2_WCF11 },
  281 
  282         { PCMCIA_VENDOR_PLANEX,
  283           PCMCIA_PRODUCT_PLANEX_GWNS11H,
  284           PCMCIA_CIS_PLANEX_GWNS11H,
  285           PCMCIA_STR_PLANEX_GWNS11H },
  286 
  287         { PCMCIA_VENDOR_BAY,
  288           PCMCIA_PRODUCT_BAY_EMOBILITY_11B,
  289           PCMCIA_CIS_BAY_EMOBILITY_11B,
  290           PCMCIA_STR_BAY_EMOBILITY_11B },
  291 
  292         { PCMCIA_VENDOR_ACTIONTEC,
  293           PCMCIA_PRODUCT_ACTIONTEC_PRISM,
  294           PCMCIA_CIS_ACTIONTEC_PRISM,
  295           PCMCIA_STR_ACTIONTEC_PRISM },
  296 
  297         { PCMCIA_VENDOR_DLINK_2,
  298           PCMCIA_PRODUCT_DLINK_DWL650H,
  299           PCMCIA_CIS_DLINK_DWL650H,
  300           PCMCIA_STR_DLINK_DWL650H },
  301 
  302         { PCMCIA_VENDOR_FUJITSU,
  303           PCMCIA_PRODUCT_FUJITSU_WL110,
  304           PCMCIA_CIS_FUJITSU_WL110,
  305           PCMCIA_STR_FUJITSU_WL110 },
  306 
  307         { 0,
  308           0,
  309           { NULL, NULL, NULL, NULL },
  310           NULL }
  311 };
  312 
  313 static const struct wi_pcmcia_product *
  314 wi_pcmcia_lookup(pa)
  315         struct pcmcia_attach_args *pa;
  316 {
  317         const struct wi_pcmcia_product *pp;
  318 
  319         /* match by CIS information */
  320         for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) {
  321                 if (pa->card->cis1_info[0] != NULL &&
  322                     pp->pp_cisinfo[0] != NULL &&
  323                     strcmp(pa->card->cis1_info[0], pp->pp_cisinfo[0]) == 0 &&
  324                     pa->card->cis1_info[1] != NULL &&
  325                     pp->pp_cisinfo[1] != NULL &&
  326                     strcmp(pa->card->cis1_info[1], pp->pp_cisinfo[1]) == 0)
  327                         return pp;
  328         }
  329 
  330         /* match by vendor/product id */
  331         for (pp = wi_pcmcia_products; pp->pp_name != NULL; pp++) {
  332                 if (pa->manufacturer != PCMCIA_VENDOR_INVALID &&
  333                     pa->manufacturer == pp->pp_vendor &&
  334                     pa->product != PCMCIA_PRODUCT_INVALID &&
  335                     pa->product == pp->pp_product)
  336                         return pp;
  337         }
  338 
  339         return (NULL);
  340 }
  341 
  342 static int
  343 wi_pcmcia_match(parent, match, aux)
  344         struct device *parent;
  345         struct cfdata *match;
  346         void *aux;
  347 {
  348         struct pcmcia_attach_args *pa = aux;
  349 
  350         if (wi_pcmcia_lookup(pa) != NULL)
  351                 return (1);
  352         return (0);
  353 }
  354 
  355 static int
  356 wi_pcmcia_enable(sc)
  357         struct wi_softc *sc;
  358 {
  359         struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)sc;
  360         struct pcmcia_function *pf = psc->sc_pf;
  361 
  362         /* establish the interrupt. */
  363         sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, wi_intr, sc);
  364         if (sc->sc_ih == NULL) {
  365                 printf("%s: couldn't establish interrupt\n",
  366                     sc->sc_dev.dv_xname);
  367                 return (EIO);
  368         }
  369         if (pcmcia_function_enable(pf) != 0) {
  370                 printf("%s: couldn't enable card\n", sc->sc_dev.dv_xname);
  371                 pcmcia_intr_disestablish(pf, sc->sc_ih);
  372                 return (EIO);
  373         }
  374         DELAY(1000);
  375         if (psc->sc_symbol_cf) {
  376                 if (wi_pcmcia_load_firm(sc,
  377                     spectrum24t_primsym, sizeof(spectrum24t_primsym),
  378                     spectrum24t_secsym, sizeof(spectrum24t_secsym))) {
  379                         printf("%s: couldn't load firmware\n",
  380                             sc->sc_dev.dv_xname);
  381                         wi_pcmcia_disable(sc);
  382                         return (EIO);
  383                 }
  384         }
  385         return (0);
  386 }
  387 
  388 static void
  389 wi_pcmcia_disable(sc)
  390         struct wi_softc *sc;
  391 {
  392         struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)sc;
  393 
  394         pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
  395         pcmcia_function_disable(psc->sc_pf);
  396 }
  397 
  398 static int
  399 wi_pcmcia_find(psc, pa, cfe)
  400         struct wi_pcmcia_softc *psc;
  401         struct pcmcia_attach_args *pa;
  402         struct pcmcia_config_entry *cfe;
  403 {
  404         struct wi_softc *sc = &psc->sc_wi;
  405 
  406         /* Allocate/map I/O space. */
  407         if (pcmcia_io_alloc(psc->sc_pf, cfe->iospace[0].start,
  408             cfe->iospace[0].length, WI_IOSIZE, &psc->sc_pcioh) != 0) {
  409                 printf("%s: can't allocate i/o space\n", sc->sc_dev.dv_xname);
  410                 goto fail1;
  411         }
  412         if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0,
  413             psc->sc_pcioh.size, &psc->sc_pcioh, &psc->sc_io_window) != 0) {
  414                 printf("%s: can't map i/o space\n", sc->sc_dev.dv_xname);
  415                 goto fail2;
  416         }
  417         /* Enable the card */
  418         pcmcia_function_init(psc->sc_pf, cfe);
  419         if (pcmcia_function_enable(psc->sc_pf)) {
  420                 printf("%s: function enable failed\n", sc->sc_dev.dv_xname);
  421                 goto fail3;
  422         }
  423         
  424         sc->sc_iot = psc->sc_pcioh.iot;
  425         sc->sc_ioh = psc->sc_pcioh.ioh;
  426 
  427         DELAY(1000);
  428         return(0);
  429 
  430 fail3:
  431         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  432 fail2:
  433         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  434 fail1:
  435         psc->sc_io_window = -1;
  436         return(1);
  437 }
  438 
  439 static void
  440 wi_pcmcia_attach(parent, self, aux)
  441         struct device  *parent, *self;
  442         void           *aux;
  443 {
  444         struct wi_pcmcia_softc *psc = (void *)self;
  445         struct wi_softc *sc = &psc->sc_wi;
  446         const struct wi_pcmcia_product *pp;
  447         struct pcmcia_attach_args *pa = aux;
  448         struct pcmcia_config_entry *cfe;
  449         char devinfo[256];
  450 
  451         /* Print out what we are. */
  452         pcmcia_devinfo(&pa->pf->sc->card, 0, devinfo, sizeof(devinfo));
  453         printf(": %s\n", devinfo);
  454 
  455         psc->sc_pf = pa->pf;
  456 
  457         SIMPLEQ_FOREACH(cfe, &pa->pf->cfe_head, cfe_list) {
  458                 if (cfe->iftype != PCMCIA_IFTYPE_IO)
  459                         continue;
  460                 if (cfe->iospace[0].length < WI_IOSIZE)
  461                         continue;
  462                 if (wi_pcmcia_find(psc, pa, cfe) == 0)
  463                         break;
  464         }
  465         if (cfe == NULL) {
  466                 printf(": no suitable CIS info found\n");
  467                 goto no_config_entry;
  468         }
  469 
  470         pp = wi_pcmcia_lookup(pa);
  471         if (pp == NULL)
  472                 panic("wi_pcmcia_attach: impossible");
  473 
  474         sc->sc_pci = 0;
  475         sc->sc_enabled = 1;
  476         sc->sc_enable = wi_pcmcia_enable;
  477         sc->sc_disable = wi_pcmcia_disable;
  478         if (pp->pp_vendor == PCMCIA_VENDOR_SYMBOL &&
  479             pp->pp_product == PCMCIA_PRODUCT_SYMBOL_LA4100)
  480                 psc->sc_symbol_cf = 1;
  481         /*
  482          * XXX: Sony PEGA-WL100 CF card has a same vendor/product id as
  483          *      Intel PCMCIA card.  It may be incorrect to detect by the
  484          *      initial value of COR register.
  485          */
  486         if (pp->pp_vendor == PCMCIA_VENDOR_INTEL &&
  487             pp->pp_product == PCMCIA_PRODUCT_INTEL_PRO_WLAN_2011 &&
  488             CSR_READ_2(sc, WI_COR) == WI_COR_IOMODE)
  489                 psc->sc_symbol_cf = 1;
  490 
  491         if (psc->sc_symbol_cf) {
  492                 if (wi_pcmcia_load_firm(sc,
  493                     spectrum24t_primsym, sizeof(spectrum24t_primsym),
  494                     spectrum24t_secsym, sizeof(spectrum24t_secsym))) {
  495                         printf("%s: couldn't load firmware\n",
  496                                 sc->sc_dev.dv_xname);
  497                         goto no_interrupt;
  498                 }
  499         }
  500 
  501         /* establish the interrupt. */
  502         sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, wi_intr, sc);
  503         if (sc->sc_ih == NULL) {
  504                 printf("%s: couldn't establish interrupt\n",
  505                         sc->sc_dev.dv_xname);
  506                 goto no_interrupt;
  507         }
  508 
  509         printf("%s:", sc->sc_dev.dv_xname);
  510         if (wi_attach(sc) != 0) {
  511                 printf("%s: failed to attach controller\n",
  512                     sc->sc_dev.dv_xname);
  513                         goto attach_failed;
  514         }
  515 
  516         psc->sc_sdhook    = shutdownhook_establish(wi_pcmcia_shutdown, psc);
  517         psc->sc_powerhook = powerhook_establish(wi_pcmcia_powerhook, psc);
  518 
  519         /* disable the card */
  520         sc->sc_enabled = 0;
  521         wi_pcmcia_disable(sc);
  522 
  523         return;
  524 
  525 attach_failed:
  526         pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
  527 no_interrupt:
  528         pcmcia_function_disable(psc->sc_pf);
  529         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  530         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  531 no_config_entry:
  532         psc->sc_io_window = -1;
  533 }
  534 
  535 static int
  536 wi_pcmcia_detach(self, flags)
  537         struct device *self;
  538         int flags;
  539 {
  540         struct wi_pcmcia_softc *psc = (struct wi_pcmcia_softc *)self;
  541         int error;
  542 
  543         if (psc->sc_io_window == -1)
  544                 /* Nothing to detach. */
  545                 return (0);
  546 
  547         if (psc->sc_powerhook != NULL)
  548                 powerhook_disestablish(psc->sc_powerhook);
  549         if (psc->sc_sdhook != NULL)
  550                 shutdownhook_disestablish(psc->sc_sdhook);
  551 
  552         error = wi_detach(&psc->sc_wi);
  553         if (error != 0)
  554                 return (error);
  555 
  556         /* Unmap our i/o window. */
  557         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  558 
  559         /* Free our i/o space. */
  560         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  561         return (0);
  562 }
  563 
  564 static void
  565 wi_pcmcia_powerhook(why, arg)
  566         int why;
  567         void *arg;
  568 {
  569         struct wi_pcmcia_softc *psc = arg;
  570         struct wi_softc *sc = &psc->sc_wi;
  571 
  572         wi_power(sc, why);
  573 }
  574 
  575 static void
  576 wi_pcmcia_shutdown(arg)
  577         void *arg;
  578 {
  579         struct wi_pcmcia_softc *psc = arg;
  580         struct wi_softc *sc = &psc->sc_wi;
  581 
  582         wi_shutdown(sc);  
  583 }
  584 
  585 /*
  586  * Special routines to download firmware for Symbol CF card.
  587  * XXX: This should be modified generic into any PRISM-2 based card.
  588  */
  589 
  590 #define WI_SBCF_PDIADDR         0x3100
  591 
  592 /* unaligned load little endian */
  593 #define GETLE32(p)      ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
  594 #define GETLE16(p)      ((p)[0] | ((p)[1]<<8))
  595 
  596 static int
  597 wi_pcmcia_load_firm(sc, primsym, primlen, secsym, seclen)
  598         struct wi_softc *sc;
  599         const void *primsym, *secsym;
  600         int primlen, seclen;
  601 {
  602         u_int8_t ebuf[256];
  603         int i;
  604 
  605         /* load primary code and run it */
  606         wi_pcmcia_set_hcr(sc, WI_HCR_EEHOLD);
  607         if (wi_pcmcia_write_firm(sc, primsym, primlen, NULL, 0))
  608                 return EIO;
  609         wi_pcmcia_set_hcr(sc, WI_HCR_RUN);
  610         for (i = 0; ; i++) {
  611                 if (i == 10)
  612                         return ETIMEDOUT;
  613                 tsleep(sc, PWAIT, "wiinit", 1);
  614                 if (CSR_READ_2(sc, WI_CNTL) == WI_CNTL_AUX_ENA_STAT)
  615                         break;
  616                 /* write the magic key value to unlock aux port */
  617                 CSR_WRITE_2(sc, WI_PARAM0, WI_AUX_KEY0);
  618                 CSR_WRITE_2(sc, WI_PARAM1, WI_AUX_KEY1);
  619                 CSR_WRITE_2(sc, WI_PARAM2, WI_AUX_KEY2);
  620                 CSR_WRITE_2(sc, WI_CNTL, WI_CNTL_AUX_ENA_CNTL);
  621         }
  622 
  623         /* issue read EEPROM command: XXX copied from wi_cmd() */
  624         CSR_WRITE_2(sc, WI_PARAM0, 0);
  625         CSR_WRITE_2(sc, WI_PARAM1, 0);
  626         CSR_WRITE_2(sc, WI_PARAM2, 0);
  627         CSR_WRITE_2(sc, WI_COMMAND, WI_CMD_READEE);
  628         for (i = 0; i < WI_TIMEOUT; i++) {
  629                 if (CSR_READ_2(sc, WI_EVENT_STAT) & WI_EV_CMD)
  630                         break;
  631                 DELAY(1);
  632         }
  633         CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD);
  634 
  635         CSR_WRITE_2(sc, WI_AUX_PAGE, WI_SBCF_PDIADDR / WI_AUX_PGSZ);
  636         CSR_WRITE_2(sc, WI_AUX_OFFSET, WI_SBCF_PDIADDR % WI_AUX_PGSZ);
  637         CSR_READ_MULTI_STREAM_2(sc, WI_AUX_DATA,
  638             (u_int16_t *)ebuf, sizeof(ebuf) / 2);
  639         if (GETLE16(ebuf) > sizeof(ebuf))
  640                 return EIO;
  641         if (wi_pcmcia_write_firm(sc, secsym, seclen, ebuf + 4, GETLE16(ebuf)))
  642                 return EIO;
  643         return 0;
  644 }
  645 
  646 static int
  647 wi_pcmcia_write_firm(sc, buf, buflen, ebuf, ebuflen)
  648         struct wi_softc *sc;
  649         const void *buf, *ebuf;
  650         int buflen, ebuflen;
  651 {
  652         const u_int8_t *p, *ep, *q, *eq;
  653         u_int32_t addr, id, eid;
  654         int i, len, elen, nblk, pdrlen;
  655 
  656         /*
  657          * Parse the header of the firmware image.
  658          */
  659         p = buf;
  660         ep = p + buflen;
  661         while (p < ep && *p++ != ' ');  /* FILE: */
  662         while (p < ep && *p++ != ' ');  /* filename */
  663         while (p < ep && *p++ != ' ');  /* type of the firmware */
  664         nblk = strtoul(p, (void *)&p, 10);
  665         pdrlen = strtoul(p + 1, (void *)&p, 10);
  666         while (p < ep && *p++ != 0x1a); /* skip rest of header */
  667 
  668         /*
  669          * Block records: address[4], length[2], data[length];
  670          */
  671         for (i = 0; i < nblk; i++) {
  672                 addr = GETLE32(p);      p += 4;
  673                 len  = GETLE16(p);      p += 2;
  674                 CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
  675                 CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
  676                 CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
  677                     (const u_int16_t *)p, len / 2);
  678                 p += len;
  679         }
  680         
  681         /*
  682          * PDR: id[4], address[4], length[4];
  683          */
  684         for (i = 0; i < pdrlen; ) {
  685                 id   = GETLE32(p);      p += 4; i += 4;
  686                 addr = GETLE32(p);      p += 4; i += 4;
  687                 len  = GETLE32(p);      p += 4; i += 4;
  688                 /* replace PDR entry with the values from EEPROM, if any */
  689                 for (q = ebuf, eq = q + ebuflen; q < eq; q += elen * 2) {
  690                         elen = GETLE16(q);      q += 2;
  691                         eid  = GETLE16(q);      q += 2;
  692                         elen--;         /* elen includes eid */
  693                         if (eid == 0)
  694                                 break;
  695                         if (eid != id)
  696                                 continue;
  697                         CSR_WRITE_2(sc, WI_AUX_PAGE, addr / WI_AUX_PGSZ);
  698                         CSR_WRITE_2(sc, WI_AUX_OFFSET, addr % WI_AUX_PGSZ);
  699                         CSR_WRITE_MULTI_STREAM_2(sc, WI_AUX_DATA,
  700                             (const u_int16_t *)q, len / 2);
  701                         break;
  702                 }
  703         }
  704         return 0;
  705 }
  706 
  707 static int
  708 wi_pcmcia_set_hcr(sc, mode)
  709         struct wi_softc *sc;
  710         int mode;
  711 {
  712         u_int16_t hcr;
  713 
  714         CSR_WRITE_2(sc, WI_COR, WI_COR_RESET);
  715         tsleep(sc, PWAIT, "wiinit", 1);
  716         hcr = CSR_READ_2(sc, WI_HCR);
  717         hcr = (hcr & WI_HCR_4WIRE) | (mode & ~WI_HCR_4WIRE);
  718         CSR_WRITE_2(sc, WI_HCR, hcr);
  719         tsleep(sc, PWAIT, "wiinit", 1);
  720         CSR_WRITE_2(sc, WI_COR, WI_COR_IOMODE);
  721         tsleep(sc, PWAIT, "wiinit", 1);
  722         return 0;
  723 }

Cache object: 742d10bf9bcebc4096b024b164332580


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.