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/sn/if_sn_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) 1999 M. Warner Losh <imp@village.org> 
    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  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 /*
   26  * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT)
   27  * 
   28  * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
   29  *                       BSD-nomads, Tokyo, Japan.
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/8.3/sys/dev/sn/if_sn_pccard.c 150106 2005-09-13 19:25:30Z imp $");
   34 
   35 #include <sys/param.h>
   36 #include <sys/bus.h>
   37 #include <sys/kernel.h>
   38 #include <sys/module.h>
   39 #include <sys/socket.h>
   40 #include <sys/systm.h>
   41 
   42 #include <net/ethernet.h> 
   43 #include <net/if.h> 
   44 #include <net/if_arp.h>
   45 
   46 #include <machine/bus.h>
   47 #include <machine/resource.h>
   48 #include <sys/rman.h> 
   49 
   50 #include <dev/pccard/pccardvar.h>
   51 #include <dev/pccard/pccard_cis.h>
   52 #include <dev/sn/if_snreg.h>
   53 #include <dev/sn/if_snvar.h>
   54 
   55 #include "card_if.h"
   56 #include "pccarddevs.h"
   57 
   58 typedef int sn_get_enaddr_t(device_t dev, u_char *eaddr);
   59 typedef int sn_activate_t(device_t dev);
   60 
   61 struct sn_sw
   62 {
   63         int type;
   64 #define SN_NORMAL 1
   65 #define SN_MEGAHERTZ 2
   66 #define SN_OSITECH 3
   67 #define SN_OSI_SOD 4
   68 #define SN_MOTO_MARINER 5
   69         char *typestr;
   70         sn_get_enaddr_t *get_mac;
   71         sn_activate_t *activate;
   72 };
   73 
   74 static sn_get_enaddr_t sn_pccard_normal_get_mac;
   75 static sn_activate_t sn_pccard_normal_activate;
   76 const static struct sn_sw sn_normal_sw = {
   77         SN_NORMAL, "plain",
   78         sn_pccard_normal_get_mac,
   79         sn_pccard_normal_activate
   80 };
   81 
   82 static sn_get_enaddr_t sn_pccard_megahertz_get_mac;
   83 static sn_activate_t sn_pccard_megahertz_activate;
   84 const static struct sn_sw sn_mhz_sw = {
   85         SN_MEGAHERTZ, "Megahertz",
   86         sn_pccard_megahertz_get_mac,
   87         sn_pccard_megahertz_activate
   88 };
   89 
   90 static const struct sn_product {
   91         struct pccard_product prod;
   92         const struct sn_sw *sw;
   93 } sn_pccard_products[] = {
   94         { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw },
   95         { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw },
   96 /*      { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */
   97         { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw },
   98         { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw},
   99         { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw},
  100 /*      { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */
  101 /*      { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */
  102 /*      { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */
  103 /*      { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */
  104 /*      { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */
  105         { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw },
  106         { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw },
  107         { { NULL } }
  108         
  109 };
  110 
  111 static const struct sn_product *
  112 sn_pccard_lookup(device_t dev)
  113 {
  114 
  115         return ((const struct sn_product *)
  116             pccard_product_lookup(dev,
  117                 (const struct pccard_product *)sn_pccard_products,
  118                 sizeof(sn_pccard_products[0]), NULL));
  119 }
  120 
  121 static int
  122 sn_pccard_probe(device_t dev)
  123 {
  124         const struct sn_product *pp;
  125 
  126         if ((pp = sn_pccard_lookup(dev)) != NULL) {
  127                 if (pp->prod.pp_name != NULL)
  128                         device_set_desc(dev, pp->prod.pp_name);
  129                 return 0;
  130         }
  131         return EIO;
  132 }
  133 
  134 static int
  135 sn_pccard_ascii_enaddr(const char *str, u_char *enet)
  136 {
  137         uint8_t digit;
  138         int i;
  139 
  140         memset(enet, 0, ETHER_ADDR_LEN);
  141         for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) {
  142                 if (str[i] >= '' && str[i] <= '9')
  143                         digit |= str[i] - '';
  144                 else if (str[i] >= 'a' && str[i] <= 'f')
  145                         digit |= (str[i] - 'a') + 10;
  146                 else if (str[i] >= 'A' && str[i] <= 'F')
  147                         digit |= (str[i] - 'A') + 10;
  148                 else
  149                         return (0);             /* Bogus digit!! */
  150 
  151                 /* Compensate for ordering of digits. */
  152                 if (i & 1) {
  153                         enet[i >> 1] = digit;
  154                         digit = 0;
  155                 } else
  156                         digit <<= 4;
  157         }
  158 
  159         return (1);
  160 }
  161 
  162 static int
  163 sn_pccard_normal_get_mac(device_t dev, u_char *eaddr)
  164 {
  165         int i, sum;
  166         const char *cisstr;
  167 
  168         pccard_get_ether(dev, eaddr);
  169         for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
  170                 sum |= eaddr[i];
  171         if (sum == 0) {
  172                 pccard_get_cis3_str(dev, &cisstr);
  173                 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
  174                     sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
  175         }
  176         if (sum == 0) {
  177                 pccard_get_cis4_str(dev, &cisstr);
  178                 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
  179                     sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
  180         }
  181         return sum;
  182 }
  183 
  184 static int
  185 sn_pccard_normal_activate(device_t dev)
  186 {
  187         int err;
  188 
  189         err = sn_activate(dev);
  190         if (err)
  191                 sn_deactivate(dev);
  192         return (err);
  193 }
  194 
  195 static int
  196 sn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp)
  197 {
  198         uint8_t *enaddr = argp;
  199         int i;
  200         uint8_t buffer[ETHER_ADDR_LEN * 2];
  201 
  202         /* Code 0x81 is Megahertz' special cis node contianing the MAC */
  203         if (tuple->code != 0x81)
  204                 return (0);
  205 
  206         /* Make sure this is a sane node, as ASCII digits */
  207         if (tuple->length != ETHER_ADDR_LEN * 2 + 1)
  208                 return (0);
  209 
  210         /* Copy the MAC ADDR and return success if decoded */
  211         for (i = 0; i < ETHER_ADDR_LEN * 2; i++)
  212                 buffer[i] = pccard_tuple_read_1(tuple, i);
  213         return (sn_pccard_ascii_enaddr(buffer, enaddr));
  214 }
  215 
  216 static int
  217 sn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr)
  218 {
  219 
  220         if (sn_pccard_normal_get_mac(dev, eaddr))
  221                 return 1;
  222         /*
  223          * If that fails, try the special CIS tuple 0x81 that the
  224          * '3288 and '3336 cards have.  That tuple specifies an ASCII
  225          * string, ala CIS3 or CIS4 in the 'normal' cards.
  226          */
  227         return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr));
  228 }
  229 
  230 static int
  231 sn_pccard_megahertz_activate(device_t dev)
  232 {
  233         int err;
  234         struct sn_softc *sc = device_get_softc(dev);
  235         u_long start;
  236 
  237         err = sn_activate(dev);
  238         if (err) {
  239                 sn_deactivate(dev);
  240                 return (err);
  241         }
  242         /*
  243          * CIS resource is the modem one, so save it away.
  244          */
  245         sc->modem_rid = sc->port_rid;
  246         sc->modem_res = sc->port_res;
  247 
  248         /*
  249          * The MHz XJEM/CCEM series of cards just need to have any
  250          * old resource allocated for the ethernet side of things,
  251          * provided bit 0x80 isn't set in the address.  That bit is
  252          * evidentially reserved for modem function and is how the
  253          * card steers the addresses internally.
  254          */
  255         sc->port_res = NULL;
  256         start = 0;
  257         do
  258         {
  259                 sc->port_rid = 1;
  260                 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
  261                     &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE);
  262                 if (sc->port_res == NULL)
  263                         break;
  264                 if (!(rman_get_start(sc->port_res) & 0x80))
  265                         break;
  266                 start = rman_get_start(sc->port_res) + SMC_IO_EXTENT;
  267                 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid,
  268                     sc->port_res);
  269         } while (start < 0xff80);
  270         if (sc->port_res == NULL) {
  271                 sn_deactivate(dev);
  272                 return ENOMEM;
  273         }
  274         sc->bst = rman_get_bustag(sc->port_res);
  275         sc->bsh = rman_get_bushandle(sc->port_res);
  276         return 0;
  277 }
  278 
  279 static int
  280 sn_pccard_attach(device_t dev)
  281 {
  282         struct sn_softc *sc = device_get_softc(dev);
  283         u_char eaddr[ETHER_ADDR_LEN];
  284         int i, err;
  285         uint16_t w;
  286         u_char sum;
  287         const struct sn_product *pp;
  288 
  289         pp = sn_pccard_lookup(dev);
  290         sum = pp->sw->get_mac(dev, eaddr);
  291 
  292         /* Allocate resources so we can program the ether addr */
  293         sc->dev = dev;
  294         err = pp->sw->activate(dev);
  295         if (err != 0)
  296                 return (err);
  297 
  298         if (sum) {
  299                 printf("Programming sn card's addr\n");
  300                 SMC_SELECT_BANK(sc, 1);
  301                 for (i = 0; i < 3; i++) {
  302                         w = (uint16_t)eaddr[i * 2] | 
  303                             (((uint16_t)eaddr[i * 2 + 1]) << 8);
  304                         CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w);
  305                 }
  306         }
  307         err = sn_attach(dev);
  308         if (err)
  309                 sn_deactivate(dev);
  310         return (err);
  311 }
  312 
  313 static device_method_t sn_pccard_methods[] = {
  314         /* Device interface */
  315         DEVMETHOD(device_probe,         sn_pccard_probe),
  316         DEVMETHOD(device_attach,        sn_pccard_attach),
  317         DEVMETHOD(device_detach,        sn_detach),
  318 
  319         { 0, 0 }
  320 };
  321 
  322 static driver_t sn_pccard_driver = {
  323         "sn",
  324         sn_pccard_methods,
  325         sizeof(struct sn_softc),
  326 };
  327 
  328 extern devclass_t sn_devclass;
  329 
  330 DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0);
  331 MODULE_DEPEND(sn, ether, 1, 1, 1);

Cache object: 3e756adb9ab03897e1b1cf7573ec23ba


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