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$");
   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 #define CIS_CONFIG_SPACE        (struct resource *)~0UL
   62 
   63 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
   64     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   65     struct tuple_callbacks *info, void *);
   66 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
   67     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   68     struct tuple_callbacks *info, void *);
   69 static int decode_tuple_vers_1(device_t cbdev, device_t child, int id,
   70     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   71     struct tuple_callbacks *info, void *);
   72 static int decode_tuple_funcid(device_t cbdev, device_t child, int id,
   73     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   74     struct tuple_callbacks *info, void *);
   75 static int decode_tuple_manfid(device_t cbdev, device_t child, int id,
   76     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   77     struct tuple_callbacks *info, void *);
   78 static int decode_tuple_funce(device_t cbdev, device_t child, int id,
   79     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   80     struct tuple_callbacks *info, void *);
   81 static int decode_tuple_bar(device_t cbdev, device_t child, int id,
   82     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   83     struct tuple_callbacks *info, void *);
   84 static int decode_tuple_unhandled(device_t cbdev, device_t child, int id,
   85     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   86     struct tuple_callbacks *info, void *);
   87 static int decode_tuple_end(device_t cbdev, device_t child, int id,
   88     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   89     struct tuple_callbacks *info, void *);
   90 
   91 static int      cardbus_read_tuple_conf(device_t cbdev, device_t child,
   92                     uint32_t start, uint32_t *off, int *tupleid, int *len,
   93                     uint8_t *tupledata);
   94 static int      cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
   95                     uint32_t start, uint32_t *off, int *tupleid, int *len,
   96                     uint8_t *tupledata);
   97 static int      cardbus_read_tuple(device_t cbdev, device_t child,
   98                     struct resource *res, uint32_t start, uint32_t *off,
   99                     int *tupleid, int *len, uint8_t *tupledata);
  100 static void     cardbus_read_tuple_finish(device_t cbdev, device_t child,
  101                     int rid, struct resource *res);
  102 static struct resource  *cardbus_read_tuple_init(device_t cbdev, device_t child,
  103                     uint32_t *start, int *rid);
  104 static int      decode_tuple(device_t cbdev, device_t child, int tupleid,
  105                     int len, uint8_t *tupledata, uint32_t start,
  106                     uint32_t *off, struct tuple_callbacks *callbacks,
  107                     void *);
  108 
  109 #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
  110 
  111 static char *funcnames[] = {
  112         "Multi-Functioned",
  113         "Memory",
  114         "Serial Port",
  115         "Parallel Port",
  116         "Fixed Disk",
  117         "Video Adaptor",
  118         "Network Adaptor",
  119         "AIMS",
  120         "SCSI",
  121         "Security"
  122 };
  123 
  124 /*
  125  * Handler functions for various CIS tuples
  126  */
  127 
  128 static int
  129 decode_tuple_generic(device_t cbdev, device_t child, int id,
  130     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  131     struct tuple_callbacks *info, void *argp)
  132 {
  133         int i;
  134 
  135         if (cardbus_cis_debug) {
  136                 if (info)
  137                         printf("TUPLE: %s [%d]:", info->name, len);
  138                 else
  139                         printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
  140 
  141                 for (i = 0; i < len; i++) {
  142                         if (i % 0x10 == 0 && len > 0x10)
  143                                 printf("\n       0x%02x:", i);
  144                         printf(" %02x", tupledata[i]);
  145                 }
  146                 printf("\n");
  147         }
  148         return (0);
  149 }
  150 
  151 static int
  152 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
  153     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  154     struct tuple_callbacks *info, void *argp)
  155 {
  156         int i;
  157 
  158         if (cardbus_cis_debug) {
  159                 printf("TUPLE: %s [%d]:", info->name, len);
  160 
  161                 for (i = 0; i < len; i++) {
  162                         if (i % 0x10 == 0 && len > 0x10)
  163                                 printf("\n       0x%02x:", i);
  164                         printf(" %02x", tupledata[i]);
  165                 }
  166                 printf("\n");
  167         }
  168         if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
  169             tupledata[2] != 'S') {
  170                 printf("Invalid data for CIS Link Target!\n");
  171                 decode_tuple_generic(cbdev, child, id, len, tupledata,
  172                     start, off, info, argp);
  173                 return (EINVAL);
  174         }
  175         return (0);
  176 }
  177 
  178 static int
  179 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
  180     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  181     struct tuple_callbacks *info, void *argp)
  182 {
  183         int i;
  184 
  185         if (cardbus_cis_debug) {
  186                 printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
  187                 printf("Product name: ");
  188                 for (i = 2; i < len; i++) {
  189                         if (tupledata[i] == '\0')
  190                                 printf(" | ");
  191                         else if (tupledata[i] == 0xff)
  192                                 break;
  193                         else
  194                                 printf("%c", tupledata[i]);
  195                 }
  196                 printf("\n");
  197         }
  198         return (0);
  199 }
  200 
  201 static int
  202 decode_tuple_funcid(device_t cbdev, device_t child, int id,
  203     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  204     struct tuple_callbacks *info, void *argp)
  205 {
  206         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  207         int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
  208         int i;
  209 
  210         if (cardbus_cis_debug) {
  211                 printf("Functions: ");
  212                 for (i = 0; i < len; i++) {
  213                         if (tupledata[i] < numnames)
  214                                 printf("%s", funcnames[tupledata[i]]);
  215                         else
  216                                 printf("Unknown(%d)", tupledata[i]);
  217                         if (i < len - 1)
  218                                 printf(", ");
  219                 }
  220                 printf("\n");
  221         }
  222         if (len > 0)
  223                 dinfo->funcid = tupledata[0];           /* use first in list */
  224         return (0);
  225 }
  226 
  227 static int
  228 decode_tuple_manfid(device_t cbdev, device_t child, int id,
  229     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  230     struct tuple_callbacks *info, void *argp)
  231 {
  232         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  233         int i;
  234 
  235         if (cardbus_cis_debug) {
  236                 printf("Manufacturer ID: ");
  237                 for (i = 0; i < len; i++)
  238                         printf("%02x", tupledata[i]);
  239                 printf("\n");
  240         }
  241 
  242         if (len == 5) {
  243                 dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
  244                 dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
  245         }
  246         return (0);
  247 }
  248 
  249 static int
  250 decode_tuple_funce(device_t cbdev, device_t child, int id,
  251     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  252     struct tuple_callbacks *info, void *argp)
  253 {
  254         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  255         int type, i;
  256 
  257         if (cardbus_cis_debug) {
  258                 printf("Function Extension: ");
  259                 for (i = 0; i < len; i++)
  260                         printf("%02x", tupledata[i]);
  261                 printf("\n");
  262         }
  263         if (len < 2)                    /* too short */
  264                 return (0);
  265         type = tupledata[0];            /* XXX <32 always? */
  266         switch (dinfo->funcid) {
  267         case PCCARD_FUNCTION_NETWORK:
  268                 switch (type) {
  269                 case PCCARD_TPLFE_TYPE_LAN_NID:
  270                         if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
  271                                 /* ignore, warning? */
  272                                 return (0);
  273                         }
  274                         bcopy(tupledata + 2, dinfo->funce.lan.nid,
  275                             tupledata[1]);
  276                         break;
  277                 }
  278                 dinfo->fepresent |= 1<<type;
  279                 break;
  280         }
  281         return (0);
  282 }
  283 
  284 static int
  285 decode_tuple_bar(device_t cbdev, device_t child, int id,
  286     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  287     struct tuple_callbacks *info, void *argp)
  288 {
  289         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  290         int type;
  291         uint8_t reg;
  292         uint32_t bar;
  293 
  294         if (len != 6) {
  295                 device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
  296                 return (EINVAL);
  297         }
  298 
  299         reg = *tupledata;
  300         len = le32toh(*(uint32_t*)(tupledata + 2));
  301         if (reg & TPL_BAR_REG_AS)
  302                 type = SYS_RES_IOPORT;
  303         else
  304                 type = SYS_RES_MEMORY;
  305 
  306         bar = reg & TPL_BAR_REG_ASI_MASK;
  307         if (bar == 0) {
  308                 device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
  309                 return (EINVAL);        /* XXX Return an error? */
  310         } else if (bar == 7) {
  311                 /* XXX Should we try to map in Option ROMs? */
  312                 return (0);
  313         }
  314 
  315         /* Convert from BAR type to BAR offset */
  316         bar = PCIR_BAR(bar - 1);
  317 
  318         if (type == SYS_RES_MEMORY) {
  319                 if (reg & TPL_BAR_REG_PREFETCHABLE)
  320                         dinfo->mprefetchable |= (1 << PCI_RID2BAR(bar));
  321 #if 0
  322                 /*
  323                  * XXX: It appears from a careful reading of the spec
  324                  * that we're not supposed to honor this when the bridge
  325                  * is not on the main system bus.  PCI spec doesn't appear
  326                  * to allow for memory ranges not listed in the bridge's
  327                  * decode range to be decoded.  The PC Card spec seems to
  328                  * indicate that this should only be done on x86 based
  329                  * machines, which seems to imply that on non-x86 machines
  330                  * the adddresses can be anywhere.  This further implies that
  331                  * since the hardware can do it on non-x86 machines, it should
  332                  * be able to do it on x86 machines.  Therefore, we can and
  333                  * should ignore this hint.  Furthermore, the PC Card spec
  334                  * recommends always allocating memory above 1MB, contradicting
  335                  * the other part of the PC Card spec.
  336                  *
  337                  * NetBSD ignores this bit, but it also ignores the
  338                  * prefetchable bit too, so that's not an indication of
  339                  * correctness.
  340                  */
  341                 if (reg & TPL_BAR_REG_BELOW1MB)
  342                         dinfo->mbelow1mb |= (1 << PCI_RID2BAR(bar));
  343 #endif
  344         }
  345 
  346         return (0);
  347 }
  348 
  349 static int
  350 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
  351     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  352     struct tuple_callbacks *info, void *argp)
  353 {
  354         /* Make this message suck less XXX */
  355         printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
  356         return (EINVAL);
  357 }
  358 
  359 static int
  360 decode_tuple_end(device_t cbdev, device_t child, int id,
  361     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  362     struct tuple_callbacks *info, void *argp)
  363 {
  364         if (cardbus_cis_debug)
  365                 printf("CIS reading done\n");
  366         return (0);
  367 }
  368 
  369 /*
  370  * Functions to read the a tuple from the card
  371  */
  372 
  373 static int
  374 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
  375     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  376 {
  377         int i, j;
  378         uint32_t e;
  379         uint32_t loc;
  380 
  381         loc = start + *off;
  382 
  383         e = pci_read_config(child, loc - loc % 4, 4);
  384         for (j = loc % 4; j > 0; j--)
  385                 e >>= 8;
  386         *len = 0;
  387         for (i = loc, j = -2; j < *len; j++, i++) {
  388                 if (i % 4 == 0)
  389                         e = pci_read_config(child, i, 4);
  390                 if (j == -2)
  391                         *tupleid = 0xff & e;
  392                 else if (j == -1)
  393                         *len = 0xff & e;
  394                 else
  395                         tupledata[j] = 0xff & e;
  396                 e >>= 8;
  397         }
  398         *off += *len + 2;
  399         return (0);
  400 }
  401 
  402 static int
  403 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
  404     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  405 {
  406         bus_space_tag_t bt;
  407         bus_space_handle_t bh;
  408         int ret;
  409 
  410         bt = rman_get_bustag(res);
  411         bh = rman_get_bushandle(res);
  412 
  413         *tupleid = bus_space_read_1(bt, bh, start + *off);
  414         *len = bus_space_read_1(bt, bh, start + *off + 1);
  415         bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
  416         ret = 0;
  417         *off += *len + 2;
  418         return (ret);
  419 }
  420 
  421 static int
  422 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
  423     uint32_t start, uint32_t *off, int *tupleid, int *len,
  424     uint8_t *tupledata)
  425 {
  426         if (res == CIS_CONFIG_SPACE)
  427                 return (cardbus_read_tuple_conf(cbdev, child, start, off,
  428                     tupleid, len, tupledata));
  429         return (cardbus_read_tuple_mem(cbdev, res, start, off, tupleid, len,
  430             tupledata));
  431 }
  432 
  433 static void
  434 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
  435     struct resource *res)
  436 {
  437         if (res != CIS_CONFIG_SPACE) {
  438                 bus_release_resource(child, SYS_RES_MEMORY, rid, res);
  439                 if (rid == PCIM_CIS_ASI_ROM)
  440                         pci_write_config(child, rid, pci_read_config(child,
  441                             rid, 4) & ~PCIR_BIOS, 4);
  442         }
  443 }
  444 
  445 static struct resource *
  446 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
  447     int *rid)
  448 {
  449         struct resource *res;
  450         uint32_t space;
  451 
  452         space = *start & PCIM_CIS_ASI_MASK;
  453         switch (space) {
  454         case PCIM_CIS_ASI_CONFIG:
  455                 if (cardbus_cis_debug)
  456                         device_printf(cbdev, "CIS in PCI config space\n");
  457                 /* CIS in PCI config space need no initialization */
  458                 return (CIS_CONFIG_SPACE);
  459         case PCIM_CIS_ASI_BAR0:
  460         case PCIM_CIS_ASI_BAR1:
  461         case PCIM_CIS_ASI_BAR2:
  462         case PCIM_CIS_ASI_BAR3:
  463         case PCIM_CIS_ASI_BAR4:
  464         case PCIM_CIS_ASI_BAR5:
  465                 *rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
  466                 if (cardbus_cis_debug)
  467                         device_printf(cbdev, "CIS in BAR %#x\n", *rid);
  468                 break;
  469         case PCIM_CIS_ASI_ROM:
  470                 *rid = PCIR_BIOS;
  471                 if (cardbus_cis_debug)
  472                         device_printf(cbdev, "CIS in option rom\n");
  473                 break;
  474         default:
  475                 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
  476                     space);
  477                 return (NULL);
  478         }
  479 
  480         /* allocate the memory space to read CIS */
  481         res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1,
  482             rman_make_alignment_flags(4096) | RF_ACTIVE);
  483         if (res == NULL) {
  484                 device_printf(cbdev, "Unable to allocate resource "
  485                     "to read CIS.\n");
  486                 return (NULL);
  487         }
  488         if (*rid == PCIR_BIOS)
  489                 pci_write_config(child, *rid,
  490                     rman_get_start(res) | PCIM_BIOS_ENABLE, 4);
  491 
  492         /* Flip to the right ROM image if CIS is in ROM */
  493         if (space == PCIM_CIS_ASI_ROM) {
  494                 bus_space_tag_t bt;
  495                 bus_space_handle_t bh;
  496                 uint32_t imagesize;
  497                 uint32_t imagebase = 0;
  498                 uint32_t pcidata;
  499                 uint16_t romsig;
  500                 int romnum = 0;
  501                 int imagenum;
  502 
  503                 bt = rman_get_bustag(res);
  504                 bh = rman_get_bushandle(res);
  505 
  506                 imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28;
  507                 for (romnum = 0;; romnum++) {
  508                         romsig = bus_space_read_2(bt, bh,
  509                             imagebase + CARDBUS_EXROM_SIGNATURE);
  510                         if (romsig != 0xaa55) {
  511                                 device_printf(cbdev, "Bad header in rom %d: "
  512                                     "[%x] %04x\n", romnum, imagebase +
  513                                     CARDBUS_EXROM_SIGNATURE, romsig);
  514                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  515                                     *rid, res);
  516                                 *rid = 0;
  517                                 return (NULL);
  518                         }
  519 
  520                         /*
  521                          * If this was the Option ROM image that we were
  522                          * looking for, then we are done.
  523                          */
  524                         if (romnum == imagenum)
  525                                 break;
  526 
  527                         /* Find out where the next Option ROM image is */
  528                         pcidata = imagebase + bus_space_read_2(bt, bh,
  529                             imagebase + CARDBUS_EXROM_DATA_PTR);
  530                         imagesize = bus_space_read_2(bt, bh,
  531                             pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
  532 
  533                         if (imagesize == 0) {
  534                                 /*
  535                                  * XXX some ROMs seem to have this as zero,
  536                                  * can we assume this means 1 block?
  537                                  */
  538                                 device_printf(cbdev, "Warning, size of Option "
  539                                     "ROM image %d is 0 bytes, assuming 512 "
  540                                     "bytes.\n", romnum);
  541                                 imagesize = 1;
  542                         }
  543 
  544                         /* Image size is in 512 byte units */
  545                         imagesize <<= 9;
  546 
  547                         if ((bus_space_read_1(bt, bh, pcidata +
  548                             CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
  549                                 device_printf(cbdev, "Cannot find CIS in "
  550                                     "Option ROM\n");
  551                                 bus_release_resource(cbdev, SYS_RES_MEMORY,
  552                                     *rid, res);
  553                                 *rid = 0;
  554                                 return (NULL);
  555                         }
  556                         imagebase += imagesize;
  557                 }
  558                 *start = imagebase + (*start & PCIM_CIS_ADDR_MASK);
  559         } else {
  560                 *start = *start & PCIM_CIS_ADDR_MASK;
  561         }
  562 
  563         return (res);
  564 }
  565 
  566 /*
  567  * Dispatch the right handler function per tuple
  568  */
  569 
  570 static int
  571 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
  572     uint8_t *tupledata, uint32_t start, uint32_t *off,
  573     struct tuple_callbacks *callbacks, void *argp)
  574 {
  575         int i;
  576         for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
  577                 if (tupleid == callbacks[i].id)
  578                         return (callbacks[i].func(cbdev, child, tupleid, len,
  579                             tupledata, start, off, &callbacks[i], argp));
  580         }
  581         return (callbacks[i].func(cbdev, child, tupleid, len,
  582             tupledata, start, off, NULL, argp));
  583 }
  584 
  585 int
  586 cardbus_parse_cis(device_t cbdev, device_t child,
  587     struct tuple_callbacks *callbacks, void *argp)
  588 {
  589         uint8_t tupledata[MAXTUPLESIZE];
  590         int tupleid = CISTPL_NULL;
  591         int len;
  592         int expect_linktarget;
  593         uint32_t start, off;
  594         struct resource *res;
  595         int rid;
  596 
  597         bzero(tupledata, MAXTUPLESIZE);
  598         expect_linktarget = TRUE;
  599         if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) {
  600                 if (cardbus_cis_debug)
  601                         device_printf(cbdev,
  602                             "Warning: CIS pointer 0 (no CIS present)\n");
  603                 return (ENXIO);
  604         }
  605         if (cardbus_cis_debug)
  606                 device_printf(cbdev, "CIS pointer is %#x\n", start);
  607         off = 0;
  608         res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
  609         if (res == NULL) {
  610                 device_printf(cbdev, "Unable to allocate resources for CIS\n");
  611                 return (ENXIO);
  612         }
  613 
  614         do {
  615                 if (cardbus_read_tuple(cbdev, child, res, start, &off,
  616                     &tupleid, &len, tupledata) != 0) {
  617                         device_printf(cbdev, "Failed to read CIS.\n");
  618                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  619                         return (ENXIO);
  620                 }
  621 
  622                 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
  623                         device_printf(cbdev, "Expecting link target, got 0x%x\n",
  624                             tupleid);
  625                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  626                         return (EINVAL);
  627                 }
  628                 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
  629                     tupledata, start, &off, callbacks, argp);
  630                 if (expect_linktarget != 0) {
  631                         device_printf(cbdev, "Parsing failed with %d\n",
  632                             expect_linktarget);
  633                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  634                         return (expect_linktarget);
  635                 }
  636         } while (tupleid != CISTPL_END);
  637         cardbus_read_tuple_finish(cbdev, child, rid, res);
  638         return (0);
  639 }
  640 
  641 int
  642 cardbus_do_cis(device_t cbdev, device_t child)
  643 {
  644         struct tuple_callbacks init_callbacks[] = {
  645                 MAKETUPLE(LONGLINK_CB,          unhandled),
  646                 MAKETUPLE(INDIRECT,             unhandled),
  647                 MAKETUPLE(LONGLINK_MFC,         unhandled),
  648                 MAKETUPLE(BAR,                  bar),
  649                 MAKETUPLE(LONGLINK_A,           unhandled),
  650                 MAKETUPLE(LONGLINK_C,           unhandled),
  651                 MAKETUPLE(LINKTARGET,           linktarget),
  652                 MAKETUPLE(VERS_1,               vers_1),
  653                 MAKETUPLE(MANFID,               manfid),
  654                 MAKETUPLE(FUNCID,               funcid),
  655                 MAKETUPLE(FUNCE,                funce),
  656                 MAKETUPLE(END,                  end),
  657                 MAKETUPLE(GENERIC,              generic),
  658         };
  659 
  660         return (cardbus_parse_cis(cbdev, child, init_callbacks, NULL));
  661 }

Cache object: b5ddf615138b5df7a3fb962f5f8e5e3b


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