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/cardbus/cardbus_cis.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) 2000,2001 Jonathan Chen.
    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 AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/6.0/sys/dev/cardbus/cardbus_cis.c 142144 2005-02-20 20:36:16Z imp $");
   29 
   30 /*
   31  * CIS Handling for the Cardbus Bus
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 
   39 #include <sys/bus.h>
   40 #include <machine/bus.h>
   41 #include <machine/resource.h>
   42 #include <sys/rman.h>
   43 #include <sys/endian.h>
   44 
   45 #include <sys/pciio.h>
   46 #include <dev/pci/pcivar.h>
   47 #include <dev/pci/pcireg.h>
   48 
   49 #include <dev/pccard/pccardvar.h>
   50 #include <dev/pccard/pccard_cis.h>
   51 
   52 #include <dev/cardbus/cardbusreg.h>
   53 #include <dev/cardbus/cardbusvar.h>
   54 #include <dev/cardbus/cardbus_cis.h>
   55 
   56 extern int cardbus_cis_debug;
   57 
   58 #define DPRINTF(a) if (cardbus_cis_debug) printf a
   59 #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
   60 
   61 struct tuple_callbacks;
   62 
   63 typedef int (tuple_cb) (device_t cbdev, device_t child, int id, int len,
   64                  uint8_t *tupledata, uint32_t start, uint32_t *off,
   65                  struct tuple_callbacks *info);
   66 
   67 struct tuple_callbacks {
   68         int     id;
   69         char    *name;
   70         tuple_cb *func;
   71 };
   72 
   73 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
   74     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   75     struct tuple_callbacks *info);
   76 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
   77     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   78     struct tuple_callbacks *info);
   79 static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
   80     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   81     struct tuple_callbacks *info);
   82 static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
   83     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   84     struct tuple_callbacks *info);
   85 static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
   86     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   87     struct tuple_callbacks *info);
   88 static int decode_tuple_funce(device_t cbdev, device_t child, int id,
   89     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   90     struct tuple_callbacks *info);
   91 static int decode_tuple_bar(device_t cbdev, device_t child, int id,
   92     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   93     struct tuple_callbacks *info);
   94 static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
   95     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   96     struct tuple_callbacks *info);
   97 static int decode_tuple_end(device_t cbdev, device_t child, int id,
   98     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   99     struct tuple_callbacks *info);
  100 
  101 static int      cardbus_read_tuple_conf(device_t cbdev, device_t child,
  102                     uint32_t start, uint32_t *off, int *tupleid, int *len,
  103                     uint8_t *tupledata);
  104 static int      cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
  105                     uint32_t start, uint32_t *off, int *tupleid, int *len,
  106                     uint8_t *tupledata);
  107 static int      cardbus_read_tuple(device_t cbdev, device_t child,
  108                     struct resource *res, uint32_t start, uint32_t *off,
  109                     int *tupleid, int *len, uint8_t *tupledata);
  110 static void     cardbus_read_tuple_finish(device_t cbdev, device_t child,
  111                     int rid, struct resource *res);
  112 static struct resource  *cardbus_read_tuple_init(device_t cbdev, device_t child,
  113                     uint32_t *start, int *rid);
  114 static int      decode_tuple(device_t cbdev, device_t child, int tupleid,
  115                     int len, uint8_t *tupledata, uint32_t start,
  116                     uint32_t *off, struct tuple_callbacks *callbacks);
  117 static int      cardbus_parse_cis(device_t cbdev, device_t child,
  118                     struct tuple_callbacks *callbacks);
  119 
  120 #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
  121 
  122 static char *funcnames[] = {
  123         "Multi-Functioned",
  124         "Memory",
  125         "Serial Port",
  126         "Parallel Port",
  127         "Fixed Disk",
  128         "Video Adaptor",
  129         "Network Adaptor",
  130         "AIMS",
  131         "SCSI",
  132         "Security"
  133 };
  134 
  135 /*
  136  * Handler functions for various CIS tuples
  137  */
  138 
  139 static int
  140 decode_tuple_generic(device_t cbdev, device_t child, int id,
  141     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  142     struct tuple_callbacks *info)
  143 {
  144         int i;
  145 
  146         if (cardbus_cis_debug) {
  147                 if (info)
  148                         printf("TUPLE: %s [%d]:", info->name, len);
  149                 else
  150                         printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
  151 
  152                 for (i = 0; i < len; i++) {
  153                         if (i % 0x10 == 0 && len > 0x10)
  154                                 printf("\n       0x%02x:", i);
  155                         printf(" %02x", tupledata[i]);
  156                 }
  157                 printf("\n");
  158         }
  159         return (0);
  160 }
  161 
  162 static int
  163 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
  164     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  165     struct tuple_callbacks *info)
  166 {
  167         int i;
  168 
  169         if (cardbus_cis_debug) {
  170                 printf("TUPLE: %s [%d]:", info->name, len);
  171 
  172                 for (i = 0; i < len; i++) {
  173                         if (i % 0x10 == 0 && len > 0x10)
  174                                 printf("\n       0x%02x:", i);
  175                         printf(" %02x", tupledata[i]);
  176                 }
  177                 printf("\n");
  178         }
  179         if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
  180             tupledata[2] != 'S') {
  181                 printf("Invalid data for CIS Link Target!\n");
  182                 decode_tuple_generic(cbdev, child, id, len, tupledata,
  183                     start, off, info);
  184                 return (EINVAL);
  185         }
  186         return (0);
  187 }
  188 
  189 static int
  190 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
  191     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  192     struct tuple_callbacks *info)
  193 {
  194         int i;
  195 
  196         if (cardbus_cis_debug) {
  197                 printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
  198                 printf("Product name: ");
  199                 for (i = 2; i < len; i++) {
  200                         if (tupledata[i] == '\0')
  201                                 printf(" | ");
  202                         else if (tupledata[i] == 0xff)
  203                                 break;
  204                         else
  205                                 printf("%c", tupledata[i]);
  206                 }
  207                 printf("\n");
  208         }
  209         return (0);
  210 }
  211 
  212 static int
  213 decode_tuple_funcid(device_t cbdev, device_t child, int id,
  214     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  215     struct tuple_callbacks *info)
  216 {
  217         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  218         int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
  219         int i;
  220 
  221         if (cardbus_cis_debug) {
  222                 printf("Functions: ");
  223                 for (i = 0; i < len; i++) {
  224                         if (tupledata[i] < numnames)
  225                                 printf("%s", funcnames[tupledata[i]]);
  226                         else
  227                                 printf("Unknown(%d)", tupledata[i]);
  228                         if (i < len-1)
  229                                 printf(", ");
  230                 }
  231                 printf("\n");
  232         }
  233         if (len > 0)
  234                 dinfo->funcid = tupledata[0];           /* use first in list */
  235         return (0);
  236 }
  237 
  238 static int
  239 decode_tuple_manfid(device_t cbdev, device_t child, int id,
  240     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  241     struct tuple_callbacks *info)
  242 {
  243         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  244         int i;
  245 
  246         if (cardbus_cis_debug) {
  247                 printf("Manufacturer ID: ");
  248                 for (i = 0; i < len; i++)
  249                         printf("%02x", tupledata[i]);
  250                 printf("\n");
  251         }
  252 
  253         if (len == 5) {
  254                 dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
  255                 dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
  256         }
  257         return (0);
  258 }
  259 
  260 static int
  261 decode_tuple_funce(device_t cbdev, device_t child, int id,
  262     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  263     struct tuple_callbacks *info)
  264 {
  265         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  266         int type, i;
  267 
  268         if (cardbus_cis_debug) {
  269                 printf("Function Extension: ");
  270                 for (i = 0; i < len; i++)
  271                         printf("%02x", tupledata[i]);
  272                 printf("\n");
  273         }
  274         if (len < 2)                    /* too short */
  275                 return (0);
  276         type = tupledata[0];            /* XXX <32 always? */
  277         switch (dinfo->funcid) {
  278         case PCCARD_FUNCTION_NETWORK:
  279                 switch (type) {
  280                 case PCCARD_TPLFE_TYPE_LAN_NID:
  281                         if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
  282                                 /* ignore, warning? */
  283                                 return (0);
  284                         }
  285                         bcopy(tupledata + 2, dinfo->funce.lan.nid,
  286                             tupledata[1]);
  287                         break;
  288                 }
  289                 dinfo->fepresent |= 1<<type;
  290                 break;
  291         }
  292         return (0);
  293 }
  294 
  295 static int
  296 decode_tuple_bar(device_t cbdev, device_t child, int id,
  297     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  298     struct tuple_callbacks *info)
  299 {
  300         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  301         int type;
  302         uint8_t reg;
  303         uint32_t bar, pci_bar;
  304 
  305         if (len != 6) {
  306                 device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
  307                 return (EINVAL);
  308         }
  309 
  310         reg = *tupledata;
  311         len = le32toh(*(uint32_t*)(tupledata + 2));
  312         if (reg & TPL_BAR_REG_AS) {
  313                 type = SYS_RES_IOPORT;
  314         } else {
  315                 type = SYS_RES_MEMORY;
  316         }
  317 
  318         bar = reg & TPL_BAR_REG_ASI_MASK;
  319         if (bar == 0) {
  320                 device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
  321                 return (EINVAL);        /* XXX Return an error? */
  322         } else if (bar == 7) {
  323                 /* XXX Should we try to map in Option ROMs? */
  324                 return (0);
  325         }
  326 
  327         /* Convert from BAR type to BAR offset */
  328         bar = CARDBUS_BASE0_REG + (bar - 1) * 4;
  329 
  330         if (type == SYS_RES_MEMORY) {
  331                 if (reg & TPL_BAR_REG_PREFETCHABLE)
  332                         dinfo->mprefetchable |= BARBIT(bar);
  333 #if 0
  334                 /*
  335                  * XXX: It appears from a careful reading of the spec
  336                  * that we're not supposed to honor this when the bridge
  337                  * is not on the main system bus.  PCI spec doesn't appear
  338                  * to allow for memory ranges not listed in the bridge's
  339                  * decode range to be decoded.  The PC Card spec seems to
  340                  * indicate that this should only be done on x86 based
  341                  * machines, which seems to imply that on non-x86 machines
  342                  * the adddresses can be anywhere.  This further implies that
  343                  * since the hardware can do it on non-x86 machines, it should
  344                  * be able to do it on x86 machines.  Therefore, we can and
  345                  * should ignore this hint.  Furthermore, the PC Card spec
  346                  * recommends always allocating memory above 1MB, contradicting
  347                  * the other part of the PC Card spec.
  348                  *
  349                  * NetBSD ignores this bit, but it also ignores the
  350                  * prefetchable bit too, so that's not an indication of
  351                  * correctness.
  352                  */
  353                 if (reg & TPL_BAR_REG_BELOW1MB)
  354                         dinfo->mbelow1mb |= BARBIT(bar);
  355 #endif
  356         }
  357 
  358         /*
  359          * Sanity check the BAR length reported in the CIS with the length
  360          * encoded in the PCI BAR.  The latter seems to be more reliable.
  361          * XXX - This probably belongs elsewhere.
  362          */
  363         pci_write_config(child, bar, 0xffffffff, 4);
  364         pci_bar = pci_read_config(child, bar, 4);
  365         if ((pci_bar != 0x0) && (pci_bar != 0xffffffff)) {
  366                 if (type == SYS_RES_MEMORY) {
  367                         pci_bar &= ~0xf;
  368                 } else {
  369                         pci_bar &= ~0x3;
  370                 }
  371                 len = 1 << (ffs(pci_bar) - 1);
  372         }
  373 
  374         DEVPRINTF((cbdev, "Opening BAR: type=%s, bar=%02x, len=%04x%s%s\n",
  375             (type == SYS_RES_MEMORY) ? "MEM" : "IO", bar, len,
  376             (type == SYS_RES_MEMORY && dinfo->mprefetchable & BARBIT(bar)) ?
  377             " (Prefetchable)" : "", type == SYS_RES_MEMORY ?
  378             ((dinfo->mbelow1mb & BARBIT(bar)) ? " (Below 1Mb)" : "") : ""));
  379 
  380         resource_list_add(&dinfo->pci.resources, type, bar, 0UL, ~0UL, len);
  381 
  382         /*
  383          * Mark the appropriate bit in the PCI command register so that
  384          * device drivers will know which type of BARs can be used.
  385          */
  386         pci_enable_io(child, type);
  387         return (0);
  388 }
  389 
  390 static int
  391 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
  392     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  393     struct tuple_callbacks *info)
  394 {
  395         /* Make this message suck less XXX */
  396         printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
  397         return (-1);
  398 }
  399 
  400 static int
  401 decode_tuple_end(device_t cbdev, device_t child, int id,
  402     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  403     struct tuple_callbacks *info)
  404 {
  405         if (cardbus_cis_debug)
  406                 printf("CIS reading done\n");
  407         return (0);
  408 }
  409 
  410 /*
  411  * Functions to read the a tuple from the card
  412  */
  413 
  414 static int
  415 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
  416     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  417 {
  418         int i, j;
  419         uint32_t e;
  420         uint32_t loc;
  421 
  422         loc = start + *off;
  423 
  424         e = pci_read_config(child, loc - loc % 4, 4);
  425         for (j = loc % 4; j > 0; j--)
  426                 e >>= 8;
  427         *len = 0;
  428         for (i = loc, j = -2; j < *len; j++, i++) {
  429                 if (i % 4 == 0)
  430                         e = pci_read_config(child, i, 4);
  431                 if (j == -2)
  432                         *tupleid = 0xff & e;
  433                 else if (j == -1)
  434                         *len = 0xff & e;
  435                 else
  436                         tupledata[j] = 0xff & e;
  437                 e >>= 8;
  438         }
  439         *off += *len + 2;
  440         return (0);
  441 }
  442 
  443 static int
  444 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
  445     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  446 {
  447         bus_space_tag_t bt;
  448         bus_space_handle_t bh;
  449         int ret;
  450 
  451         bt = rman_get_bustag(res);
  452         bh = rman_get_bushandle(res);
  453 
  454         *tupleid = bus_space_read_1(bt, bh, start + *off);
  455         *len = bus_space_read_1(bt, bh, start + *off + 1);
  456         bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
  457         ret = 0;
  458         *off += *len + 2;
  459         return (ret);
  460 }
  461 
  462 static int
  463 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
  464     uint32_t start, uint32_t *off, int *tupleid, int *len,
  465     uint8_t *tupledata)
  466 {
  467         if (res == (struct resource*)~0UL) {
  468                 return (cardbus_read_tuple_conf(cbdev, child, start, off,
  469                     tupleid, len, tupledata));
  470         } else {
  471                 return (cardbus_read_tuple_mem(cbdev, res, start, off,
  472                     tupleid, len, tupledata));
  473         }
  474 }
  475 
  476 static void
  477 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
  478     struct resource *res)
  479 {
  480         if (res != (struct resource*)~0UL) {
  481                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  482                 pci_write_config(child, rid, 0, 4);
  483                 PCI_DISABLE_IO(cbdev, child, SYS_RES_MEMORY);
  484         }
  485 }
  486 
  487 static struct resource *
  488 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
  489     int *rid)
  490 {
  491         uint32_t testval;
  492         uint32_t size;
  493         struct resource *res;
  494 
  495         switch (CARDBUS_CIS_SPACE(*start)) {
  496         case CARDBUS_CIS_ASI_TUPLE:
  497                 /* CIS in PCI config space need no initialization */
  498                 return ((struct resource*)~0UL);
  499         case CARDBUS_CIS_ASI_BAR0:
  500         case CARDBUS_CIS_ASI_BAR1:
  501         case CARDBUS_CIS_ASI_BAR2:
  502         case CARDBUS_CIS_ASI_BAR3:
  503         case CARDBUS_CIS_ASI_BAR4:
  504         case CARDBUS_CIS_ASI_BAR5:
  505                 *rid = CARDBUS_BASE0_REG + (CARDBUS_CIS_SPACE(*start) - 1) * 4;
  506                 break;
  507         case CARDBUS_CIS_ASI_ROM:
  508                 *rid = CARDBUS_ROM_REG;
  509 #if 0
  510                 /*
  511                  * This mask doesn't contain the bit that actually enables
  512                  * the Option ROM.
  513                  */
  514                 pci_write_config(child, *rid, CARDBUS_ROM_ADDRMASK, 4);
  515 #endif
  516                 break;
  517         default:
  518                 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
  519                     CARDBUS_CIS_SPACE(*start));
  520                 return (NULL);
  521         }
  522 
  523         /* figure out how much space we need */
  524         pci_write_config(child, *rid, 0xffffffff, 4);
  525         testval = pci_read_config(child, *rid, 4);
  526 
  527         /*
  528          * This bit has a different meaning depending if we are dealing
  529          * with a normal BAR or an Option ROM BAR.
  530          */
  531         if (((testval & 0x1) == 0x1) && (*rid != CARDBUS_ROM_REG)) {
  532                 device_printf(cbdev, "CIS Space is IO, expecting memory.\n");
  533                 return (NULL);
  534         }
  535 
  536         size = CARDBUS_MAPREG_MEM_SIZE(testval);
  537         /* XXX Is this some kind of hack? */
  538         if (size < 4096)
  539                 size = 4096;
  540         /* allocate the memory space to read CIS */
  541         res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, rid, 0, ~0, size,
  542             rman_make_alignment_flags(size) | RF_ACTIVE);
  543         if (res == NULL) {
  544                 device_printf(cbdev, "Unable to allocate resource "
  545                     "to read CIS.\n");
  546                 return (NULL);
  547         }
  548         pci_write_config(child, *rid,
  549             rman_get_start(res) | ((*rid == CARDBUS_ROM_REG)?
  550                 CARDBUS_ROM_ENABLE : 0),
  551             4);
  552         PCI_ENABLE_IO(cbdev, child, SYS_RES_MEMORY);
  553 
  554         /* Flip to the right ROM image if CIS is in ROM */
  555         if (CARDBUS_CIS_SPACE(*start) == CARDBUS_CIS_ASI_ROM) {
  556                 bus_space_tag_t bt;
  557                 bus_space_handle_t bh;
  558                 uint32_t imagesize;
  559                 uint32_t imagebase = 0;
  560                 uint32_t pcidata;
  561                 uint16_t romsig;
  562                 int romnum = 0;
  563                 int imagenum;
  564 
  565                 bt = rman_get_bustag(res);
  566                 bh = rman_get_bushandle(res);
  567 
  568                 imagenum = CARDBUS_CIS_ASI_ROM_IMAGE(*start);
  569                 for (romnum = 0;; romnum++) {
  570                         romsig = bus_space_read_2(bt, bh,
  571                             imagebase + CARDBUS_EXROM_SIGNATURE);
  572                         if (romsig != 0xaa55) {
  573                                 device_printf(cbdev, "Bad header in rom %d: "
  574                                     "[%x] %04x\n", romnum, imagebase +
  575                                     CARDBUS_EXROM_SIGNATURE, romsig);
  576                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  577                                     *rid, res);
  578                                 *rid = 0;
  579                                 return (NULL);
  580                         }
  581 
  582                         /*
  583                          * If this was the Option ROM image that we were
  584                          * looking for, then we are done.
  585                          */
  586                         if (romnum == imagenum)
  587                                 break;
  588 
  589                         /* Find out where the next Option ROM image is */
  590                         pcidata = imagebase + bus_space_read_2(bt, bh,
  591                             imagebase + CARDBUS_EXROM_DATA_PTR);
  592                         imagesize = bus_space_read_2(bt, bh,
  593                             pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
  594 
  595                         if (imagesize == 0) {
  596                                 /*
  597                                  * XXX some ROMs seem to have this as zero,
  598                                  * can we assume this means 1 block?
  599                                  */
  600                                 device_printf(cbdev, "Warning, size of Option "
  601                                     "ROM image %d is 0 bytes, assuming 512 "
  602                                     "bytes.\n", romnum);
  603                                 imagesize = 1;
  604                         }
  605 
  606                         /* Image size is in 512 byte units */
  607                         imagesize <<= 9;
  608 
  609                         if ((bus_space_read_1(bt, bh, pcidata +
  610                             CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
  611                                 device_printf(cbdev, "Cannot find CIS in "
  612                                     "Option ROM\n");
  613                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  614                                     *rid, res);
  615                                 *rid = 0;
  616                                 return (NULL);
  617                         }
  618                         imagebase += imagesize;
  619                 }
  620                 *start = imagebase + CARDBUS_CIS_ADDR(*start);
  621         } else {
  622                 *start = CARDBUS_CIS_ADDR(*start);
  623         }
  624 
  625         return (res);
  626 }
  627 
  628 /*
  629  * Dispatch the right handler function per tuple
  630  */
  631 
  632 static int
  633 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
  634     uint8_t *tupledata, uint32_t start, uint32_t *off,
  635     struct tuple_callbacks *callbacks)
  636 {
  637         int i;
  638         for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
  639                 if (tupleid == callbacks[i].id)
  640                         return (callbacks[i].func(cbdev, child, tupleid, len,
  641                             tupledata, start, off, &callbacks[i]));
  642         }
  643         return (callbacks[i].func(cbdev, child, tupleid, len,
  644             tupledata, start, off, NULL));
  645 }
  646 
  647 static int
  648 cardbus_parse_cis(device_t cbdev, device_t child,
  649     struct tuple_callbacks *callbacks)
  650 {
  651         uint8_t tupledata[MAXTUPLESIZE];
  652         int tupleid;
  653         int len;
  654         int expect_linktarget;
  655         uint32_t start, off;
  656         struct resource *res;
  657         int rid;
  658 
  659         bzero(tupledata, MAXTUPLESIZE);
  660         expect_linktarget = TRUE;
  661         if ((start = pci_read_config(child, CARDBUS_CIS_REG, 4)) == 0) {
  662                 device_printf(cbdev, "CIS pointer is 0!\n");
  663                 return (ENXIO);
  664         }
  665         off = 0;
  666         res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
  667         if (res == NULL) {
  668                 device_printf(cbdev, "Unable to allocate resources for CIS\n");
  669                 return (ENXIO);
  670         }
  671 
  672         do {
  673                 if (0 != cardbus_read_tuple(cbdev, child, res, start, &off,
  674                     &tupleid, &len, tupledata)) {
  675                         device_printf(cbdev, "Failed to read CIS.\n");
  676                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  677                         return (ENXIO);
  678                 }
  679 
  680                 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
  681                         device_printf(cbdev, "Expecting link target, got 0x%x\n",
  682                             tupleid);
  683                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  684                         return (EINVAL);
  685                 }
  686                 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
  687                     tupledata, start, &off, callbacks);
  688                 if (expect_linktarget != 0) {
  689                         device_printf(cbdev, "Parsing failed with %d\n",
  690                             expect_linktarget);
  691                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  692                         return (expect_linktarget);
  693                 }
  694         } while (tupleid != CISTPL_END);
  695         cardbus_read_tuple_finish(cbdev, child, rid, res);
  696         return (0);
  697 }
  698 
  699 int
  700 cardbus_do_cis(device_t cbdev, device_t child)
  701 {
  702         int ret;
  703         struct tuple_callbacks init_callbacks[] = {
  704                 MAKETUPLE(LONGLINK_CB,          unhandled),
  705                 MAKETUPLE(INDIRECT,             unhandled),
  706                 MAKETUPLE(LONGLINK_MFC,         unhandled),
  707                 MAKETUPLE(BAR,                  bar),
  708                 MAKETUPLE(LONGLINK_A,           unhandled),
  709                 MAKETUPLE(LONGLINK_C,           unhandled),
  710                 MAKETUPLE(LINKTARGET,           linktarget),
  711                 MAKETUPLE(VERS_1,               vers_1),
  712                 MAKETUPLE(MANFID,               manfid),
  713                 MAKETUPLE(FUNCID,               funcid),
  714                 MAKETUPLE(FUNCE,                funce),
  715                 MAKETUPLE(END,                  end),
  716                 MAKETUPLE(GENERIC,              generic),
  717         };
  718 
  719         ret = cardbus_parse_cis(cbdev, child, init_callbacks);
  720         if (ret < 0)
  721                 return (ret);
  722         return 0;
  723 }

Cache object: 03fb08670e99d3c20b0a8a352beced84


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