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) 2005-2008, M. Warner Losh
    3  * Copyright (c) 2000,2001 Jonathan Chen.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD: releng/8.4/sys/dev/cardbus/cardbus_cis.c 241378 2012-10-09 18:45:08Z jhb $");
   30 
   31 /*
   32  * CIS Handling for the Cardbus Bus
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 
   40 #include <sys/bus.h>
   41 #include <machine/bus.h>
   42 #include <machine/resource.h>
   43 #include <sys/rman.h>
   44 #include <sys/endian.h>
   45 
   46 #include <sys/pciio.h>
   47 #include <dev/pci/pcivar.h>
   48 #include <dev/pci/pcireg.h>
   49 
   50 #include <dev/pccard/pccardvar.h>
   51 #include <dev/pccard/pccard_cis.h>
   52 
   53 #include <dev/cardbus/cardbusreg.h>
   54 #include <dev/cardbus/cardbusvar.h>
   55 #include <dev/cardbus/cardbus_cis.h>
   56 
   57 extern int cardbus_cis_debug;
   58 
   59 #define DPRINTF(a) if (cardbus_cis_debug) printf a
   60 #define DEVPRINTF(x) if (cardbus_cis_debug) device_printf x
   61 
   62 #define CIS_CONFIG_SPACE        (struct resource *)~0UL
   63 
   64 static int decode_tuple_generic(device_t cbdev, device_t child, int id,
   65     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   66     struct tuple_callbacks *info, void *);
   67 static int decode_tuple_linktarget(device_t cbdev, device_t child, int id,
   68     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
   69     struct tuple_callbacks *info, void *);
   70 static int decode_tuple_vers_1(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, void *);
   73 static int decode_tuple_funcid(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, void *);
   76 static int decode_tuple_manfid(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, void *);
   79 static int decode_tuple_funce(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, void *);
   82 static int decode_tuple_bar(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, void *);
   85 static int decode_tuple_unhandled(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, void *);
   88 static int decode_tuple_end(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, void *);
   91 
   92 static int      cardbus_read_tuple_conf(device_t cbdev, device_t child,
   93                     uint32_t start, uint32_t *off, int *tupleid, int *len,
   94                     uint8_t *tupledata);
   95 static int      cardbus_read_tuple_mem(device_t cbdev, struct resource *res,
   96                     uint32_t start, uint32_t *off, int *tupleid, int *len,
   97                     uint8_t *tupledata);
   98 static int      cardbus_read_tuple(device_t cbdev, device_t child,
   99                     struct resource *res, uint32_t start, uint32_t *off,
  100                     int *tupleid, int *len, uint8_t *tupledata);
  101 static void     cardbus_read_tuple_finish(device_t cbdev, device_t child,
  102                     int rid, struct resource *res);
  103 static struct resource  *cardbus_read_tuple_init(device_t cbdev, device_t child,
  104                     uint32_t *start, int *rid);
  105 static int      decode_tuple(device_t cbdev, device_t child, int tupleid,
  106                     int len, uint8_t *tupledata, uint32_t start,
  107                     uint32_t *off, struct tuple_callbacks *callbacks,
  108                     void *);
  109 
  110 #define MAKETUPLE(NAME,FUNC) { CISTPL_ ## NAME, #NAME, decode_tuple_ ## FUNC }
  111 
  112 static char *funcnames[] = {
  113         "Multi-Functioned",
  114         "Memory",
  115         "Serial Port",
  116         "Parallel Port",
  117         "Fixed Disk",
  118         "Video Adaptor",
  119         "Network Adaptor",
  120         "AIMS",
  121         "SCSI",
  122         "Security"
  123 };
  124 
  125 /*
  126  * Handler functions for various CIS tuples
  127  */
  128 
  129 static int
  130 decode_tuple_generic(device_t cbdev, device_t child, int id,
  131     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  132     struct tuple_callbacks *info, void *argp)
  133 {
  134         int i;
  135 
  136         if (cardbus_cis_debug) {
  137                 if (info)
  138                         printf("TUPLE: %s [%d]:", info->name, len);
  139                 else
  140                         printf("TUPLE: Unknown(0x%02x) [%d]:", id, len);
  141 
  142                 for (i = 0; i < len; i++) {
  143                         if (i % 0x10 == 0 && len > 0x10)
  144                                 printf("\n       0x%02x:", i);
  145                         printf(" %02x", tupledata[i]);
  146                 }
  147                 printf("\n");
  148         }
  149         return (0);
  150 }
  151 
  152 static int
  153 decode_tuple_linktarget(device_t cbdev, device_t child, int id,
  154     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  155     struct tuple_callbacks *info, void *argp)
  156 {
  157         int i;
  158 
  159         if (cardbus_cis_debug) {
  160                 printf("TUPLE: %s [%d]:", info->name, len);
  161 
  162                 for (i = 0; i < len; i++) {
  163                         if (i % 0x10 == 0 && len > 0x10)
  164                                 printf("\n       0x%02x:", i);
  165                         printf(" %02x", tupledata[i]);
  166                 }
  167                 printf("\n");
  168         }
  169         if (len != 3 || tupledata[0] != 'C' || tupledata[1] != 'I' ||
  170             tupledata[2] != 'S') {
  171                 printf("Invalid data for CIS Link Target!\n");
  172                 decode_tuple_generic(cbdev, child, id, len, tupledata,
  173                     start, off, info, argp);
  174                 return (EINVAL);
  175         }
  176         return (0);
  177 }
  178 
  179 static int
  180 decode_tuple_vers_1(device_t cbdev, device_t child, int id,
  181     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  182     struct tuple_callbacks *info, void *argp)
  183 {
  184         int i;
  185 
  186         if (cardbus_cis_debug) {
  187                 printf("Product version: %d.%d\n", tupledata[0], tupledata[1]);
  188                 printf("Product name: ");
  189                 for (i = 2; i < len; i++) {
  190                         if (tupledata[i] == '\0')
  191                                 printf(" | ");
  192                         else if (tupledata[i] == 0xff)
  193                                 break;
  194                         else
  195                                 printf("%c", tupledata[i]);
  196                 }
  197                 printf("\n");
  198         }
  199         return (0);
  200 }
  201 
  202 static int
  203 decode_tuple_funcid(device_t cbdev, device_t child, int id,
  204     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  205     struct tuple_callbacks *info, void *argp)
  206 {
  207         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  208         int numnames = sizeof(funcnames) / sizeof(funcnames[0]);
  209         int i;
  210 
  211         if (cardbus_cis_debug) {
  212                 printf("Functions: ");
  213                 for (i = 0; i < len; i++) {
  214                         if (tupledata[i] < numnames)
  215                                 printf("%s", funcnames[tupledata[i]]);
  216                         else
  217                                 printf("Unknown(%d)", tupledata[i]);
  218                         if (i < len - 1)
  219                                 printf(", ");
  220                 }
  221                 printf("\n");
  222         }
  223         if (len > 0)
  224                 dinfo->funcid = tupledata[0];           /* use first in list */
  225         return (0);
  226 }
  227 
  228 static int
  229 decode_tuple_manfid(device_t cbdev, device_t child, int id,
  230     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  231     struct tuple_callbacks *info, void *argp)
  232 {
  233         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  234         int i;
  235 
  236         if (cardbus_cis_debug) {
  237                 printf("Manufacturer ID: ");
  238                 for (i = 0; i < len; i++)
  239                         printf("%02x", tupledata[i]);
  240                 printf("\n");
  241         }
  242 
  243         if (len == 5) {
  244                 dinfo->mfrid = tupledata[1] | (tupledata[2] << 8);
  245                 dinfo->prodid = tupledata[3] | (tupledata[4] << 8);
  246         }
  247         return (0);
  248 }
  249 
  250 static int
  251 decode_tuple_funce(device_t cbdev, device_t child, int id,
  252     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  253     struct tuple_callbacks *info, void *argp)
  254 {
  255         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  256         int type, i;
  257 
  258         if (cardbus_cis_debug) {
  259                 printf("Function Extension: ");
  260                 for (i = 0; i < len; i++)
  261                         printf("%02x", tupledata[i]);
  262                 printf("\n");
  263         }
  264         if (len < 2)                    /* too short */
  265                 return (0);
  266         type = tupledata[0];            /* XXX <32 always? */
  267         switch (dinfo->funcid) {
  268         case PCCARD_FUNCTION_NETWORK:
  269                 switch (type) {
  270                 case PCCARD_TPLFE_TYPE_LAN_NID:
  271                         if (tupledata[1] > sizeof(dinfo->funce.lan.nid)) {
  272                                 /* ignore, warning? */
  273                                 return (0);
  274                         }
  275                         bcopy(tupledata + 2, dinfo->funce.lan.nid,
  276                             tupledata[1]);
  277                         break;
  278                 }
  279                 dinfo->fepresent |= 1<<type;
  280                 break;
  281         }
  282         return (0);
  283 }
  284 
  285 static int
  286 decode_tuple_bar(device_t cbdev, device_t child, int id,
  287     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  288     struct tuple_callbacks *info, void *argp)
  289 {
  290         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  291         int type;
  292         uint8_t reg;
  293         uint32_t bar;
  294 
  295         if (len != 6) {
  296                 device_printf(cbdev, "CIS BAR length not 6 (%d)\n", len);
  297                 return (EINVAL);
  298         }
  299 
  300         reg = *tupledata;
  301         len = le32toh(*(uint32_t*)(tupledata + 2));
  302         if (reg & TPL_BAR_REG_AS)
  303                 type = SYS_RES_IOPORT;
  304         else
  305                 type = SYS_RES_MEMORY;
  306 
  307         bar = reg & TPL_BAR_REG_ASI_MASK;
  308         if (bar == 0) {
  309                 device_printf(cbdev, "Invalid BAR type 0 in CIS\n");
  310                 return (EINVAL);        /* XXX Return an error? */
  311         } else if (bar == 7) {
  312                 /* XXX Should we try to map in Option ROMs? */
  313                 return (0);
  314         }
  315 
  316         /* Convert from BAR type to BAR offset */
  317         bar = PCIR_BAR(bar - 1);
  318 
  319         if (type == SYS_RES_MEMORY) {
  320                 if (reg & TPL_BAR_REG_PREFETCHABLE)
  321                         dinfo->mprefetchable |= (1 << PCI_RID2BAR(bar));
  322                 /*
  323                  * The PC Card spec says we're only supposed to honor this
  324                  * hint when the cardbus bridge is a child of pci0 (the main
  325                  * bus).  The PC Card spec seems to indicate that this should
  326                  * only be done on x86 based machines, which suggests that on
  327                  * non-x86 machines the addresses can be anywhere.  Since the
  328                  * hardware can do it on non-x86 machines, it should be able
  329                  * to do it on x86 machines too.  Therefore, we can and should
  330                  * ignore this hint.  Furthermore, the PC Card spec recommends
  331                  * always allocating memory above 1MB, contradicting the other
  332                  * part of the PC Card spec, it seems.  We make note of it,
  333                  * but otherwise don't use this information.
  334                  *
  335                  * Some Realtek cards have this set in their CIS, but fail
  336                  * to actually work when mapped this way, and experience
  337                  * has shown ignoring this big to be a wise choice.
  338                  *
  339                  * XXX We should cite chapter and verse for standard refs.
  340                  */
  341                 if (reg & TPL_BAR_REG_BELOW1MB)
  342                         dinfo->mbelow1mb |= (1 << PCI_RID2BAR(bar));
  343         }
  344 
  345         return (0);
  346 }
  347 
  348 static int
  349 decode_tuple_unhandled(device_t cbdev, device_t child, int id,
  350     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  351     struct tuple_callbacks *info, void *argp)
  352 {
  353         /* Make this message suck less XXX */
  354         printf("TUPLE: %s [%d] is unhandled! Bailing...", info->name, len);
  355         return (EINVAL);
  356 }
  357 
  358 static int
  359 decode_tuple_end(device_t cbdev, device_t child, int id,
  360     int len, uint8_t *tupledata, uint32_t start, uint32_t *off,
  361     struct tuple_callbacks *info, void *argp)
  362 {
  363         if (cardbus_cis_debug)
  364                 printf("CIS reading done\n");
  365         return (0);
  366 }
  367 
  368 /*
  369  * Functions to read the a tuple from the card
  370  */
  371 
  372 static int
  373 cardbus_read_tuple_conf(device_t cbdev, device_t child, uint32_t start,
  374     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  375 {
  376         int i, j;
  377         uint32_t e;
  378         uint32_t loc;
  379 
  380         loc = start + *off;
  381 
  382         e = pci_read_config(child, loc - loc % 4, 4);
  383         for (j = loc % 4; j > 0; j--)
  384                 e >>= 8;
  385         *len = 0;
  386         for (i = loc, j = -2; j < *len; j++, i++) {
  387                 if (i % 4 == 0)
  388                         e = pci_read_config(child, i, 4);
  389                 if (j == -2)
  390                         *tupleid = 0xff & e;
  391                 else if (j == -1)
  392                         *len = 0xff & e;
  393                 else
  394                         tupledata[j] = 0xff & e;
  395                 e >>= 8;
  396         }
  397         *off += *len + 2;
  398         return (0);
  399 }
  400 
  401 static int
  402 cardbus_read_tuple_mem(device_t cbdev, struct resource *res, uint32_t start,
  403     uint32_t *off, int *tupleid, int *len, uint8_t *tupledata)
  404 {
  405         bus_space_tag_t bt;
  406         bus_space_handle_t bh;
  407         int ret;
  408 
  409         bt = rman_get_bustag(res);
  410         bh = rman_get_bushandle(res);
  411 
  412         *tupleid = bus_space_read_1(bt, bh, start + *off);
  413         *len = bus_space_read_1(bt, bh, start + *off + 1);
  414         bus_space_read_region_1(bt, bh, *off + start + 2, tupledata, *len);
  415         ret = 0;
  416         *off += *len + 2;
  417         return (ret);
  418 }
  419 
  420 static int
  421 cardbus_read_tuple(device_t cbdev, device_t child, struct resource *res,
  422     uint32_t start, uint32_t *off, int *tupleid, int *len,
  423     uint8_t *tupledata)
  424 {
  425         if (res == CIS_CONFIG_SPACE)
  426                 return (cardbus_read_tuple_conf(cbdev, child, start, off,
  427                     tupleid, len, tupledata));
  428         return (cardbus_read_tuple_mem(cbdev, res, start, off, tupleid, len,
  429             tupledata));
  430 }
  431 
  432 static void
  433 cardbus_read_tuple_finish(device_t cbdev, device_t child, int rid,
  434     struct resource *res)
  435 {
  436         if (res != CIS_CONFIG_SPACE) {
  437                 bus_release_resource(child, SYS_RES_MEMORY, rid, res);
  438                 bus_delete_resource(child, SYS_RES_MEMORY, rid);
  439         }
  440 }
  441 
  442 static struct resource *
  443 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
  444     int *rid)
  445 {
  446         struct resource *res;
  447         uint32_t space;
  448 
  449         space = *start & PCIM_CIS_ASI_MASK;
  450         switch (space) {
  451         case PCIM_CIS_ASI_CONFIG:
  452                 DEVPRINTF((cbdev, "CIS in PCI config space\n"));
  453                 /* CIS in PCI config space need no initialization */
  454                 return (CIS_CONFIG_SPACE);
  455         case PCIM_CIS_ASI_BAR0:
  456         case PCIM_CIS_ASI_BAR1:
  457         case PCIM_CIS_ASI_BAR2:
  458         case PCIM_CIS_ASI_BAR3:
  459         case PCIM_CIS_ASI_BAR4:
  460         case PCIM_CIS_ASI_BAR5:
  461                 *rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
  462                 DEVPRINTF((cbdev, "CIS in BAR %#x\n", *rid));
  463                 break;
  464         case PCIM_CIS_ASI_ROM:
  465                 *rid = PCIR_BIOS;
  466                 DEVPRINTF((cbdev, "CIS in option rom\n"));
  467                 break;
  468         default:
  469                 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
  470                     space);
  471                 return (NULL);
  472         }
  473 
  474         /* allocate the memory space to read CIS */
  475         res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid,
  476             rman_make_alignment_flags(4096) | RF_ACTIVE);
  477         if (res == NULL) {
  478                 device_printf(cbdev, "Unable to allocate resource "
  479                     "to read CIS.\n");
  480                 return (NULL);
  481         }
  482         DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
  483 
  484         /* Flip to the right ROM image if CIS is in ROM */
  485         if (space == PCIM_CIS_ASI_ROM) {
  486                 bus_space_tag_t bt;
  487                 bus_space_handle_t bh;
  488                 uint32_t imagesize;
  489                 uint32_t imagebase = 0;
  490                 uint32_t pcidata;
  491                 uint16_t romsig;
  492                 int romnum = 0;
  493                 int imagenum;
  494 
  495                 bt = rman_get_bustag(res);
  496                 bh = rman_get_bushandle(res);
  497 
  498                 imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28;
  499                 for (romnum = 0;; romnum++) {
  500                         romsig = bus_space_read_2(bt, bh,
  501                             imagebase + CARDBUS_EXROM_SIGNATURE);
  502                         if (romsig != 0xaa55) {
  503                                 device_printf(cbdev, "Bad header in rom %d: "
  504                                     "[%x] %04x\n", romnum, imagebase +
  505                                     CARDBUS_EXROM_SIGNATURE, romsig);
  506                                 cardbus_read_tuple_finish(cbdev, child, *rid,
  507                                     res);
  508                                 *rid = 0;
  509                                 return (NULL);
  510                         }
  511 
  512                         /*
  513                          * If this was the Option ROM image that we were
  514                          * looking for, then we are done.
  515                          */
  516                         if (romnum == imagenum)
  517                                 break;
  518 
  519                         /* Find out where the next Option ROM image is */
  520                         pcidata = imagebase + bus_space_read_2(bt, bh,
  521                             imagebase + CARDBUS_EXROM_DATA_PTR);
  522                         imagesize = bus_space_read_2(bt, bh,
  523                             pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
  524 
  525                         if (imagesize == 0) {
  526                                 /*
  527                                  * XXX some ROMs seem to have this as zero,
  528                                  * can we assume this means 1 block?
  529                                  */
  530                                 device_printf(cbdev, "Warning, size of Option "
  531                                     "ROM image %d is 0 bytes, assuming 512 "
  532                                     "bytes.\n", romnum);
  533                                 imagesize = 1;
  534                         }
  535 
  536                         /* Image size is in 512 byte units */
  537                         imagesize <<= 9;
  538 
  539                         if ((bus_space_read_1(bt, bh, pcidata +
  540                             CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
  541                                 device_printf(cbdev, "Cannot find CIS in "
  542                                     "Option ROM\n");
  543                                 cardbus_read_tuple_finish(cbdev, child, *rid,
  544                                     res);
  545                                 *rid = 0;
  546                                 return (NULL);
  547                         }
  548                         imagebase += imagesize;
  549                 }
  550                 *start = imagebase + (*start & PCIM_CIS_ADDR_MASK);
  551         } else {
  552                 *start = *start & PCIM_CIS_ADDR_MASK;
  553         }
  554         DEVPRINTF((cbdev, "CIS offset is %#x\n", *start));
  555 
  556         return (res);
  557 }
  558 
  559 /*
  560  * Dispatch the right handler function per tuple
  561  */
  562 
  563 static int
  564 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
  565     uint8_t *tupledata, uint32_t start, uint32_t *off,
  566     struct tuple_callbacks *callbacks, void *argp)
  567 {
  568         int i;
  569         for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
  570                 if (tupleid == callbacks[i].id)
  571                         return (callbacks[i].func(cbdev, child, tupleid, len,
  572                             tupledata, start, off, &callbacks[i], argp));
  573         }
  574         return (callbacks[i].func(cbdev, child, tupleid, len,
  575             tupledata, start, off, NULL, argp));
  576 }
  577 
  578 int
  579 cardbus_parse_cis(device_t cbdev, device_t child,
  580     struct tuple_callbacks *callbacks, void *argp)
  581 {
  582         uint8_t tupledata[MAXTUPLESIZE];
  583         int tupleid = CISTPL_NULL;
  584         int len;
  585         int expect_linktarget;
  586         uint32_t start, off;
  587         struct resource *res;
  588         int rid;
  589 
  590         bzero(tupledata, MAXTUPLESIZE);
  591         expect_linktarget = TRUE;
  592         if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) {
  593                 DEVPRINTF((cbdev, "Warning: CIS pointer is 0: (no CIS)\n"));
  594                 return (ENXIO);
  595         }
  596         DEVPRINTF((cbdev, "CIS pointer is %#x\n", start));
  597         off = 0;
  598         res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
  599         if (res == NULL) {
  600                 device_printf(cbdev, "Unable to allocate resources for CIS\n");
  601                 return (ENXIO);
  602         }
  603 
  604         do {
  605                 if (cardbus_read_tuple(cbdev, child, res, start, &off,
  606                     &tupleid, &len, tupledata) != 0) {
  607                         device_printf(cbdev, "Failed to read CIS.\n");
  608                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  609                         return (ENXIO);
  610                 }
  611 
  612                 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
  613                         device_printf(cbdev, "Expecting link target, got 0x%x\n",
  614                             tupleid);
  615                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  616                         return (EINVAL);
  617                 }
  618                 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
  619                     tupledata, start, &off, callbacks, argp);
  620                 if (expect_linktarget != 0) {
  621                         device_printf(cbdev, "Parsing failed with %d\n",
  622                             expect_linktarget);
  623                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  624                         return (expect_linktarget);
  625                 }
  626         } while (tupleid != CISTPL_END);
  627         cardbus_read_tuple_finish(cbdev, child, rid, res);
  628         return (0);
  629 }
  630 
  631 int
  632 cardbus_do_cis(device_t cbdev, device_t child)
  633 {
  634         struct tuple_callbacks init_callbacks[] = {
  635                 MAKETUPLE(LONGLINK_CB,          unhandled),
  636                 MAKETUPLE(INDIRECT,             unhandled),
  637                 MAKETUPLE(LONGLINK_MFC,         unhandled),
  638                 MAKETUPLE(BAR,                  bar),
  639                 MAKETUPLE(LONGLINK_A,           unhandled),
  640                 MAKETUPLE(LONGLINK_C,           unhandled),
  641                 MAKETUPLE(LINKTARGET,           linktarget),
  642                 MAKETUPLE(VERS_1,               vers_1),
  643                 MAKETUPLE(MANFID,               manfid),
  644                 MAKETUPLE(FUNCID,               funcid),
  645                 MAKETUPLE(FUNCE,                funce),
  646                 MAKETUPLE(END,                  end),
  647                 MAKETUPLE(GENERIC,              generic),
  648         };
  649 
  650         return (cardbus_parse_cis(cbdev, child, init_callbacks, NULL));
  651 }

Cache object: c6c1e17154f2f07471a9063c30475f47


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