root/dev/pcmcia/if_sm_pcmcia.c

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

DEFINITIONS

This source file includes following definitions.
  1. sm_pcmcia_match
  2. sm_pcmcia_attach
  3. sm_pcmcia_detach
  4. sm_pcmcia_activate
  5. sm_pcmcia_ascii_enaddr
  6. sm_pcmcia_funce_enaddr
  7. sm_pcmcia_lannid_ciscallback
  8. sm_pcmcia_enable
  9. sm_pcmcia_disable

    1 /*      $OpenBSD: if_sm_pcmcia.c,v 1.27 2006/06/17 18:01:52 brad Exp $  */
    2 /*      $NetBSD: if_sm_pcmcia.c,v 1.11 1998/08/15 20:47:32 thorpej Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   10  * NASA Ames Research Center.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the NetBSD
   23  *      Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 #include "bpfilter.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/socket.h>
   47 #include <sys/ioctl.h>
   48 #include <sys/errno.h>
   49 #include <sys/syslog.h>
   50 #include <sys/selinfo.h>
   51 #include <sys/timeout.h>
   52 #include <sys/device.h>
   53 
   54 #include <net/if.h>
   55 #include <net/if_dl.h>
   56 #include <net/if_media.h>
   57 
   58 #ifdef INET
   59 #include <netinet/in.h>
   60 #include <netinet/in_systm.h>
   61 #include <netinet/in_var.h>
   62 #include <netinet/ip.h>
   63 #include <netinet/if_ether.h>
   64 #endif
   65 
   66 #if NBPFILTER > 0
   67 #include <net/bpf.h>
   68 #endif
   69 
   70 #include <machine/intr.h>
   71 #include <machine/bus.h>
   72 
   73 #include <net/if_media.h>
   74 
   75 #include <dev/mii/mii.h>
   76 #include <dev/mii/miivar.h>
   77 
   78 #include <dev/ic/smc91cxxreg.h>
   79 #include <dev/ic/smc91cxxvar.h>
   80 
   81 #include <dev/pcmcia/pcmciareg.h>
   82 #include <dev/pcmcia/pcmciavar.h>
   83 #include <dev/pcmcia/pcmciadevs.h>
   84 
   85 int     sm_pcmcia_match(struct device *, void *, void *);
   86 void    sm_pcmcia_attach(struct device *, struct device *, void *);
   87 int     sm_pcmcia_detach(struct device *, int);
   88 int     sm_pcmcia_activate(struct device *, enum devact);
   89 
   90 struct sm_pcmcia_softc {
   91         struct  smc91cxx_softc sc_smc;          /* real "smc" softc */
   92 
   93         /* PCMCIA-specific goo. */
   94         struct  pcmcia_io_handle sc_pcioh;      /* PCMCIA i/o space info */
   95         int     sc_io_window;                   /* our i/o window */
   96         void    *sc_ih;                         /* interrupt cookie */
   97         struct  pcmcia_function *sc_pf;         /* our PCMCIA function */
   98 };
   99 
  100 struct cfattach sm_pcmcia_ca = {
  101         sizeof(struct sm_pcmcia_softc), sm_pcmcia_match, sm_pcmcia_attach,
  102         sm_pcmcia_detach, sm_pcmcia_activate
  103 };
  104 
  105 int     sm_pcmcia_enable(struct smc91cxx_softc *);
  106 void    sm_pcmcia_disable(struct smc91cxx_softc *);
  107 
  108 int     sm_pcmcia_ascii_enaddr(const char *, u_int8_t *);
  109 int     sm_pcmcia_funce_enaddr(struct device *, u_int8_t *);
  110 
  111 int     sm_pcmcia_lannid_ciscallback(struct pcmcia_tuple *, void *);
  112 
  113 struct sm_pcmcia_product {
  114         u_int16_t       spp_vendor;     /* vendor ID */
  115         u_int16_t       spp_product;    /* product ID */
  116         int             spp_expfunc;    /* expected function */
  117 } sm_pcmcia_prod[] = {
  118         { PCMCIA_VENDOR_MEGAHERTZ2,     PCMCIA_PRODUCT_MEGAHERTZ2_XJACK,
  119           0 },
  120         { PCMCIA_VENDOR_MEGAHERTZ2,     PCMCIA_PRODUCT_MEGAHERTZ2_XJEM1144,
  121           0 },
  122         { PCMCIA_VENDOR_NEWMEDIA,       PCMCIA_PRODUCT_NEWMEDIA_BASICS,
  123           0 },
  124         { PCMCIA_VENDOR_SMC,            PCMCIA_PRODUCT_SMC_8020,
  125           0 },
  126         { PCMCIA_VENDOR_PSION,          PCMCIA_PRODUCT_PSION_GOLDCARD,
  127           0 }
  128 };
  129 
  130 int
  131 sm_pcmcia_match(parent, match, aux)
  132         struct device *parent;
  133         void *match, *aux;
  134 {
  135         struct pcmcia_attach_args *pa = aux;
  136         int i;
  137 
  138         for (i = 0; i < sizeof(sm_pcmcia_prod)/sizeof(sm_pcmcia_prod[0]); i++)
  139                 if (pa->manufacturer == sm_pcmcia_prod[i].spp_vendor &&
  140                     pa->product == sm_pcmcia_prod[i].spp_product &&
  141                     pa->pf->number == sm_pcmcia_prod[i].spp_expfunc)
  142                         return (1);
  143         return (0);
  144 }
  145 
  146 void
  147 sm_pcmcia_attach(parent, self, aux)
  148         struct device *parent, *self;
  149         void *aux;
  150 {
  151         struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)self;
  152         struct smc91cxx_softc *sc = &psc->sc_smc;
  153         struct pcmcia_attach_args *pa = aux;
  154         struct pcmcia_config_entry *cfe;
  155         u_int8_t myla[ETHER_ADDR_LEN], *enaddr = NULL;
  156         const char *intrstr;
  157 
  158         psc->sc_pf = pa->pf;
  159         cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
  160 
  161         /* Enable the card. */
  162         pcmcia_function_init(pa->pf, cfe);
  163         if (pcmcia_function_enable(pa->pf)) {
  164                 printf(": function enable failed\n");
  165                 return;
  166         }
  167 
  168         /* XXX sanity check number of mem and i/o spaces */
  169 
  170         /* Allocate and map i/o space for the card. */
  171         if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
  172             cfe->iospace[0].length, &psc->sc_pcioh)) {
  173                 printf(": can't allocate i/o space\n");
  174                 return;
  175         }
  176 
  177         sc->sc_bst = psc->sc_pcioh.iot;
  178         sc->sc_bsh = psc->sc_pcioh.ioh;
  179 
  180 #ifdef notyet
  181         sc->sc_enable = sm_pcmcia_enable;
  182         sc->sc_disable = sm_pcmcia_disable;
  183 #endif
  184         sc->sc_enabled = 1;
  185 
  186         if (pcmcia_io_map(pa->pf, (cfe->flags & PCMCIA_CFE_IO16) ?
  187             PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8, 0, cfe->iospace[0].length,
  188             &psc->sc_pcioh, &psc->sc_io_window)) {
  189                 printf(": can't map i/o space\n");
  190                 return;
  191         }
  192 
  193         printf(" port 0x%lx/%lu", psc->sc_pcioh.addr,
  194             (u_long)psc->sc_pcioh.size);
  195 
  196         /*
  197          * First try to get the Ethernet address from FUNCE/LANNID tuple.
  198          */
  199         if (sm_pcmcia_funce_enaddr(parent, myla))
  200                 enaddr = myla;
  201 
  202         /*
  203          * If that failed, try one of the CIS info strings.
  204          */
  205         if (enaddr == NULL) {
  206                 char *cisstr = NULL;
  207 
  208                 switch (pa->manufacturer) {
  209                 case PCMCIA_VENDOR_MEGAHERTZ2:
  210                         cisstr = pa->pf->sc->card.cis1_info[3];
  211                         break;
  212                 case PCMCIA_VENDOR_SMC:
  213                         cisstr = pa->pf->sc->card.cis1_info[2];
  214                         break;
  215                 }
  216                 if (cisstr != NULL && sm_pcmcia_ascii_enaddr(cisstr, myla))
  217                         enaddr = myla;
  218         }
  219 
  220         if (enaddr == NULL)
  221                 printf(", unable to get Ethernet address\n");
  222 
  223         psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET,
  224             smc91cxx_intr, sc, sc->sc_dev.dv_xname);
  225         intrstr = pcmcia_intr_string(psc->sc_pf, psc->sc_ih);
  226         if (*intrstr)
  227                 printf(", %s", intrstr);
  228 
  229         /* Perform generic initialization. */
  230         smc91cxx_attach(sc, enaddr);
  231 
  232 #ifdef notyet
  233         pcmcia_function_disable(pa->pf);
  234 #endif
  235 }
  236 
  237 int
  238 sm_pcmcia_detach(dev, flags)
  239         struct device *dev;
  240         int flags;
  241 {
  242         struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)dev;
  243         struct ifnet *ifp = &psc->sc_smc.sc_arpcom.ac_if;
  244         int rv = 0;
  245 
  246         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  247         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  248 
  249         ether_ifdetach(ifp);
  250         if_detach(ifp);
  251 
  252         return (rv);
  253 }
  254 
  255 int
  256 sm_pcmcia_activate(dev, act)
  257         struct device *dev;
  258         enum devact act;
  259 {
  260         struct sm_pcmcia_softc *sc = (struct sm_pcmcia_softc *)dev;
  261         struct ifnet *ifp = &sc->sc_smc.sc_arpcom.ac_if;
  262         int s;
  263 
  264         s = splnet();
  265         switch (act) {
  266         case DVACT_ACTIVATE:
  267                 pcmcia_function_enable(sc->sc_pf);
  268                 sc->sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
  269                     smc91cxx_intr, sc, sc->sc_smc.sc_dev.dv_xname);
  270                 smc91cxx_init(&sc->sc_smc);
  271                 break;
  272 
  273         case DVACT_DEACTIVATE:
  274                 ifp->if_timer = 0;
  275                 if (ifp->if_flags & IFF_RUNNING)
  276                         smc91cxx_stop(&sc->sc_smc);
  277                 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
  278                 pcmcia_function_disable(sc->sc_pf);
  279                 break;
  280         }
  281         splx(s);
  282         return (0);
  283 }
  284 
  285 int
  286 sm_pcmcia_ascii_enaddr(cisstr, myla)
  287         const char *cisstr;
  288         u_int8_t *myla;
  289 {
  290         char enaddr_str[12];
  291         int i, j;
  292 
  293         if (strlen(cisstr) != 12) {
  294                 /* Bogus address! */
  295                 return (0);
  296         }
  297         bcopy(cisstr, enaddr_str, sizeof enaddr_str);
  298         for (i = 0; i < 6; i++) {
  299                 for (j = 0; j < 2; j++) {
  300                         /* Convert to upper case. */
  301                         if (enaddr_str[(i * 2) + j] >= 'a' &&
  302                             enaddr_str[(i * 2) + j] <= 'z')
  303                                 enaddr_str[(i * 2) + j] -= 'a' - 'A';
  304 
  305                         /* Parse the digit. */
  306                         if (enaddr_str[(i * 2) + j] >= '0' &&
  307                             enaddr_str[(i * 2) + j] <= '9')
  308                                 myla[i] |= enaddr_str[(i * 2) + j]
  309                                     - '0';
  310                         else if (enaddr_str[(i * 2) + j] >= 'A' &&
  311                                  enaddr_str[(i * 2) + j] <= 'F')
  312                                 myla[i] |= enaddr_str[(i * 2) + j]
  313                                     - 'A' + 10;
  314                         else {
  315                                 /* Bogus digit!! */
  316                                 return (0);
  317                         }
  318 
  319                         /* Compensate for ordering of digits. */
  320                         if (j == 0)
  321                                 myla[i] <<= 4;
  322                 }
  323         }
  324 
  325         return (1);
  326 }
  327 
  328 int
  329 sm_pcmcia_funce_enaddr(parent, myla)
  330         struct device *parent;
  331         u_int8_t *myla;
  332 {
  333 
  334         return (pcmcia_scan_cis(parent, sm_pcmcia_lannid_ciscallback, myla));
  335 }
  336 
  337 int
  338 sm_pcmcia_lannid_ciscallback(tuple, arg)
  339         struct pcmcia_tuple *tuple;
  340         void *arg;
  341 {
  342         u_int8_t *myla = arg;
  343         int i;
  344 
  345         if (tuple->code == PCMCIA_CISTPL_FUNCE || tuple->code ==
  346             PCMCIA_CISTPL_SPCL) {
  347                 /* subcode, length */
  348                 if (tuple->length < 2)
  349                         return (0);
  350 
  351                 if ((pcmcia_tuple_read_1(tuple, 0) !=
  352                      PCMCIA_TPLFE_TYPE_LAN_NID) ||
  353                     (pcmcia_tuple_read_1(tuple, 1) != ETHER_ADDR_LEN))
  354                         return (0);
  355 
  356                 for (i = 0; i < ETHER_ADDR_LEN; i++)
  357                         myla[i] = pcmcia_tuple_read_1(tuple, i + 2);
  358                 return (1);
  359         }
  360         return (0);
  361 }
  362 
  363 int
  364 sm_pcmcia_enable(sc)
  365         struct smc91cxx_softc *sc;
  366 {
  367         struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
  368 
  369         /* Establish the interrupt handler. */
  370         psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, smc91cxx_intr,
  371             sc, sc->sc_dev.dv_xname);
  372         if (psc->sc_ih == NULL) {
  373                 printf("%s: couldn't establish interrupt handler\n",
  374                     sc->sc_dev.dv_xname);
  375                 return (1);
  376         }
  377 
  378         return (pcmcia_function_enable(psc->sc_pf));
  379 }
  380 
  381 void
  382 sm_pcmcia_disable(sc)
  383         struct smc91cxx_softc *sc;
  384 {
  385         struct sm_pcmcia_softc *psc = (struct sm_pcmcia_softc *)sc;
  386 
  387         pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
  388         pcmcia_function_disable(psc->sc_pf);
  389 }

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