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.0/sys/dev/cardbus/cardbus_cis.c 189755 2009-03-13 05:31:27Z imp $");
   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 adddresses 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                 if (rid == PCIM_CIS_ASI_ROM)
  439                         pci_write_config(child, rid, pci_read_config(child,
  440                             rid, 4) & ~PCIR_BIOS, 4);
  441         }
  442 }
  443 
  444 static struct resource *
  445 cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start,
  446     int *rid)
  447 {
  448         struct resource *res;
  449         uint32_t space;
  450 
  451         space = *start & PCIM_CIS_ASI_MASK;
  452         switch (space) {
  453         case PCIM_CIS_ASI_CONFIG:
  454                 DEVPRINTF((cbdev, "CIS in PCI config space\n"));
  455                 /* CIS in PCI config space need no initialization */
  456                 return (CIS_CONFIG_SPACE);
  457         case PCIM_CIS_ASI_BAR0:
  458         case PCIM_CIS_ASI_BAR1:
  459         case PCIM_CIS_ASI_BAR2:
  460         case PCIM_CIS_ASI_BAR3:
  461         case PCIM_CIS_ASI_BAR4:
  462         case PCIM_CIS_ASI_BAR5:
  463                 *rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0);
  464                 DEVPRINTF((cbdev, "CIS in BAR %#x\n", *rid));
  465                 break;
  466         case PCIM_CIS_ASI_ROM:
  467                 *rid = PCIR_BIOS;
  468                 DEVPRINTF((cbdev, "CIS in option rom\n"));
  469                 break;
  470         default:
  471                 device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n",
  472                     space);
  473                 return (NULL);
  474         }
  475 
  476         /* allocate the memory space to read CIS */
  477         res = bus_alloc_resource(child, SYS_RES_MEMORY, rid, 0, ~0, 1,
  478             rman_make_alignment_flags(4096) | RF_ACTIVE);
  479         if (res == NULL) {
  480                 device_printf(cbdev, "Unable to allocate resource "
  481                     "to read CIS.\n");
  482                 return (NULL);
  483         }
  484         DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res)));
  485         if (*rid == PCIR_BIOS)
  486                 pci_write_config(child, *rid,
  487                     rman_get_start(res) | PCIM_BIOS_ENABLE, 4);
  488 
  489         /* Flip to the right ROM image if CIS is in ROM */
  490         if (space == PCIM_CIS_ASI_ROM) {
  491                 bus_space_tag_t bt;
  492                 bus_space_handle_t bh;
  493                 uint32_t imagesize;
  494                 uint32_t imagebase = 0;
  495                 uint32_t pcidata;
  496                 uint16_t romsig;
  497                 int romnum = 0;
  498                 int imagenum;
  499 
  500                 bt = rman_get_bustag(res);
  501                 bh = rman_get_bushandle(res);
  502 
  503                 imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28;
  504                 for (romnum = 0;; romnum++) {
  505                         romsig = bus_space_read_2(bt, bh,
  506                             imagebase + CARDBUS_EXROM_SIGNATURE);
  507                         if (romsig != 0xaa55) {
  508                                 device_printf(cbdev, "Bad header in rom %d: "
  509                                     "[%x] %04x\n", romnum, imagebase +
  510                                     CARDBUS_EXROM_SIGNATURE, romsig);
  511                                 bus_release_resource(child, SYS_RES_MEMORY,
  512                                     *rid, res);
  513                                 *rid = 0;
  514                                 return (NULL);
  515                         }
  516 
  517                         /*
  518                          * If this was the Option ROM image that we were
  519                          * looking for, then we are done.
  520                          */
  521                         if (romnum == imagenum)
  522                                 break;
  523 
  524                         /* Find out where the next Option ROM image is */
  525                         pcidata = imagebase + bus_space_read_2(bt, bh,
  526                             imagebase + CARDBUS_EXROM_DATA_PTR);
  527                         imagesize = bus_space_read_2(bt, bh,
  528                             pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH);
  529 
  530                         if (imagesize == 0) {
  531                                 /*
  532                                  * XXX some ROMs seem to have this as zero,
  533                                  * can we assume this means 1 block?
  534                                  */
  535                                 device_printf(cbdev, "Warning, size of Option "
  536                                     "ROM image %d is 0 bytes, assuming 512 "
  537                                     "bytes.\n", romnum);
  538                                 imagesize = 1;
  539                         }
  540 
  541                         /* Image size is in 512 byte units */
  542                         imagesize <<= 9;
  543 
  544                         if ((bus_space_read_1(bt, bh, pcidata +
  545                             CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) {
  546                                 device_printf(cbdev, "Cannot find CIS in "
  547                                     "Option ROM\n");
  548                                 bus_release_resource(child, SYS_RES_MEMORY,
  549                                     *rid, res);
  550                                 *rid = 0;
  551                                 return (NULL);
  552                         }
  553                         imagebase += imagesize;
  554                 }
  555                 *start = imagebase + (*start & PCIM_CIS_ADDR_MASK);
  556         } else {
  557                 *start = *start & PCIM_CIS_ADDR_MASK;
  558         }
  559         DEVPRINTF((cbdev, "CIS offset is %#x\n", *start));
  560 
  561         return (res);
  562 }
  563 
  564 /*
  565  * Dispatch the right handler function per tuple
  566  */
  567 
  568 static int
  569 decode_tuple(device_t cbdev, device_t child, int tupleid, int len,
  570     uint8_t *tupledata, uint32_t start, uint32_t *off,
  571     struct tuple_callbacks *callbacks, void *argp)
  572 {
  573         int i;
  574         for (i = 0; callbacks[i].id != CISTPL_GENERIC; i++) {
  575                 if (tupleid == callbacks[i].id)
  576                         return (callbacks[i].func(cbdev, child, tupleid, len,
  577                             tupledata, start, off, &callbacks[i], argp));
  578         }
  579         return (callbacks[i].func(cbdev, child, tupleid, len,
  580             tupledata, start, off, NULL, argp));
  581 }
  582 
  583 int
  584 cardbus_parse_cis(device_t cbdev, device_t child,
  585     struct tuple_callbacks *callbacks, void *argp)
  586 {
  587         uint8_t tupledata[MAXTUPLESIZE];
  588         int tupleid = CISTPL_NULL;
  589         int len;
  590         int expect_linktarget;
  591         uint32_t start, off;
  592         struct resource *res;
  593         int rid;
  594 
  595         bzero(tupledata, MAXTUPLESIZE);
  596         expect_linktarget = TRUE;
  597         if ((start = pci_read_config(child, PCIR_CIS, 4)) == 0) {
  598                 DEVPRINTF((cbdev, "Warning: CIS pointer is 0: (no CIS)\n"));
  599                 return (ENXIO);
  600         }
  601         DEVPRINTF((cbdev, "CIS pointer is %#x\n", start));
  602         off = 0;
  603         res = cardbus_read_tuple_init(cbdev, child, &start, &rid);
  604         if (res == NULL) {
  605                 device_printf(cbdev, "Unable to allocate resources for CIS\n");
  606                 return (ENXIO);
  607         }
  608 
  609         do {
  610                 if (cardbus_read_tuple(cbdev, child, res, start, &off,
  611                     &tupleid, &len, tupledata) != 0) {
  612                         device_printf(cbdev, "Failed to read CIS.\n");
  613                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  614                         return (ENXIO);
  615                 }
  616 
  617                 if (expect_linktarget && tupleid != CISTPL_LINKTARGET) {
  618                         device_printf(cbdev, "Expecting link target, got 0x%x\n",
  619                             tupleid);
  620                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  621                         return (EINVAL);
  622                 }
  623                 expect_linktarget = decode_tuple(cbdev, child, tupleid, len,
  624                     tupledata, start, &off, callbacks, argp);
  625                 if (expect_linktarget != 0) {
  626                         device_printf(cbdev, "Parsing failed with %d\n",
  627                             expect_linktarget);
  628                         cardbus_read_tuple_finish(cbdev, child, rid, res);
  629                         return (expect_linktarget);
  630                 }
  631         } while (tupleid != CISTPL_END);
  632         cardbus_read_tuple_finish(cbdev, child, rid, res);
  633         return (0);
  634 }
  635 
  636 int
  637 cardbus_do_cis(device_t cbdev, device_t child)
  638 {
  639         struct tuple_callbacks init_callbacks[] = {
  640                 MAKETUPLE(LONGLINK_CB,          unhandled),
  641                 MAKETUPLE(INDIRECT,             unhandled),
  642                 MAKETUPLE(LONGLINK_MFC,         unhandled),
  643                 MAKETUPLE(BAR,                  bar),
  644                 MAKETUPLE(LONGLINK_A,           unhandled),
  645                 MAKETUPLE(LONGLINK_C,           unhandled),
  646                 MAKETUPLE(LINKTARGET,           linktarget),
  647                 MAKETUPLE(VERS_1,               vers_1),
  648                 MAKETUPLE(MANFID,               manfid),
  649                 MAKETUPLE(FUNCID,               funcid),
  650                 MAKETUPLE(FUNCE,                funce),
  651                 MAKETUPLE(END,                  end),
  652                 MAKETUPLE(GENERIC,              generic),
  653         };
  654 
  655         return (cardbus_parse_cis(cbdev, child, init_callbacks, NULL));
  656 }

Cache object: 8bab1f1fa75ae9900131da7d1610f0cd


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