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

Cache object: 9edbf5e3814fceaa0adea3b9740d2172


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