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/netif/ep/if_ep_pccard.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 /*
    2  * Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by Herb Peyerl.
   16  * 4. The name of Herb Peyerl may not be used to endorse or promote products
   17  *    derived from this software without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   29  *
   30  * $FreeBSD: src/sys/dev/ep/if_ep_pccard.c,v 1.12.2.2 2000/08/08 23:55:02 peter Exp $
   31  */
   32 
   33 /*
   34  * Pccard support for 3C589 by:
   35  *              HAMADA Naoki
   36  *              nao@tom-yam.or.jp
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/kernel.h>
   42 #include <sys/socket.h>
   43 #include <sys/module.h>
   44 #include <sys/interrupt.h>
   45 #include <sys/bus.h>
   46 #include <sys/rman.h>
   47  
   48 #include <net/ethernet.h>
   49 #include <net/if.h> 
   50 #include <net/if_arp.h>
   51 #include <net/if_media.h>
   52 #include <net/ifq_var.h>
   53 
   54 #include <machine/clock.h>
   55 
   56 #include "if_epreg.h"
   57 #include "if_epvar.h"
   58 
   59 #include <bus/pccard/pccardvar.h>
   60 
   61 #include "card_if.h"
   62 #include "pccarddevs.h"
   63 
   64 static const char *ep_pccard_identify(u_short id);
   65 
   66 /*
   67  * Initialize the device - called from Slot manager.
   68  */
   69 static int
   70 ep_pccard_probe(device_t dev)
   71 {
   72         struct ep_softc *       sc = device_get_softc(dev);
   73         struct ep_board *       epb = &sc->epb;
   74         const char *            desc;
   75         int                     error;
   76 
   77         error = ep_alloc(dev);
   78         if (error)
   79                 return error;
   80 
   81         /*
   82          * XXX - Certain (newer?) 3Com cards need epb->cmd_off ==
   83          * 2. Sadly, you need to have a correct cmd_off in order to
   84          * identify the card.  So we have to hit it with both and
   85          * cross our virtual fingers.  There's got to be a better way
   86          * to do this.  jyoung@accessus.net 09/11/1999 
   87          */
   88 
   89         epb->cmd_off = 0;
   90         epb->prod_id = get_e(sc, EEPROM_PROD_ID);
   91         if ((desc = ep_pccard_identify(epb->prod_id)) == NULL) {
   92                 if (bootverbose) 
   93                         device_printf(dev, "Pass 1 of 2 detection "
   94                             "failed (nonfatal)\n");
   95                 epb->cmd_off = 2;
   96                 epb->prod_id = get_e(sc, EEPROM_PROD_ID);
   97                 if ((desc = ep_pccard_identify(epb->prod_id)) == NULL) {
   98                         device_printf(dev, "Unit failed to come ready or "
   99                             "product ID unknown! (id 0x%x)\n", epb->prod_id);
  100                         ep_free(dev);
  101                         return (ENXIO);
  102                 }
  103         }
  104         device_set_desc(dev, desc);
  105 
  106         /*
  107          * For some reason the 3c574 needs this.
  108          */
  109         ep_get_macaddr(sc, (u_char *)&sc->arpcom.ac_enaddr);
  110 
  111         ep_free(dev);
  112         return (0);
  113 }
  114 
  115 static const char *
  116 ep_pccard_identify(u_short id)
  117 {
  118         /* Determine device type and associated MII capabilities  */
  119         switch (id) {
  120         case 0x6055: /* 3C556 */
  121                 return ("3Com 3C556");
  122         case 0x4057: /* 3C574 */
  123                 return ("3Com 3C574");
  124         case 0x4b57: /* 3C574B */
  125                 return ("3Com 3C574B, Megahertz 3CCFE574BT or "
  126                     "Fast Etherlink 3C574-TX");
  127         case 0x2b57: /* 3CXSH572BT */
  128                 return ("3Com OfficeConnect 572BT");
  129         case 0x9058: /* 3C589 */
  130                 return ("3Com Etherlink III 3C589");
  131         case 0x2056: /* 3C562/3C563 */
  132                 return ("3Com 3C562D/3C563D");
  133         }
  134         return (NULL);
  135 }
  136 
  137 static int
  138 ep_pccard_card_attach(struct ep_board *epb)
  139 {
  140         /* Determine device type and associated MII capabilities  */
  141         switch (epb->prod_id) {
  142         case 0x6055: /* 3C556 */
  143         case 0x2b57: /* 3C572BT */
  144         case 0x4057: /* 3C574 */
  145         case 0x4b57: /* 3C574B */
  146                 epb->mii_trans = 1;
  147                 return (1);
  148         case 0x2056: /* 3C562D/3C563D */
  149         case 0x9058: /* 3C589 */
  150                 epb->mii_trans = 0;
  151                 return (1);
  152         }
  153         return (0);
  154 }
  155 
  156 static int
  157 ep_pccard_attach(device_t dev)
  158 {
  159         struct ep_softc *       sc = device_get_softc(dev);
  160         struct ifnet *          ifp = &sc->arpcom.ac_if;
  161         int                     error = 0;
  162 
  163         if ((error = ep_alloc(dev))) {
  164                 device_printf(dev, "ep_alloc() failed! (%d)\n", error);
  165                 goto bad;
  166         }
  167 
  168         sc->epb.cmd_off = 0;
  169         sc->epb.prod_id = get_e(sc, EEPROM_PROD_ID);
  170         if (!ep_pccard_card_attach(&sc->epb)) {
  171                 sc->epb.cmd_off = 2;
  172                 sc->epb.prod_id = get_e(sc, EEPROM_PROD_ID);
  173                 sc->epb.res_cfg = get_e(sc, EEPROM_RESOURCE_CFG);
  174                 if (!ep_pccard_card_attach(&sc->epb)) {
  175                         device_printf(dev,
  176                             "Probe found ID, attach failed so ignore card!\n");
  177                         error = ENXIO;
  178                         goto bad;
  179                 }
  180         }
  181 
  182         /* ROM size = 0, ROM base = 0 */
  183         /* For now, ignore AUTO SELECT feature of 3C589B and later. */
  184         outw(BASE + EP_W0_ADDRESS_CFG, get_e(sc, EEPROM_ADDR_CFG) & 0xc000);
  185 
  186         /* Fake IRQ must be 3 */
  187         outw(BASE + EP_W0_RESOURCE_CFG, (sc->epb.res_cfg & 0x0fff) | 0x3000);
  188 
  189         outw(BASE + EP_W0_PRODUCT_ID, sc->epb.prod_id);
  190 
  191         if (sc->epb.mii_trans) {
  192                 /*
  193                  * turn on the MII transciever
  194                  */
  195                 GO_WINDOW(3);
  196                 outw(BASE + EP_W3_OPTIONS, 0x8040);
  197                 DELAY(1000);
  198                 outw(BASE + EP_W3_OPTIONS, 0xc040);
  199                 outw(BASE + EP_COMMAND, RX_RESET);
  200                 outw(BASE + EP_COMMAND, TX_RESET);
  201                 while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS);
  202                 DELAY(1000);
  203                 outw(BASE + EP_W3_OPTIONS, 0x8040);
  204         } else {
  205                 ep_get_media(sc);
  206         }
  207 
  208         if ((error = ep_attach(sc))) {
  209                 device_printf(dev, "ep_attach() failed! (%d)\n", error);
  210                 goto bad;
  211         }
  212 
  213         ifq_set_cpuid(&ifp->if_snd, rman_get_cpuid(sc->irq));
  214 
  215         error = bus_setup_intr(dev, sc->irq, INTR_MPSAFE, ep_intr,
  216                                     sc, &sc->ep_intrhand, 
  217                                     sc->arpcom.ac_if.if_serializer);
  218         if (error) {
  219                 device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
  220                 goto bad;
  221         }
  222 
  223         return (0);
  224 bad:
  225         ep_free(dev);
  226         return (error);
  227 }
  228 
  229 static int
  230 ep_pccard_detach(device_t dev)
  231 {
  232         struct ep_softc *sc = device_get_softc(dev);
  233         struct ifnet *ifp = &sc->arpcom.ac_if;
  234 
  235         lwkt_serialize_enter(ifp->if_serializer);
  236 
  237         if (sc->gone) {
  238                 device_printf(dev, "already unloaded\n");
  239                 lwkt_serialize_exit(ifp->if_serializer);
  240                 return (0);
  241         }
  242         ifp->if_flags &= ~IFF_RUNNING; 
  243         sc->gone = 1;
  244         bus_teardown_intr(dev, sc->irq, sc->ep_intrhand);
  245 
  246         lwkt_serialize_exit(ifp->if_serializer);
  247 
  248         ether_ifdetach(&sc->arpcom.ac_if);
  249         ep_free(dev);
  250         return (0);
  251 }
  252 
  253 static const struct pccard_product ep_pccard_products[] = {
  254         PCMCIA_CARD(3COM, 3C1, 0),
  255         PCMCIA_CARD(3COM, 3C562, 0),
  256         PCMCIA_CARD(3COM, 3C574, 0),    /* ROADRUNNER */
  257         PCMCIA_CARD(3COM, 3C589, 0),
  258         PCMCIA_CARD(3COM, 3CCFEM556BI, 0),      /* ROADRUNNER */
  259         PCMCIA_CARD(3COM, 3CXEM556, 0),
  260         PCMCIA_CARD(3COM, 3CXEM556INT, 0),
  261         {NULL}
  262 };
  263 
  264 static int
  265 ep_pccard_match(device_t dev)
  266 {
  267         const struct pccard_product *pp;
  268 
  269         if ((pp = pccard_product_lookup(dev, ep_pccard_products,
  270                     sizeof(ep_pccard_products[0]), NULL)) != NULL) {
  271                 if (pp->pp_name != NULL)
  272                         device_set_desc(dev, pp->pp_name);
  273                 return 0;
  274         }
  275         return EIO;
  276 }
  277 
  278 static device_method_t ep_pccard_methods[] = {
  279         /* Device interface */
  280         DEVMETHOD(device_probe, pccard_compat_probe),
  281         DEVMETHOD(device_attach, pccard_compat_attach),
  282         DEVMETHOD(device_detach, ep_pccard_detach),
  283 
  284         /* Card interface */
  285         DEVMETHOD(card_compat_match, ep_pccard_match),
  286         DEVMETHOD(card_compat_probe, ep_pccard_probe),
  287         DEVMETHOD(card_compat_attach, ep_pccard_attach),
  288 
  289         DEVMETHOD_END
  290 };
  291 
  292 static driver_t ep_pccard_driver = {
  293         "ep",
  294         ep_pccard_methods,
  295         sizeof(struct ep_softc),
  296 };
  297 
  298 extern devclass_t ep_devclass;
  299 
  300 DRIVER_MODULE(if_ep, pccard, ep_pccard_driver, ep_devclass, NULL, NULL);

Cache object: bfe77635b07ddd0cf0c2d8856a328f9a


[ 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.