root/dev/pcmcia/if_awi_pcmcia.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. awi_pcmcia_lookup
  2. awi_pcmcia_enable
  3. awi_pcmcia_disable
  4. awi_pcmcia_match
  5. awi_pcmcia_find
  6. awi_pcmcia_attach
  7. awi_pcmcia_detach
  8. awi_pcmcia_powerhook

    1 /* $NetBSD: if_awi_pcmcia.c,v 1.13 2000/03/22 11:22:20 onoe Exp $ */
    2 /* $OpenBSD: if_awi_pcmcia.c,v 1.16 2005/11/21 18:16:42 millert Exp $ */
    3 
    4 /*-
    5  * Copyright (c) 1999 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Bill Sommerfeld
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. All advertising materials mentioning features or use of this software
   20  *    must display the following acknowledgement:
   21  *        This product includes software developed by the NetBSD
   22  *        Foundation, Inc. and its contributors.
   23  * 4. Neither the name of The NetBSD Foundation nor the names of its
   24  *    contributors may be used to endorse or promote products derived
   25  *    from this software without specific prior written permission.
   26  *
   27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 /*
   41  * PCMCIA attachment for BayStack 650 802.11FH PCMCIA card,
   42  * based on the AMD 79c930 802.11 controller chip.
   43  *
   44  * This attachment can probably be trivially adapted for other FH and
   45  * DS cards based on the same chipset.
   46  */
   47 
   48 #include "bpfilter.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/mbuf.h>
   53 #include <sys/socket.h>
   54 #include <sys/ioctl.h>
   55 #include <sys/errno.h>
   56 #include <sys/syslog.h>
   57 #include <sys/selinfo.h>
   58 #include <sys/device.h>
   59 
   60 #include <net/if.h>
   61 #include <net/if_dl.h>
   62 #include <net/if_media.h>
   63 
   64 #include <netinet/in.h>
   65 #include <netinet/if_ether.h>
   66 
   67 #include <net80211/ieee80211.h>
   68 #include <net80211/ieee80211_ioctl.h>
   69 
   70 #if NBPFILTER > 0
   71 #include <net/bpf.h>
   72 #endif
   73 
   74 #include <machine/cpu.h>
   75 #include <machine/bus.h>
   76 #include <machine/intr.h>
   77 
   78 #include <dev/ic/am79c930reg.h>
   79 #include <dev/ic/am79c930var.h>
   80 #include <dev/ic/awireg.h>
   81 #include <dev/ic/awivar.h>
   82 
   83 #include <dev/pcmcia/pcmciareg.h>
   84 #include <dev/pcmcia/pcmciavar.h>
   85 #include <dev/pcmcia/pcmciadevs.h>
   86 
   87 struct awi_pcmcia_softc {
   88         struct awi_softc sc_awi;                /* real "awi" softc */
   89 
   90         /* PCMCIA-specific goo */
   91         struct pcmcia_io_handle sc_pcioh;       /* PCMCIA i/o space info */
   92         struct pcmcia_mem_handle sc_memh;       /* PCMCIA memory space info */
   93         int sc_io_window;                       /* our i/o window */
   94         int sc_mem_window;                      /* our memory window */
   95         struct pcmcia_function *sc_pf;          /* our PCMCIA function */
   96         void *sc_powerhook;                     /* power hook descriptor */
   97 };
   98 
   99 static int awi_pcmcia_match(struct device *, void *, void *);
  100 static void awi_pcmcia_attach(struct device *, struct device *, void *);
  101 static int awi_pcmcia_detach(struct device *, int);
  102 static int awi_pcmcia_enable(struct awi_softc *);
  103 static void awi_pcmcia_disable(struct awi_softc *);
  104 static void awi_pcmcia_powerhook(int, void *);
  105 
  106 static int      awi_pcmcia_find(struct awi_pcmcia_softc *,
  107     struct pcmcia_attach_args *, struct pcmcia_config_entry *);
  108 
  109 struct cfattach awi_pcmcia_ca = {
  110         sizeof(struct awi_pcmcia_softc), awi_pcmcia_match, awi_pcmcia_attach,
  111         awi_pcmcia_detach, awi_activate
  112 };
  113 
  114 static struct awi_pcmcia_product {
  115         u_int16_t       app_vendor;     /* vendor ID */
  116         u_int16_t       app_product;    /* product ID */
  117         const char      *app_cisinfo[4]; /* CIS information */
  118         const char      *app_name;      /* product name */
  119 } awi_pcmcia_products[] = {
  120         { PCMCIA_VENDOR_BAY,            PCMCIA_PRODUCT_BAY_STACK_650,
  121           PCMCIA_CIS_BAY_STACK_650,     "BayStack 650" },
  122 
  123         { PCMCIA_VENDOR_BAY,            PCMCIA_PRODUCT_BAY_STACK_660,
  124           PCMCIA_CIS_BAY_STACK_660,     "BayStack 660" },
  125 
  126         { PCMCIA_VENDOR_BAY,            PCMCIA_PRODUCT_BAY_SURFER_PRO,
  127           PCMCIA_CIS_BAY_SURFER_PRO,    "AirSurfer Pro" },
  128 
  129         { PCMCIA_VENDOR_AMD,            PCMCIA_PRODUCT_AMD_AM79C930,
  130           PCMCIA_CIS_AMD_AM79C930,      "AMD AM79C930" },
  131 
  132         { PCMCIA_VENDOR_ICOM,           PCMCIA_PRODUCT_ICOM_SL200,
  133           PCMCIA_CIS_ICOM_SL200,        "Icom SL-200" },
  134 
  135         { PCMCIA_VENDOR_NOKIA,          PCMCIA_PRODUCT_NOKIA_C020_WLAN,
  136           PCMCIA_CIS_NOKIA_C020_WLAN,   "Nokia C020" },
  137 
  138         { PCMCIA_VENDOR_FARALLON,       PCMCIA_PRODUCT_FARALLON_SKYLINE,
  139           PCMCIA_CIS_FARALLON_SKYLINE,  "SkyLINE Wireless" },
  140 
  141         { PCMCIA_VENDOR_ZOOM,           PCMCIA_PRODUCT_ZOOM_AIR4000,
  142           PCMCIA_CIS_ZOOM_AIR4000,      "Zoom Air-4000" },
  143 
  144 /*      { PCMCIA_VENDOR_BREEZECOM,      PCMCIA_PRODUCT_BREEZECOM_BREEZENET,
  145           PCMCIA_CIS_BREEZECOM_BREEZENET,       "BreezeNet SC-PX" },
  146 */
  147         { 0,                            0,
  148           { NULL, NULL, NULL, NULL },   NULL },
  149 };
  150 
  151 static struct awi_pcmcia_product *
  152         awi_pcmcia_lookup(struct pcmcia_attach_args *);
  153 
  154 static struct awi_pcmcia_product *
  155 awi_pcmcia_lookup(pa)
  156         struct pcmcia_attach_args *pa;
  157 {
  158         struct awi_pcmcia_product *app;
  159 
  160         for (app = awi_pcmcia_products; app->app_name != NULL; app++) {
  161                 /* match by vendor/product id */
  162                 if (pa->manufacturer != PCMCIA_VENDOR_INVALID &&
  163                     pa->manufacturer == app->app_vendor &&
  164                     pa->product != PCMCIA_PRODUCT_INVALID &&
  165                     pa->product == app->app_product)
  166                         return (app);
  167 
  168                 /* match by CIS information */
  169                 if (pa->card->cis1_info[0] != NULL &&
  170                     app->app_cisinfo[0] != NULL &&
  171                     strcmp(pa->card->cis1_info[0], app->app_cisinfo[0]) == 0 &&
  172                     pa->card->cis1_info[1] != NULL &&
  173                     app->app_cisinfo[1] != NULL &&
  174                     strcmp(pa->card->cis1_info[1], app->app_cisinfo[1]) == 0)
  175                         return (app);
  176         }
  177 
  178         return (NULL);
  179 }
  180 
  181 static int
  182 awi_pcmcia_enable(sc)
  183         struct awi_softc *sc;
  184 {
  185         struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc;
  186         struct pcmcia_function *pf = psc->sc_pf;
  187 
  188         /* establish the interrupt. */
  189         sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, awi_intr,
  190             sc, sc->sc_dev.dv_xname);
  191         if (sc->sc_ih == NULL) {
  192                 printf("%s: couldn't establish interrupt\n",
  193                     sc->sc_dev.dv_xname);
  194                 return (1);
  195         }
  196 
  197         if (pcmcia_function_enable(pf)) {
  198                 pcmcia_intr_disestablish(pf, sc->sc_ih);
  199                 return (1);
  200         }
  201         DELAY(1000);
  202 
  203         return (0);
  204 }
  205 
  206 static void
  207 awi_pcmcia_disable(sc)
  208         struct awi_softc *sc;
  209 {
  210         struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)sc;
  211         struct pcmcia_function *pf = psc->sc_pf;
  212 
  213         pcmcia_intr_disestablish (pf, sc->sc_ih);
  214         pcmcia_function_disable (pf);
  215 }
  216 
  217 static int
  218 awi_pcmcia_match(parent, match, aux)
  219         struct device *parent;
  220         void *match;
  221         void *aux;
  222 {
  223         struct pcmcia_attach_args *pa = aux;
  224 
  225         if (awi_pcmcia_lookup(pa) != NULL)
  226                 return (1);
  227 
  228         return (0);
  229 }
  230 
  231 static int
  232 awi_pcmcia_find(psc, pa, cfe)
  233         struct awi_pcmcia_softc *psc;
  234         struct pcmcia_attach_args *pa;
  235         struct pcmcia_config_entry *cfe;
  236 {
  237         struct awi_softc *sc = &psc->sc_awi;
  238         int fail = 0;
  239         u_int8_t version[AWI_BANNER_LEN];
  240 
  241         /*
  242          * see if we can read the firmware version sanely
  243          * through the i/o ports.
  244          * if not, try a different CIS string..
  245          */
  246         if (pcmcia_io_alloc(psc->sc_pf, cfe->iospace[0].start,
  247             cfe->iospace[0].length, AM79C930_IO_ALIGN,
  248             &psc->sc_pcioh) != 0)
  249                 goto fail;
  250 
  251         if (pcmcia_io_map(psc->sc_pf, PCMCIA_WIDTH_AUTO, 0, psc->sc_pcioh.size,
  252             &psc->sc_pcioh, &psc->sc_io_window))
  253                 goto fail_io_free;
  254 
  255         /* Enable the card. */
  256         pcmcia_function_init(psc->sc_pf, cfe);
  257         if (pcmcia_function_enable(psc->sc_pf))
  258                 goto fail_io_unmap;
  259 
  260         sc->sc_chip.sc_bustype = AM79C930_BUS_PCMCIA;
  261         sc->sc_chip.sc_iot = psc->sc_pcioh.iot;
  262         sc->sc_chip.sc_ioh = psc->sc_pcioh.ioh;
  263         am79c930_chip_init(&sc->sc_chip, 0);
  264 
  265         DELAY(1000);
  266 
  267         awi_read_bytes(sc, AWI_BANNER, version, AWI_BANNER_LEN);
  268 
  269         if (memcmp(version, "PCnetMobile:", 12) == 0)
  270                 return (0);
  271 
  272         fail++;
  273         pcmcia_function_disable(psc->sc_pf);
  274 
  275  fail_io_unmap:
  276         fail++;
  277         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  278 
  279  fail_io_free:
  280         fail++;
  281         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  282  fail:
  283         fail++;
  284         psc->sc_io_window = -1;
  285         return (fail);
  286 }
  287 
  288 static void
  289 awi_pcmcia_attach(parent, self, aux)
  290         struct device  *parent, *self;
  291         void           *aux;
  292 {
  293         struct awi_pcmcia_softc *psc = (void *)self;
  294         struct awi_softc *sc = &psc->sc_awi;
  295         struct awi_pcmcia_product *app;
  296         struct pcmcia_attach_args *pa = aux;
  297         struct pcmcia_config_entry *cfe;
  298         const char *intrstr;
  299 #if 0
  300         bus_addr_t memoff;
  301 #endif
  302 
  303         app = awi_pcmcia_lookup(pa);
  304         if (app == NULL)
  305                 panic("awi_pcmcia_attach: impossible");
  306 
  307         psc->sc_pf = pa->pf;
  308 
  309         for (cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head); cfe != NULL;
  310              cfe = SIMPLEQ_NEXT(cfe, cfe_list)) {
  311                 if (cfe->iftype != PCMCIA_IFTYPE_IO)
  312                         continue;
  313                 if (cfe->num_iospace < 1)
  314                         continue;
  315                 if (cfe->iospace[0].length < AM79C930_IO_SIZE)
  316                         continue;
  317 
  318                 if (awi_pcmcia_find(psc, pa, cfe) == 0)
  319                         break;
  320         }
  321         if (cfe == NULL) {
  322                 printf(": no suitable CIS info found\n");
  323                 goto no_config_entry;
  324         }
  325 
  326         sc->sc_enabled = 1;
  327         printf(": %s\n", app->app_name);
  328 
  329         psc->sc_mem_window = -1;
  330 #if 0   /* if memory mode is disabled it futhers futher */
  331         if (pcmcia_mem_alloc(psc->sc_pf, AM79C930_MEM_SIZE,
  332             &psc->sc_memh) != 0) {
  333                 printf("%s: unable to allocate memory space; using i/o only\n",
  334                     sc->sc_dev.dv_xname);
  335         } else if (pcmcia_mem_map(psc->sc_pf,
  336             PCMCIA_MEM_COMMON, AM79C930_MEM_BASE,
  337             AM79C930_MEM_SIZE, &psc->sc_memh, &memoff, &psc->sc_mem_window)) {
  338                 printf("%s: unable to map memory space; using i/o only\n",
  339                     sc->sc_dev.dv_xname);
  340                 pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
  341         } else {
  342                 sc->sc_chip.sc_memt = psc->sc_memh.memt;
  343                 sc->sc_chip.sc_memh = psc->sc_memh.memh;
  344                 am79c930_chip_init(&sc->sc_chip, 1);
  345         }
  346 #endif
  347 
  348         sc->sc_enable = awi_pcmcia_enable;
  349         sc->sc_disable = awi_pcmcia_disable;
  350 
  351         /* establish the interrupt. */
  352         sc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
  353             awi_intr, sc, sc->sc_dev.dv_xname);
  354         intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
  355         if (sc->sc_ih == NULL) {
  356                 printf(", %s\n", intrstr);
  357                 goto no_interrupt;
  358         }
  359         if (*intrstr)
  360                 printf(", %s", intrstr);
  361         sc->sc_ifp = &sc->sc_arpcom.ac_if;
  362         sc->sc_cansleep = 1;
  363 
  364         if (awi_attach(sc) != 0) {
  365                 printf("%s: failed to attach controller\n",
  366                     sc->sc_dev.dv_xname);
  367                 goto attach_failed;
  368         }
  369         psc->sc_powerhook = powerhook_establish(awi_pcmcia_powerhook, psc);
  370 
  371         sc->sc_enabled = 0;
  372         /* disable device and disestablish the interrupt */
  373         awi_pcmcia_disable(sc);
  374         return;
  375 
  376  attach_failed:
  377         pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
  378 
  379  no_interrupt:
  380         /* Unmap our memory window and space */
  381         if (psc->sc_mem_window != -1) {
  382                 pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window);
  383                 pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
  384         }
  385 
  386         /* Unmap our i/o window and space */
  387         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  388         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  389 
  390         /* Disable the function */
  391         pcmcia_function_disable(psc->sc_pf);
  392 
  393  no_config_entry:
  394         psc->sc_io_window = -1;
  395 }
  396 
  397 
  398 static int
  399 awi_pcmcia_detach(self, flags)
  400         struct device *self;
  401         int flags;
  402 {
  403         struct awi_pcmcia_softc *psc = (struct awi_pcmcia_softc *)self;
  404         int error;
  405 
  406         if (psc->sc_io_window == -1)
  407                 /* Nothing to detach. */
  408                 return (0);
  409 
  410         if (psc->sc_powerhook != NULL)
  411                 powerhook_disestablish(psc->sc_powerhook);
  412 
  413         error = awi_detach(&psc->sc_awi);
  414         if (error != 0)
  415                 return (error);
  416 
  417         /* Unmap our memory window and free memory space */
  418         if (psc->sc_mem_window != -1) {
  419                 pcmcia_mem_unmap(psc->sc_pf, psc->sc_mem_window);
  420                 pcmcia_mem_free(psc->sc_pf, &psc->sc_memh);
  421         }
  422 
  423         /* Unmap our i/o window. */
  424         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  425 
  426         /* Free our i/o space. */
  427         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  428         return (0);
  429 }
  430 
  431 static void
  432 awi_pcmcia_powerhook(why, arg)
  433         int why;
  434         void *arg;
  435 {
  436         struct awi_pcmcia_softc *psc = arg;
  437         struct awi_softc *sc = &psc->sc_awi;
  438 
  439         awi_power(sc, why);
  440 }

/* [<][>][^][v][top][bottom][index][help] */