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$");
   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 int
  153 cardbus_barsort(const void *a, const void *b)
  154 {
  155         return ((*(const struct resource_list_entry * const *)b)->count -
  156             (*(const struct resource_list_entry * const *)a)->count);
  157 }
  158 
  159 /* XXX this function is too long */
  160 static int
  161 cardbus_alloc_resources(device_t cbdev, device_t child)
  162 {
  163         struct cardbus_devinfo *dinfo = device_get_ivars(child);
  164         int count;
  165         struct resource_list_entry *rle;
  166         struct resource_list_entry **barlist;
  167         int tmp;
  168         uint32_t mem_psize = 0, mem_nsize = 0, io_size = 0;
  169         struct resource *res;
  170         uint32_t start,end;
  171         int rid, flags;
  172 
  173         count = 0;
  174         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  175                 count++;
  176         }
  177         if (count == 0)
  178                 return (0);
  179         barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF,
  180             M_WAITOK);
  181         count = 0;
  182         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  183                 barlist[count] = rle;
  184                 if (rle->type == SYS_RES_IOPORT) {
  185                         io_size += rle->count;
  186                 } else if (rle->type == SYS_RES_MEMORY) {
  187                         if (dinfo->mprefetchable & BARBIT(rle->rid))
  188                                 mem_psize += rle->count;
  189                         else
  190                                 mem_nsize += rle->count;
  191                 }
  192                 count++;
  193         }
  194 
  195         /*
  196          * We want to allocate the largest resource first, so that our
  197          * allocated memory is packed.
  198          */
  199         qsort(barlist, count, sizeof(struct resource_list_entry *),
  200             cardbus_barsort);
  201 
  202         /* Allocate prefetchable memory */
  203         flags = 0;
  204         for (tmp = 0; tmp < count; tmp++) {
  205                 rle = barlist[tmp];
  206                 if (rle->res == NULL &&
  207                     rle->type == SYS_RES_MEMORY &&
  208                     dinfo->mprefetchable & BARBIT(rle->rid)) {
  209                         flags = rman_make_alignment_flags(rle->count);
  210                         break;
  211                 }
  212         }
  213         if (flags > 0) { /* If any prefetchable memory is requested... */
  214                 /*
  215                  * First we allocate one big space for all resources of this
  216                  * type.  We do this because our parent, pccbb, needs to open
  217                  * a window to forward all addresses within the window, and
  218                  * it would be best if nobody else has resources allocated
  219                  * within the window.
  220                  * (XXX: Perhaps there might be a better way to do this?)
  221                  */
  222                 rid = 0;
  223                 res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0,
  224                     (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL,
  225                     mem_psize, flags);
  226                 if (res == NULL) {
  227                         device_printf(cbdev,
  228                             "Can't get memory for prefetch mem\n");
  229                         free(barlist, M_DEVBUF);
  230                         return (EIO);
  231                 }
  232                 start = rman_get_start(res);
  233                 end = rman_get_end(res);
  234                 DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end));
  235                 /*
  236                  * Now that we know the region is free, release it and hand it
  237                  * out piece by piece.
  238                  */
  239                 bus_release_resource(cbdev, SYS_RES_MEMORY, rid, res);
  240                 for (tmp = 0; tmp < count; tmp++) {
  241                         rle = barlist[tmp];
  242                         if (rle->type == SYS_RES_MEMORY &&
  243                             dinfo->mprefetchable & BARBIT(rle->rid)) {
  244                                 rle->res = bus_alloc_resource(cbdev,
  245                                     rle->type, &rle->rid, start, end,
  246                                     rle->count,
  247                                     rman_make_alignment_flags(rle->count));
  248                                 if (rle->res != NULL) {
  249                                         rle->start = rman_get_start(rle->res);
  250                                         rle->end = rman_get_end(rle->res);
  251                                         pci_write_config(child,
  252                                             rle->rid, rle->start, 4);
  253                                 }
  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                                 rle->res = bus_alloc_resource(cbdev,
  301                                     rle->type, &rle->rid, start, end,
  302                                     rle->count,
  303                                     rman_make_alignment_flags(rle->count));
  304                                 if (rle->res == NULL) {
  305                                         DEVPRINTF((cbdev, "Cannot pre-allocate "
  306                                             "memory for cardbus device\n"));
  307                                         free(barlist, M_DEVBUF);
  308                                         return (ENOMEM);
  309                                 }
  310                                 rle->start = rman_get_start(rle->res);
  311                                 rle->end = rman_get_end(rle->res);
  312                                 pci_write_config(child,
  313                                     rle->rid, rle->start, 4);
  314                         }
  315                 }
  316         }
  317 
  318         /* Allocate IO ports */
  319         flags = 0;
  320         for (tmp = 0; tmp < count; tmp++) {
  321                 rle = barlist[tmp];
  322                 if (rle->type == SYS_RES_IOPORT) {
  323                         flags = rman_make_alignment_flags(rle->count);
  324                         break;
  325                 }
  326         }
  327         if (flags > 0) { /* If any IO port is requested... */
  328                 /*
  329                  * First we allocate one big space for all resources of this
  330                  * type.  We do this because our parent, pccbb, needs to open
  331                  * a window to forward all addresses within the window, and
  332                  * it would be best if nobody else has resources allocated
  333                  * within the window.
  334                  * (XXX: Perhaps there might be a better way to do this?)
  335                  */
  336                 rid = 0;
  337                 res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0,
  338                     (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags);
  339                 if (res == NULL) {
  340                         device_printf(cbdev,
  341                             "Can't get memory for IO ports\n");
  342                         free(barlist, M_DEVBUF);
  343                         return (EIO);
  344                 }
  345                 start = rman_get_start(res);
  346                 end = rman_get_end(res);
  347                 DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end));
  348                 /*
  349                  * Now that we know the region is free, release it and hand it
  350                  * out piece by piece.
  351                  */
  352                 bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res);
  353                 for (tmp = 0; tmp < count; tmp++) {
  354                         rle = barlist[tmp];
  355                         if (rle->type == SYS_RES_IOPORT) {
  356                                 rle->res = bus_alloc_resource(cbdev,
  357                                     rle->type, &rle->rid, start, end,
  358                                     rle->count,
  359                                     rman_make_alignment_flags(rle->count));
  360                                 if (rle->res == NULL) {
  361                                         DEVPRINTF((cbdev, "Cannot pre-allocate "
  362                                             "IO port for cardbus device\n"));
  363                                         free(barlist, M_DEVBUF);
  364                                         return (ENOMEM);
  365                                 }
  366                                 rle->start = rman_get_start(rle->res);
  367                                 rle->end = rman_get_end(rle->res);
  368                                 pci_write_config(child,
  369                                     rle->rid, rle->start, 4);
  370                         }
  371                 }
  372         }
  373 
  374         /* Allocate IRQ */
  375         rid = 0;
  376         res = bus_alloc_resource_any(cbdev, SYS_RES_IRQ, &rid, RF_SHAREABLE);
  377         if (res == NULL) {
  378                 device_printf(cbdev, "Can't get memory for irq\n");
  379                 free(barlist, M_DEVBUF);
  380                 return (EIO);
  381         }
  382         start = rman_get_start(res);
  383         end = rman_get_end(res);
  384         resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, start, end,
  385             1);
  386         rle = resource_list_find(&dinfo->pci.resources, SYS_RES_IRQ, rid);
  387         rle->res = res;
  388         dinfo->pci.cfg.intline = start;
  389         pci_write_config(child, PCIR_INTLINE, start, 1);
  390 
  391         free(barlist, M_DEVBUF);
  392         return (0);
  393 }
  394 
  395 /************************************************************************/
  396 /* Probe/Attach                                                         */
  397 /************************************************************************/
  398 
  399 static int
  400 cardbus_probe(device_t cbdev)
  401 {
  402         device_set_desc(cbdev, "CardBus bus");
  403         return 0;
  404 }
  405 
  406 static int
  407 cardbus_attach(device_t cbdev)
  408 {
  409         return 0;
  410 }
  411 
  412 static int
  413 cardbus_detach(device_t cbdev)
  414 {
  415         cardbus_detach_card(cbdev);
  416         return 0;
  417 }
  418 
  419 static int
  420 cardbus_suspend(device_t self)
  421 {
  422         cardbus_detach_card(self);
  423         return (0);
  424 }
  425 
  426 static int
  427 cardbus_resume(device_t self)
  428 {
  429         return (0);
  430 }
  431 
  432 /************************************************************************/
  433 /* Attach/Detach card                                                   */
  434 /************************************************************************/
  435 
  436 static void
  437 cardbus_device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg)
  438 {
  439         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_INTLINE,
  440             pci_get_irq(device_get_parent(brdev)), 1);
  441         cfg->intline = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_INTLINE, 1);
  442 
  443         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 0x08, 1);
  444         cfg->cachelnsz = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_CACHELNSZ, 1);
  445 
  446         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 0xa8, 1);
  447         cfg->lattimer = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_LATTIMER, 1);
  448 
  449         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MINGNT, 0x14, 1);
  450         cfg->mingnt = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MINGNT, 1);
  451 
  452         PCIB_WRITE_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 0x14, 1);
  453         cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1);
  454 }
  455 
  456 static int
  457 cardbus_attach_card(device_t cbdev)
  458 {
  459         device_t brdev = device_get_parent(cbdev);
  460         device_t child;
  461         int cardattached = 0;
  462         int bus, slot, func;
  463 
  464         cardbus_detach_card(cbdev); /* detach existing cards */
  465         POWER_ENABLE_SOCKET(brdev, cbdev);
  466         bus = pcib_get_bus(cbdev);
  467         /* For each function, set it up and try to attach a driver to it */
  468         for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) {
  469                 int cardbusfunchigh = 0;
  470                 for (func = 0; func <= cardbusfunchigh; func++) {
  471                         struct cardbus_devinfo *dinfo;
  472 
  473                         dinfo = (struct cardbus_devinfo *)
  474                             pci_read_device(brdev, bus, slot, func,
  475                                 sizeof(struct cardbus_devinfo));
  476                         if (dinfo == NULL)
  477                                 continue;
  478                         if (dinfo->pci.cfg.mfdev)
  479                                 cardbusfunchigh = CARDBUS_FUNCMAX;
  480 
  481                         cardbus_device_setup_regs(brdev, bus, slot, func,
  482                             &dinfo->pci.cfg);
  483                         child = device_add_child(cbdev, NULL, -1);
  484                         if (child == NULL) {
  485                                 DEVPRINTF((cbdev, "Cannot add child!\n"));
  486                                 pci_freecfg((struct pci_devinfo *)dinfo);
  487                                 continue;
  488                         }
  489                         dinfo->pci.cfg.dev = child;
  490                         resource_list_init(&dinfo->pci.resources);
  491                         device_set_ivars(child, dinfo);
  492                         if (cardbus_do_cis(cbdev, child) != 0) {
  493                                 DEVPRINTF((cbdev, "Can't parse cis\n"));
  494                                 pci_freecfg((struct pci_devinfo *)dinfo);
  495                                 continue;
  496                         }
  497                         cardbus_pickup_maps(cbdev, child);
  498                         cardbus_alloc_resources(cbdev, child);
  499                         pci_print_verbose(&dinfo->pci);
  500                         if (device_probe_and_attach(child) != 0)
  501                                 cardbus_release_all_resources(cbdev, dinfo);
  502                         else
  503                                 cardattached++;
  504                 }
  505         }
  506 
  507         if (cardattached > 0)
  508                 return (0);
  509         POWER_DISABLE_SOCKET(brdev, cbdev);
  510         return (ENOENT);
  511 }
  512 
  513 static int
  514 cardbus_detach_card(device_t cbdev)
  515 {
  516         int numdevs;
  517         device_t *devlist;
  518         int tmp;
  519         int err = 0;
  520 
  521         device_get_children(cbdev, &devlist, &numdevs);
  522 
  523         if (numdevs == 0) {
  524                 free(devlist, M_TEMP);
  525                 return (ENOENT);
  526         }
  527 
  528         for (tmp = 0; tmp < numdevs; tmp++) {
  529                 struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]);
  530                 int status = device_get_state(devlist[tmp]);
  531 
  532                 if (dinfo->pci.cfg.dev != devlist[tmp])
  533                         device_printf(cbdev, "devinfo dev mismatch\n");
  534                 if (status == DS_ATTACHED || status == DS_BUSY)
  535                         device_detach(devlist[tmp]);
  536                 cardbus_release_all_resources(cbdev, dinfo);
  537                 device_delete_child(cbdev, devlist[tmp]);
  538                 pci_freecfg((struct pci_devinfo *)dinfo);
  539         }
  540         POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev);
  541         free(devlist, M_TEMP);
  542         return (err);
  543 }
  544 
  545 static void
  546 cardbus_driver_added(device_t cbdev, driver_t *driver)
  547 {
  548         int numdevs;
  549         device_t *devlist;
  550         device_t dev;
  551         int i;
  552         struct cardbus_devinfo *dinfo;
  553 
  554         DEVICE_IDENTIFY(driver, cbdev);
  555         device_get_children(cbdev, &devlist, &numdevs);
  556         /*
  557          * If there are no drivers attached, but there are children,
  558          * then power the card up.
  559          */
  560         for (i = 0; i < numdevs; i++) {
  561                 dev = devlist[i];
  562                 if (device_get_state(dev) != DS_NOTPRESENT)
  563                     break;
  564         }
  565         if (i > 0 && i == numdevs)
  566                 POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev);
  567         for (i = 0; i < numdevs; i++) {
  568                 dev = devlist[i];
  569                 if (device_get_state(dev) != DS_NOTPRESENT)
  570                         continue;
  571                 dinfo = device_get_ivars(dev);
  572                 pci_print_verbose(&dinfo->pci);
  573                 resource_list_init(&dinfo->pci.resources);
  574                 cardbus_do_cis(cbdev, dev);
  575                 cardbus_pickup_maps(cbdev, dev);
  576                 cardbus_alloc_resources(cbdev, dev);
  577                 if (device_probe_and_attach(dev) != 0)
  578                         cardbus_release_all_resources(cbdev, dinfo);
  579         }
  580         free(devlist, M_TEMP);
  581 }
  582 
  583 static void
  584 cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo)
  585 {
  586         struct resource_list_entry *rle;
  587 
  588         /* Free all allocated resources */
  589         STAILQ_FOREACH(rle, &dinfo->pci.resources, link) {
  590                 if (rle->res) {
  591                         if (rman_get_device(rle->res) != cbdev)
  592                                 device_printf(cbdev, "release_all_resource: "
  593                                     "Resource still owned by child, oops. "
  594                                     "(type=%d, rid=%d, addr=%lx)\n",
  595                                     rle->type, rle->rid,
  596                                     rman_get_start(rle->res));
  597                         BUS_RELEASE_RESOURCE(device_get_parent(cbdev),
  598                             cbdev, rle->type, rle->rid, rle->res);
  599                         rle->res = NULL;
  600                         /*
  601                          * zero out config so the card won't acknowledge
  602                          * access to the space anymore
  603                          */
  604                         pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4);
  605                 }
  606         }
  607         resource_list_free(&dinfo->pci.resources);
  608 }
  609 
  610 /************************************************************************/
  611 /* Other Bus Methods                                                    */
  612 /************************************************************************/
  613 
  614 static int
  615 cardbus_read_ivar(device_t cbdev, device_t child, int which, uintptr_t *result)
  616 {
  617         struct cardbus_devinfo *dinfo;
  618         pcicfgregs *cfg;
  619 
  620         dinfo = device_get_ivars(child);
  621         cfg = &dinfo->pci.cfg;
  622 
  623         switch (which) {
  624         case PCI_IVAR_ETHADDR:
  625                 /*
  626                  * The generic accessor doesn't deal with failure, so
  627                  * we set the return value, then return an error.
  628                  */
  629                 if (dinfo->fepresent & (1 << PCCARD_TPLFE_TYPE_LAN_NID)) {
  630                         *((uint8_t **) result) = dinfo->funce.lan.nid;
  631                         break;
  632                 }
  633                 *((uint8_t **) result) = NULL;
  634                 return (EINVAL);
  635         default:
  636                 return (pci_read_ivar(cbdev, child, which, result));
  637         }
  638         return 0;
  639 }
  640 
  641 static int
  642 cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value)
  643 {
  644         return(pci_write_ivar(cbdev, child, which, value));
  645 }
  646 
  647 static device_method_t cardbus_methods[] = {
  648         /* Device interface */
  649         DEVMETHOD(device_probe,         cardbus_probe),
  650         DEVMETHOD(device_attach,        cardbus_attach),
  651         DEVMETHOD(device_detach,        cardbus_detach),
  652         DEVMETHOD(device_suspend,       cardbus_suspend),
  653         DEVMETHOD(device_resume,        cardbus_resume),
  654 
  655         /* Bus interface */
  656         DEVMETHOD(bus_read_ivar,        cardbus_read_ivar),
  657         DEVMETHOD(bus_write_ivar,       cardbus_write_ivar),
  658         DEVMETHOD(bus_driver_added,     cardbus_driver_added),
  659 
  660         /* Card Interface */
  661         DEVMETHOD(card_attach_card,     cardbus_attach_card),
  662         DEVMETHOD(card_detach_card,     cardbus_detach_card),
  663 
  664         {0,0}
  665 };
  666 
  667 DEFINE_CLASS_1(cardbus, cardbus_driver, cardbus_methods, 0, pci_driver);
  668 
  669 static devclass_t cardbus_devclass;
  670 
  671 DRIVER_MODULE(cardbus, cbb, cardbus_driver, cardbus_devclass, 0, 0);
  672 MODULE_VERSION(cardbus, 1);

Cache object: c897481f2e95e0c08ee99342862e0508


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