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

Cache object: bb175cada1c88bec6cf74d1f6df5cd41


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