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.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) 2003 M. Warner Losh.  All Rights Reserved.
    3  * Copyright (c) 2000,2001 Jonathan Chen.  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: releng/6.0/sys/dev/cardbus/cardbus.c 143785 2005-03-18 05:19:50Z imp $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/malloc.h>
   33 #include <sys/module.h>
   34 #include <sys/kernel.h>
   35 #include <sys/sysctl.h>
   36 
   37 #include <sys/bus.h>
   38 #include <machine/bus.h>
   39 #include <sys/rman.h>
   40 #include <machine/resource.h>
   41 
   42 #include <sys/pciio.h>
   43 #include <dev/pci/pcivar.h>
   44 #include <dev/pci/pcireg.h>
   45 #include <dev/pci/pci_private.h>
   46 
   47 #include <dev/cardbus/cardbusreg.h>
   48 #include <dev/cardbus/cardbusvar.h>
   49 #include <dev/cardbus/cardbus_cis.h>
   50 #include <dev/pccard/pccard_cis.h>
   51 #include <dev/pccard/pccardvar.h>
   52 
   53 #include "power_if.h"
   54 #include "pcib_if.h"
   55 
   56 /* sysctl vars */
   57 SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters");
   58 
   59 int    cardbus_debug = 0;
   60 TUNABLE_INT("hw.cardbus.debug", &cardbus_debug);
   61 SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW,
   62     &cardbus_debug, 0,
   63   "CardBus debug");
   64 
   65 int    cardbus_cis_debug = 0;
   66 TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug);
   67 SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW,
   68     &cardbus_cis_debug, 0,
   69   "CardBus CIS debug");
   70 
   71 #define DPRINTF(a) if (cardbus_debug) printf a
   72 #define DEVPRINTF(x) if (cardbus_debug) device_printf x
   73 
   74 
   75 static void     cardbus_add_map(device_t cbdev, device_t child, int reg);
   76 static int      cardbus_alloc_resources(device_t cbdev, device_t child);
   77 static int      cardbus_attach(device_t cbdev);
   78 static int      cardbus_attach_card(device_t cbdev);
   79 static int      cardbus_barsort(const void *a, const void *b);
   80 static int      cardbus_detach(device_t cbdev);
   81 static int      cardbus_detach_card(device_t cbdev);
   82 static void     cardbus_device_setup_regs(device_t brdev, int b, int s, int f,
   83                     pcicfgregs *cfg);
   84 static void     cardbus_driver_added(device_t cbdev, driver_t *driver);
   85 static void     cardbus_pickup_maps(device_t cbdev, device_t child);
   86 static int      cardbus_probe(device_t cbdev);
   87 static int      cardbus_read_ivar(device_t cbdev, device_t child, int which,
   88                     uintptr_t *result);
   89 static void     cardbus_release_all_resources(device_t cbdev,
   90                     struct cardbus_devinfo *dinfo);
   91 static int      cardbus_write_ivar(device_t cbdev, device_t child, int which,
   92                     uintptr_t value);
   93 
   94 /*
   95  * Resource allocation
   96  */
   97 /*
   98  * Adding a memory/io resource (sans CIS)
   99  */
  100 
  101 static void
  102 cardbus_add_map(device_t cbdev, device_t child, int reg)
  103 {
  104         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  105         struct resource_list_entry *rle;
  106         uint32_t size;
  107         uint32_t testval;
  108         int type;
  109 
  110         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  111                 if (rle->rid == reg)
  112                         return;
  113         }
  114 
  115         if (reg == CARDBUS_ROM_REG)
  116                 testval = CARDBUS_ROM_ADDRMASK;
  117         else
  118                 testval = ~0;
  119 
  120         pci_write_config(child, reg, testval, 4);
  121         testval = pci_read_config(child, reg, 4);
  122 
  123         if (testval == ~0 || testval == 0)
  124                 return;
  125 
  126         if ((testval & 1) == 0)
  127                 type = SYS_RES_MEMORY;
  128         else
  129                 type = SYS_RES_IOPORT;
  130 
  131         size = CARDBUS_MAPREG_MEM_SIZE(testval);
  132         device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n",
  133             reg, size);
  134         resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size);
  135 }
  136 
  137 static void
  138 cardbus_pickup_maps(device_t cbdev, device_t child)
  139 {
  140         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  141         int reg;
  142 
  143         /*
  144          * Try to pick up any resources that was not specified in CIS.
  145          * Maybe this isn't any longer necessary now that we have fixed
  146          * CIS parsing and we should filter things here?  XXX
  147          */
  148         for (reg = 0; reg < dinfo->pci.cfg.nummaps; reg++)
  149                 cardbus_add_map(cbdev, child, PCIR_BAR(reg));
  150 }
  151 
  152 static void
  153 cardbus_do_res(struct resource_list_entry *rle, device_t child, uint32_t start)
  154 {
  155         rle->start = start;
  156         rle->end = start + rle->count - 1;
  157         pci_write_config(child, rle->rid, rle->start, 4);
  158 }
  159 
  160 static int
  161 cardbus_barsort(const void *a, const void *b)
  162 {
  163         return ((*(const struct resource_list_entry * const *)b)->count -
  164             (*(const struct resource_list_entry * const *)a)->count);
  165 }
  166 
  167 /* XXX this function is too long */
  168 static int
  169 cardbus_alloc_resources(device_t cbdev, device_t child)
  170 {
  171         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  172         int count;
  173         struct resource_list_entry *rle;
  174         struct resource_list_entry **barlist;
  175         int tmp;
  176         uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
  177         struct resource *res;
  178         uint32_t start,end;
  179         int rid, flags;
  180 
  181         count = 0;
  182         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  183                 count++;
  184         }
  185         if (count == 0)
  186                 return (0);
  187         barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
  188             M_WAITOK);
  189         count = 0;
  190         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  191                 barlist[count] = rle;
  192                 if (rle->type == SYS_RES_IOPORT) {
  193                         io_size += rle->count;
  194                 } else if (rle->type == SYS_RES_MEMORY) {
  195                         if (dinfo->mprefetchable & BARBIT(rle->rid))
  196                                 mem_psize += rle->count;
  197                         else
  198                                 mem_nsize += rle->count;
  199                 }
  200                 count++;
  201         }
  202 
  203         /*
  204          * We want to allocate the largest resource first, so that our
  205          * allocated memory is packed.
  206          */
  207         qsort(barlist, count, sizeof(struct resource_list_entry *),
  208             cardbus_barsort);
  209 
  210         /* Allocate prefetchable memory */
  211         flags = 0;
  212         for (tmp = 0; tmp < count; tmp++) {
  213                 rle = barlist[tmp];
  214                 if (rle->res == NULL &&
  215                     rle->type == SYS_RES_MEMORY &&
  216                     dinfo->mprefetchable & BARBIT(rle->rid)) {
  217                         flags = rman_make_alignment_flags(rle->count);
  218                         break;
  219                 }
  220         }
  221         if (flags > 0) { /* If any prefetchable memory is requested... */
  222                 /*
  223                  * First we allocate one big space for all resources of this
  224                  * type.  We do this because our parent, pccbb, needs to open
  225                  * a window to forward all addresses within the window, and
  226                  * it would be best if nobody else has resources allocated
  227                  * within the window.
  228                  * (XXX: Perhaps there might be a better way to do this?)
  229                  */
  230                 rid = 0;
  231                 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
  232                     (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
  233                     mem_psize, flags);
  234                 if (res == NULL) {
  235                         device_printf(cbdev,
  236                             "Can't get memory for prefetch mem\n");
  237                         free(barlist, M_DEVBUF);
  238                         return (EIO);
  239                 }
  240                 start = rman_get_start(res);
  241                 end = rman_get_end(res);
  242                 DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
  243                 /*
  244                  * Now that we know the region is free, release it and hand it
  245                  * out piece by piece.
  246                  */
  247                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  248                 for (tmp = 0; tmp < count; tmp++) {
  249                         rle = barlist[tmp];
  250                         if (rle->type == SYS_RES_MEMORY &&
  251                             dinfo->mprefetchable & BARBIT(rle->rid)) {
  252                                 cardbus_do_res(rle, child, start);
  253                                 start += rle->count;
  254                         }
  255                 }
  256         }
  257 
  258         /* Allocate non-prefetchable memory */
  259         flags = 0;
  260         for (tmp = 0; tmp < count; tmp++) {
  261                 rle = barlist[tmp];
  262                 if (rle->type == SYS_RES_MEMORY &&
  263                     (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) {
  264                         flags = rman_make_alignment_flags(rle->count);
  265                         break;
  266                 }
  267         }
  268         if (flags > 0) { /* If any non-prefetchable memory is requested... */
  269                 /*
  270                  * First we allocate one big space for all resources of this
  271                  * type.  We do this because our parent, pccbb, needs to open
  272                  * a window to forward all addresses within the window, and
  273                  * it would be best if nobody else has resources allocated
  274                  * within the window.
  275                  * (XXX: Perhaps there might be a better way to do this?)
  276                  */
  277                 rid = 0;
  278                 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
  279                     ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL,
  280                     mem_nsize, flags);
  281                 if (res == NULL) {
  282                         device_printf(cbdev,
  283                             "Can't get memory for non-prefetch mem\n");
  284                         free(barlist, M_DEVBUF);
  285                         return (EIO);
  286                 }
  287                 start = rman_get_start(res);
  288                 end = rman_get_end(res);
  289                 DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n",
  290                     start, end));
  291                 /*
  292                  * Now that we know the region is free, release it and hand it
  293                  * out piece by piece.
  294                  */
  295                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  296                 for (tmp = 0; tmp < count; tmp++) {
  297                         rle = barlist[tmp];
  298                         if (rle->type == SYS_RES_MEMORY &&
  299                             (dinfo->mprefetchable & BARBIT(rle->rid)) == 0) {
  300                                 cardbus_do_res(rle, child, start);
  301                                 start += rle->count;
  302                         }
  303                 }
  304         }
  305 
  306         /* Allocate IO ports */
  307         flags = 0;
  308         for (tmp = 0; tmp < count; tmp++) {
  309                 rle = barlist[tmp];
  310                 if (rle->type == SYS_RES_IOPORT) {
  311                         flags = rman_make_alignment_flags(rle->count);
  312                         break;
  313                 }
  314         }
  315         if (flags > 0) { /* If any IO port is requested... */
  316                 /*
  317                  * First we allocate one big space for all resources of this
  318                  * type.  We do this because our parent, pccbb, needs to open
  319                  * a window to forward all addresses within the window, and
  320                  * it would be best if nobody else has resources allocated
  321                  * within the window.
  322                  * (XXX: Perhaps there might be a better way to do this?)
  323                  */
  324                 rid = 0;
  325                 res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
  326                     (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
  327                 if (res == NULL) {
  328                         device_printf(cbdev,
  329                             "Can't get memory for IO ports\n");
  330                         free(barlist, M_DEVBUF);
  331                         return (EIO);
  332                 }
  333                 start = rman_get_start(res);
  334                 end = rman_get_end(res);
  335                 DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
  336                 /*
  337                  * Now that we know the region is free, release it and hand it
  338                  * out piece by piece.
  339                  */
  340                 bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
  341                 for (tmp = 0; tmp < count; tmp++) {
  342                         rle = barlist[tmp];
  343                         if (rle->type == SYS_RES_IOPORT) {
  344                                 cardbus_do_res(rle, child, start);
  345                                 start += rle->count;
  346                         }
  347                 }
  348         }
  349 
  350         /* Allocate IRQ */
  351         rid = 0;
  352         res = bus_alloc_resource_any(cbdev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
  353         if (res == NULL) {
  354                 device_printf(cbdev, "Can't get memory for irq\n");
  355                 free(barlist, M_DEVBUF);
  356                 return (EIO);
  357         }
  358         start = rman_get_start(res);
  359         end = rman_get_end(res);
  360         bus_release_resource(cbdev, SYS_RES_IRQ, rid, res);
  361         resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, start, end,
  362             1);
  363         dinfo->pci.cfg.intline = rman_get_start(res);
  364         pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1);
  365 
  366         free(barlist, M_DEVBUF);
  367         return (0);
  368 }
  369 
  370 /************************************************************************/
  371 /* Probe/Attach                                                         */
  372 /************************************************************************/
  373 
  374 static int
  375 cardbus_probe(device_t cbdev)
  376 {
  377         device_set_desc(cbdev, "CardBus bus");
  378         return 0;
  379 }
  380 
  381 static int
  382 cardbus_attach(device_t cbdev)
  383 {
  384         return 0;
  385 }
  386 
  387 static int
  388 cardbus_detach(device_t cbdev)
  389 {
  390         cardbus_detach_card(cbdev);
  391         return 0;
  392 }
  393 
  394 static int
  395 cardbus_suspend(device_t self)
  396 {
  397         cardbus_detach_card(self);
  398         return (0);
  399 }
  400 
  401 static int
  402 cardbus_resume(device_t self)
  403 {
  404         return (0);
  405 }
  406 
  407 /************************************************************************/
  408 /* Attach/Detach card                                                   */
  409 /************************************************************************/
  410 
  411 static void
  412 cardbus_device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg)
  413 {
  414         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_INTLINE,
  415             pci_get_irq(device_get_parent(brdev)), 1);
  416         cfg->intline = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_INTLINE, 1);
  417 
  418         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1);
  419         cfg->cachelnsz = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 1);
  420 
  421         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 0xa8, 1);
  422         cfg->lattimer = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 1);
  423 
  424         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MINGNT, 0x14, 1);
  425         cfg->mingnt = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MINGNT, 1);
  426 
  427         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 0x14, 1);
  428         cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1);
  429 }
  430 
  431 static int
  432 cardbus_attach_card(device_t cbdev)
  433 {
  434         device_t brdev = device_get_parent(cbdev);
  435         device_t child;
  436         int cardattached = 0;
  437         int bus, slot, func;
  438 
  439         cardbus_detach_card(cbdev); /* detach existing cards */
  440         POWER_ENABLE_SOCKET(brdev, cbdev);
  441         bus = pcib_get_bus(cbdev);
  442         /* For each function, set it up and try to attach a driver to it */
  443         for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) {
  444                 int cardbusfunchigh = 0;
  445                 for (func = 0; func <= cardbusfunchigh; func++) {
  446                         struct cardbus_devinfo *dinfo;
  447 
  448                         dinfo = (struct cardbus_devinfo *)
  449                             pci_read_device(brdev, bus, slot, func,
  450                                 sizeof(struct cardbus_devinfo));
  451                         if (dinfo == NULL)
  452                                 continue;
  453                         if (dinfo->pci.cfg.mfdev)
  454                                 cardbusfunchigh = CARDBUS_FUNCMAX;
  455 
  456                         cardbus_device_setup_regs(brdev, bus, slot, func,
  457                             &dinfo->pci.cfg);
  458                         child = device_add_child(cbdev, NULL, -1);
  459                         if (child == NULL) {
  460                                 DEVPRINTF((cbdev, "Cannot add child!\n"));
  461                                 pci_freecfg((struct pci_devinfo *)dinfo);
  462                                 continue;
  463                         }
  464                         dinfo->pci.cfg.dev = child;
  465                         resource_list_init(&dinfo->pci.resources);
  466                         device_set_ivars(child, dinfo);
  467                         if (cardbus_do_cis(cbdev, child) != 0) {
  468                                 DEVPRINTF((cbdev, "Can't parse cis\n"));
  469                                 pci_freecfg((struct pci_devinfo *)dinfo);
  470                                 continue;
  471                         }
  472                         cardbus_pickup_maps(cbdev, child);
  473                         cardbus_alloc_resources(cbdev, child);
  474                         pci_print_verbose(&dinfo->pci);
  475                         if (device_probe_and_attach(child) != 0)
  476                                 cardbus_release_all_resources(cbdev, dinfo);
  477                         else
  478                                 cardattached++;
  479                 }
  480         }
  481 
  482         if (cardattached > 0)
  483                 return (0);
  484         POWER_DISABLE_SOCKET(brdev, cbdev);
  485         return (ENOENT);
  486 }
  487 
  488 static int
  489 cardbus_detach_card(device_t cbdev)
  490 {
  491         int numdevs;
  492         device_t *devlist;
  493         int tmp;
  494         int err = 0;
  495 
  496         device_get_children(cbdev, &devlist, &numdevs);
  497 
  498         if (numdevs == 0) {
  499                 free(devlist, M_TEMP);
  500                 return (ENOENT);
  501         }
  502 
  503         for (tmp = 0; tmp < numdevs; tmp++) {
  504                 struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]);
  505                 int status = device_get_state(devlist[tmp]);
  506 
  507                 if (dinfo->pci.cfg.dev != devlist[tmp])
  508                         device_printf(cbdev, "devinfo dev mismatch\n");
  509                 if (status == DS_ATTACHED || status == DS_BUSY)
  510                         device_detach(devlist[tmp]);
  511                 cardbus_release_all_resources(cbdev, dinfo);
  512                 device_delete_child(cbdev, devlist[tmp]);
  513                 pci_freecfg((struct pci_devinfo *)dinfo);
  514         }
  515         POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);
  516         free(devlist, M_TEMP);
  517         return (err);
  518 }
  519 
  520 static void
  521 cardbus_driver_added(device_t cbdev, driver_t *driver)
  522 {
  523         int numdevs;
  524         device_t *devlist;
  525         device_t dev;
  526         int i;
  527         struct cardbus_devinfo *dinfo;
  528 
  529         DEVICE_IDENTIFY(driver, cbdev);
  530         device_get_children(cbdev, &devlist, &numdevs);
  531         /*
  532          * If there are no drivers attached, but there are children,
  533          * then power the card up.
  534          */
  535         for (i = 0; i < numdevs; i++) {
  536                 dev = devlist[i];
  537                 if (device_get_state(dev) != DS_NOTPRESENT)
  538                     break;
  539         }
  540         if (i > 0 && i == numdevs)
  541                 POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev);
  542         for (i = 0; i < numdevs; i++) {
  543                 dev = devlist[i];
  544                 if (device_get_state(dev) != DS_NOTPRESENT)
  545                         continue;
  546                 dinfo = device_get_ivars(dev);
  547                 pci_print_verbose(&dinfo->pci);
  548                 resource_list_init(&dinfo->pci.resources);
  549                 cardbus_do_cis(cbdev, dev);
  550                 cardbus_pickup_maps(cbdev, dev);
  551                 cardbus_alloc_resources(cbdev, dev);
  552                 if (device_probe_and_attach(dev) != 0)
  553                         cardbus_release_all_resources(cbdev, dinfo);
  554         }
  555         free(devlist, M_TEMP);
  556 }
  557 
  558 static void
  559 cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo)
  560 {
  561         struct resource_list_entry *rle;
  562 
  563         /* Free all allocated resources */
  564         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  565                 if (rle->res) {
  566                         if (rman_get_device(rle->res) != cbdev)
  567                                 device_printf(cbdev, "release_all_resource: "
  568                                     "Resource still owned by child, oops. "
  569                                     "(type=%d, rid=%d, addr=%lx)\n",
  570                                     rle->type, rle->rid,
  571                                     rman_get_start(rle->res));
  572                         BUS_RELEASE_RESOURCE(device_get_parent(cbdev),
  573                             cbdev, rle->type, rle->rid, rle->res);
  574                         rle->res = NULL;
  575                         /*
  576                          * zero out config so the card won't acknowledge
  577                          * access to the space anymore
  578                          */
  579                         pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4);
  580                 }
  581         }
  582         resource_list_free(&dinfo->pci.resources);
  583 }
  584 
  585 /************************************************************************/
  586 /* Other Bus Methods                                                    */
  587 /************************************************************************/
  588 
  589 static int
  590 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result)
  591 {
  592         struct cardbus_devinfo *dinfo;
  593         pcicfgregs *cfg;
  594 
  595         dinfo = device_get_ivars(child);
  596         cfg = &dinfo->pci.cfg;
  597 
  598         switch (which) {
  599         case PCI_IVAR_ETHADDR:
  600                 /*
  601                  * The generic accessor doesn't deal with failure, so
  602                  * we set the return value, then return an error.
  603                  */
  604                 if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) {
  605                         *((uint8_t **) result) = dinfo->funce.lan.nid;
  606                         break;
  607                 }
  608                 *((uint8_t **) result) = NULL;
  609                 return (EINVAL);
  610         default:
  611                 return (pci_read_ivar(cbdev, child, which, result));
  612         }
  613         return 0;
  614 }
  615 
  616 static int
  617 cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value)
  618 {
  619         return(pci_write_ivar(cbdev, child, which, value));
  620 }
  621 
  622 static device_method_t cardbus_methods[] = {
  623         /* Device interface */
  624         DEVMETHOD(device_probe,         cardbus_probe),
  625         DEVMETHOD(device_attach,        cardbus_attach),
  626         DEVMETHOD(device_detach,        cardbus_detach),
  627         DEVMETHOD(device_suspend,       cardbus_suspend),
  628         DEVMETHOD(device_resume,        cardbus_resume),
  629 
  630         /* Bus interface */
  631         DEVMETHOD(bus_read_ivar,        cardbus_read_ivar),
  632         DEVMETHOD(bus_write_ivar,       cardbus_write_ivar),
  633         DEVMETHOD(bus_driver_added,     cardbus_driver_added),
  634 
  635         /* Card Interface */
  636         DEVMETHOD(card_attach_card,     cardbus_attach_card),
  637         DEVMETHOD(card_detach_card,     cardbus_detach_card),
  638 
  639         {0,0}
  640 };
  641 
  642 DECLARE_CLASS(pci_driver);
  643 DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 0, pci_driver);
  644 
  645 static devclass_t cardbus_devclass;
  646 
  647 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0);
  648 MODULE_VERSION(cardbus, 1);

Cache object: 187eaa2521f0ebde04245ec2dde032ec


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