root/dev/pcmcia/if_ep_pcmcia.c

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

DEFINITIONS

This source file includes following definitions.
  1. ep_pcmcia_lookup
  2. ep_pcmcia_match
  3. ep_pcmcia_enable
  4. ep_pcmcia_enable1
  5. ep_pcmcia_disable
  6. ep_pcmcia_disable1
  7. ep_pcmcia_attach
  8. ep_pcmcia_detach
  9. ep_pcmcia_activate
  10. ep_pcmcia_get_enaddr

    1 /*      $OpenBSD: if_ep_pcmcia.c,v 1.36 2007/05/08 20:25:17 deraadt Exp $       */
    2 /*      $NetBSD: if_ep_pcmcia.c,v 1.16 1998/08/17 23:20:40 thorpej Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 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 /*
   42  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
   43  *
   44  * Redistribution and use in source and binary forms, with or without
   45  * modification, are permitted provided that the following conditions
   46  * are met:
   47  * 1. Redistributions of source code must retain the above copyright
   48  *    notice, this list of conditions and the following disclaimer.
   49  * 2. Redistributions in binary form must reproduce the above copyright
   50  *    notice, this list of conditions and the following disclaimer in the
   51  *    documentation and/or other materials provided with the distribution.
   52  * 3. All advertising materials mentioning features or use of this software
   53  *    must display the following acknowledgement:
   54  *      This product includes software developed by Marc Horowitz.
   55  * 4. The name of the author may not be used to endorse or promote products
   56  *    derived from this software without specific prior written permission.
   57  *
   58  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   59  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   60  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   61  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   62  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   63  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   64  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   65  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   66  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   67  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   68  */
   69 
   70 #include "bpfilter.h"
   71 
   72 #include <sys/param.h>
   73 #include <sys/systm.h>
   74 #include <sys/mbuf.h>
   75 #include <sys/socket.h>
   76 #include <sys/ioctl.h>
   77 #include <sys/errno.h>
   78 #include <sys/syslog.h>
   79 #include <sys/selinfo.h>
   80 #include <sys/timeout.h>
   81 #include <sys/device.h>
   82 
   83 #include <net/if.h>
   84 #include <net/if_dl.h>
   85 #include <net/if_types.h>
   86 #include <net/netisr.h>
   87 #include <net/if_media.h>
   88 
   89 #ifdef INET
   90 #include <netinet/in.h>
   91 #include <netinet/in_systm.h>
   92 #include <netinet/in_var.h>
   93 #include <netinet/ip.h>
   94 #include <netinet/if_ether.h>
   95 #endif
   96 
   97 #if NBPFILTER > 0
   98 #include <net/bpf.h>
   99 #endif
  100 
  101 #include <machine/cpu.h>
  102 #include <machine/bus.h>
  103 
  104 #include <dev/mii/mii.h>
  105 #include <dev/mii/miivar.h>
  106 
  107 #include <dev/ic/elink3var.h>
  108 #include <dev/ic/elink3reg.h>
  109 
  110 #include <dev/pcmcia/pcmciareg.h>
  111 #include <dev/pcmcia/pcmciavar.h>
  112 #include <dev/pcmcia/pcmciadevs.h>
  113 
  114 int     ep_pcmcia_match(struct device *, void *, void *);
  115 void    ep_pcmcia_attach(struct device *, struct device *, void *);
  116 int     ep_pcmcia_detach(struct device *, int);
  117 int     ep_pcmcia_activate(struct device *, enum devact);
  118 
  119 int     ep_pcmcia_get_enaddr(struct pcmcia_tuple *, void *);
  120 #ifdef notyet
  121 int     ep_pcmcia_enable(struct ep_softc *);
  122 void    ep_pcmcia_disable(struct ep_softc *);
  123 void    ep_pcmcia_disable1(struct ep_softc *);
  124 #endif
  125 
  126 int     ep_pcmcia_enable1(struct ep_softc *);
  127 
  128 struct ep_pcmcia_softc {
  129         struct ep_softc sc_ep;                  /* real "ep" softc */
  130 
  131         /* PCMCIA-specific goo */
  132         struct pcmcia_io_handle sc_pcioh;       /* PCMCIA i/o space info */
  133         int sc_io_window;                       /* our i/o window */
  134         struct pcmcia_function *sc_pf;          /* our PCMCIA function */
  135 };
  136 
  137 struct cfattach ep_pcmcia_ca = {
  138         sizeof(struct ep_pcmcia_softc), ep_pcmcia_match, ep_pcmcia_attach,
  139         ep_pcmcia_detach, ep_pcmcia_activate
  140 };
  141 
  142 struct ep_pcmcia_product {
  143         u_int16_t       epp_product;    /* PCMCIA product ID */
  144         u_short         epp_chipset;    /* 3Com chipset used */
  145         int             epp_flags;      /* initial softc flags */
  146         int             epp_expfunc;    /* expected function */
  147 } ep_pcmcia_prod[] = {
  148         { PCMCIA_PRODUCT_3COM_3C562,    EP_CHIPSET_3C509,
  149           0,                            0 },
  150 
  151         { PCMCIA_PRODUCT_3COM_3C589,    EP_CHIPSET_3C509,
  152           0,                            0 },
  153 
  154         { PCMCIA_PRODUCT_3COM_3CXEM556, EP_CHIPSET_3C509,
  155           0,                            0 },
  156 
  157         { PCMCIA_PRODUCT_3COM_3CXEM556B,EP_CHIPSET_3C509,
  158           0,                            0 },
  159 
  160         { PCMCIA_PRODUCT_3COM_3C1,      EP_CHIPSET_3C509,
  161           0,                            0 },
  162 
  163         { PCMCIA_PRODUCT_3COM_3CCFEM556BI, EP_CHIPSET_ROADRUNNER,
  164           EP_FLAGS_MII,                 0 },
  165 
  166         { PCMCIA_PRODUCT_3COM_3C574,    EP_CHIPSET_ROADRUNNER,
  167           EP_FLAGS_MII,                 0 }
  168 };
  169 
  170 struct ep_pcmcia_product *ep_pcmcia_lookup(struct pcmcia_attach_args *);
  171 
  172 struct ep_pcmcia_product *
  173 ep_pcmcia_lookup(pa)
  174         struct pcmcia_attach_args *pa;
  175 {
  176         int i;
  177 
  178         for (i = 0; i < sizeof(ep_pcmcia_prod)/sizeof(ep_pcmcia_prod[0]); i++)
  179                 if (pa->product == ep_pcmcia_prod[i].epp_product &&
  180                     pa->pf->number == ep_pcmcia_prod[i].epp_expfunc)
  181                         return &ep_pcmcia_prod[i];
  182 
  183         return (NULL);
  184 }
  185 
  186 int
  187 ep_pcmcia_match(parent, match, aux)
  188         struct device *parent;
  189         void *match, *aux;
  190 {
  191         struct pcmcia_attach_args *pa = aux;
  192 
  193         if (pa->manufacturer != PCMCIA_VENDOR_3COM)
  194                 return (0);
  195 
  196         if (ep_pcmcia_lookup(pa) != NULL)
  197                 return (1);
  198 
  199         return (0);
  200 }
  201 
  202 #ifdef notdef
  203 int
  204 ep_pcmcia_enable(sc)
  205         struct ep_softc *sc;
  206 {
  207         struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
  208         struct pcmcia_function *pf = psc->sc_pf;
  209 
  210         /* establish the interrupt. */
  211         sc->sc_ih = pcmcia_intr_establish(pf, IPL_NET, epintr,
  212             sc, sc->sc_dev.dv_xname);
  213         if (sc->sc_ih == NULL) {
  214                 printf("%s: couldn't establish interrupt\n",
  215                     sc->sc_dev.dv_xname);
  216                 return (1);
  217         }
  218 
  219         return (ep_pcmcia_enable1(sc));
  220 }
  221 #endif
  222 
  223 int
  224 ep_pcmcia_enable1(sc)
  225         struct ep_softc *sc;
  226 {
  227         struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
  228         struct pcmcia_function *pf = psc->sc_pf;
  229         int ret;
  230 
  231         if ((ret = pcmcia_function_enable(pf)))
  232                 return (ret);
  233 
  234         if ((psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3C562) ||
  235             (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556) ||
  236             (psc->sc_pf->sc->card.product == PCMCIA_PRODUCT_3COM_3CXEM556B)) {
  237                 int reg;
  238 
  239                 /* turn off the serial-disable bit */
  240 
  241                 reg = pcmcia_ccr_read(pf, PCMCIA_CCR_OPTION);
  242                 if (reg & 0x08) {
  243                         reg &= ~0x08;
  244                         pcmcia_ccr_write(pf, PCMCIA_CCR_OPTION, reg);
  245                 }
  246 
  247         }
  248 
  249         return (ret);
  250 }
  251 
  252 #ifdef notyet
  253 void
  254 ep_pcmcia_disable(sc)
  255         struct ep_softc *sc;
  256 {
  257         struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
  258 
  259         pcmcia_intr_disestablish(psc->sc_pf, sc->sc_ih);
  260         ep_pcmcia_disable1(sc);
  261 }
  262 
  263 void
  264 ep_pcmcia_disable1(sc)
  265         struct ep_softc *sc;
  266 {
  267         struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *) sc;
  268 
  269         pcmcia_function_disable(psc->sc_pf);
  270 }
  271 #endif
  272 
  273 void
  274 ep_pcmcia_attach(parent, self, aux)
  275         struct device  *parent, *self;
  276         void           *aux;
  277 {
  278         struct ep_pcmcia_softc *psc = (void *) self;
  279         struct ep_softc *sc = &psc->sc_ep;
  280         struct pcmcia_attach_args *pa = aux;
  281         struct pcmcia_config_entry *cfe;
  282         struct ep_pcmcia_product *epp;
  283         u_int8_t myla[ETHER_ADDR_LEN];
  284         u_int8_t *enaddr = NULL;
  285         const char *intrstr;
  286         int i;
  287 
  288         psc->sc_pf = pa->pf;
  289         cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
  290 
  291         /* Enable the card. */
  292         pcmcia_function_init(pa->pf, cfe);
  293         if (ep_pcmcia_enable1(sc))
  294                 printf(": function enable failed\n");
  295 
  296 #ifdef notyet
  297         sc->enabled = 1;
  298 #endif
  299 
  300         if (cfe->num_memspace != 0)
  301                 printf(": unexpected number of memory spaces %d should be 0\n",
  302                     cfe->num_memspace);
  303 
  304         if (cfe->num_iospace != 1)
  305                 printf(": unexpected number of I/O spaces %d should be 1\n",
  306                     cfe->num_iospace);
  307 
  308         if (pa->product == PCMCIA_PRODUCT_3COM_3C562) {
  309                 bus_addr_t maxaddr = (pa->pf->sc->iobase + pa->pf->sc->iosize);
  310 
  311                 for (i = pa->pf->sc->iobase; i < maxaddr; i += 0x10) {
  312                         /*
  313                          * the 3c562 can only use 0x??00-0x??7f
  314                          * according to the Linux driver
  315                          */
  316                         if (i & 0x80)
  317                                 continue;
  318                         if (pcmcia_io_alloc(pa->pf, i, cfe->iospace[0].length,
  319                             cfe->iospace[0].length, &psc->sc_pcioh) == 0)
  320                                 break;
  321                 }
  322                 if (i >= maxaddr) {
  323                         printf(": can't allocate i/o space\n");
  324                         return;
  325                 }
  326         } else {
  327                 if (pcmcia_io_alloc(pa->pf, 0, cfe->iospace[0].length,
  328                     cfe->iospace[0].length, &psc->sc_pcioh))
  329                         printf(": can't allocate i/o space\n");
  330         }
  331 
  332         sc->sc_iot = psc->sc_pcioh.iot;
  333         sc->sc_ioh = psc->sc_pcioh.ioh;
  334 
  335         if (pcmcia_io_map(pa->pf, ((cfe->flags & PCMCIA_CFE_IO16) ?
  336             PCMCIA_WIDTH_IO16 : PCMCIA_WIDTH_IO8), 0, cfe->iospace[0].length,
  337             &psc->sc_pcioh, &psc->sc_io_window)) {
  338                 printf(": can't map i/o space\n");
  339                 return;
  340         }
  341 
  342         printf(" port 0x%lx/%d", psc->sc_pcioh.addr, psc->sc_pcioh.size);
  343 
  344         switch (pa->product) {
  345         case PCMCIA_PRODUCT_3COM_3C562:
  346                 /*
  347                  * 3c562a-c use this; 3c562d does it in the regular way.
  348                  * we might want to check the revision and produce a warning
  349                  * in the future.
  350                  */
  351                 /* FALLTHROUGH */
  352         case PCMCIA_PRODUCT_3COM_3C574:
  353         case PCMCIA_PRODUCT_3COM_3CCFEM556BI:
  354                 /*
  355                  * Apparently, some 3c574s do it this way, as well.
  356                  */
  357                 if (pcmcia_scan_cis(parent, ep_pcmcia_get_enaddr, myla))
  358                         enaddr = myla;
  359                 break;
  360         }
  361 
  362         sc->bustype = EP_BUS_PCMCIA;
  363 
  364         epp = ep_pcmcia_lookup(pa);
  365         if (epp == NULL)
  366                 panic("ep_pcmcia_attach: impossible");
  367 
  368         sc->ep_flags = epp->epp_flags;
  369 
  370 #ifdef notyet
  371         sc->enable = ep_pcmcia_enable;
  372         sc->disable = ep_pcmcia_disable;
  373 #endif
  374 
  375         /* establish the interrupt. */
  376         sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, epintr, sc,
  377             sc->sc_dev.dv_xname);
  378         intrstr = pcmcia_intr_string(psc->sc_pf, sc->sc_ih);
  379         if (*intrstr)
  380                 printf(", %s", intrstr);
  381 
  382         printf(":");
  383 
  384         epconfig(sc, epp->epp_chipset, enaddr);
  385 
  386 #ifdef notyet
  387         sc->enabled = 0;
  388 
  389         ep_pcmcia_disable1(sc);
  390 #endif
  391 }
  392 
  393 int
  394 ep_pcmcia_detach(dev, flags)
  395         struct device *dev;
  396         int flags;
  397 {
  398         int rv;
  399         struct ep_pcmcia_softc *psc = (struct ep_pcmcia_softc *)dev;
  400 
  401         if ((rv = ep_detach(dev)) != 0)
  402                 return (rv);
  403 
  404         pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
  405         pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
  406 
  407         return (0);
  408 }
  409 
  410 int
  411 ep_pcmcia_activate(dev, act)
  412         struct device *dev;
  413         enum devact act;
  414 {
  415         struct ep_pcmcia_softc *sc = (struct ep_pcmcia_softc *)dev;
  416         struct ep_softc *esc = &sc->sc_ep;
  417         struct ifnet *ifp = &esc->sc_arpcom.ac_if;
  418         int s;
  419 
  420         s = splnet();
  421         switch (act) {
  422         case DVACT_ACTIVATE:
  423                 pcmcia_function_enable(sc->sc_pf);
  424                 sc->sc_ep.sc_ih = pcmcia_intr_establish(sc->sc_pf, IPL_NET,
  425                     epintr, sc, esc->sc_dev.dv_xname);
  426                 epinit(esc);
  427                 break;
  428 
  429         case DVACT_DEACTIVATE:
  430                 ifp->if_timer = 0;
  431                 if (ifp->if_flags & IFF_RUNNING)
  432                         epstop(esc);
  433                 pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ep.sc_ih);
  434                 pcmcia_function_disable(sc->sc_pf);
  435                 break;
  436         }
  437         splx(s);
  438         return (0);
  439 }
  440 
  441 int
  442 ep_pcmcia_get_enaddr(tuple, arg)
  443         struct pcmcia_tuple *tuple;
  444         void *arg;
  445 {
  446         u_int8_t *myla = arg;
  447         int i;
  448 
  449         /* this is 3c562a-c magic */
  450         if (tuple->code == 0x88) {
  451                 if (tuple->length < ETHER_ADDR_LEN)
  452                         return (0);
  453 
  454                 for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
  455                         myla[i] = pcmcia_tuple_read_1(tuple, i + 1);
  456                         myla[i + 1] = pcmcia_tuple_read_1(tuple, i);
  457                 }
  458 
  459                 return (1);
  460         }
  461         return (0);
  462 }

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