Update cardbus/pccard support.
[dragonfly.git] / sys / bus / pccard / pccard.c
index ca4fde8..8edd276 100644 (file)
@@ -1,8 +1,6 @@
 /*     $NetBSD: pcmcia.c,v 1.23 2000/07/28 19:17:02 drochner Exp $     */
-/* $FreeBSD: src/sys/dev/pccard/pccard.c,v 1.70 2002/11/14 14:02:32 mux Exp $ */
-/* $DragonFly: src/sys/bus/pccard/pccard.c,v 1.19 2006/12/22 23:12:16 swildner Exp $ */
 
-/*
+/*-
  * Copyright (c) 1997 Marc Horowitz.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,6 +27,9 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/pccard/pccard.c,v 1.108 2005/07/15 01:43:08 imp Exp $
+ * $DragonFly: src/sys/bus/pccard/pccard.c,v 1.20 2007/07/05 12:08:53 sephe Exp $
  */
 
 #include <sys/param.h>
@@ -47,6 +48,7 @@
 
 #include <bus/pccard/pccardreg.h>
 #include <bus/pccard/pccardvar.h>
+#include <bus/pccard/pccard_cis.h>
 
 #include "power_if.h"
 #include "card_if.h"
@@ -83,7 +85,6 @@ static int    pccard_ccr_read(struct pccard_function *pf, int ccr);
 static void    pccard_ccr_write(struct pccard_function *pf, int ccr, int val);
 static int     pccard_attach_card(device_t dev);
 static int     pccard_detach_card(device_t dev);
-static int     pccard_card_gettype(device_t dev, int *type);
 static void    pccard_function_init(struct pccard_function *pf);
 static void    pccard_function_free(struct pccard_function *pf);
 static int     pccard_function_enable(struct pccard_function *pf);
@@ -104,12 +105,12 @@ static int        pccard_get_resource(device_t dev, device_t child, int type,
 static void    pccard_delete_resource(device_t dev, device_t child, int type,
                    int rid);
 static int     pccard_set_res_flags(device_t dev, device_t child, int type,
-                   int rid, u_int32_t flags);
+                   int rid, uint32_t flags);
 static int     pccard_set_memory_offset(device_t dev, device_t child, int rid,
-                   u_int32_t offset, u_int32_t *deltap);
+                   uint32_t offset, uint32_t *deltap);
 static void    pccard_probe_nomatch(device_t cbdev, device_t child);
 static int     pccard_read_ivar(device_t bus, device_t child, int which,
-                                uintptr_t *result);
+                   u_char *result);
 static void    pccard_driver_added(device_t dev, driver_t *driver);
 static struct resource *pccard_alloc_resource(device_t dev,
                    device_t child, int type, int *rid, u_long start,
@@ -146,6 +147,33 @@ pccard_ccr_write(struct pccard_function *pf, int ccr, int val)
        }
 }
 
+static int
+pccard_set_default_descr(device_t dev)
+{
+       const char *vendorstr, *prodstr;
+       uint32_t vendor, prod;
+       char *str;
+
+       vendorstr = pccard_get_vendor_str(dev);
+       prodstr = pccard_get_product_str(dev);
+       if (vendorstr != NULL && prodstr != NULL) {
+               str = kmalloc(strlen(vendorstr) + strlen(prodstr) + 2, M_DEVBUF,
+                   M_WAITOK);
+               ksprintf(str, "%s %s", vendorstr, prodstr);
+               device_set_desc_copy(dev, str);
+               kfree(str, M_DEVBUF);
+       } else {
+               vendor = pccard_get_vendor(dev);
+               prod = pccard_get_product(dev);
+
+               str = kmalloc(100, M_DEVBUF, M_WAITOK);
+               ksnprintf(str, 100, "vendor=0x%x product=0x%x", vendor, prod);
+               device_set_desc_copy(dev, str);
+               kfree(str, M_DEVBUF);
+       }
+       return (0);
+}
+
 static int
 pccard_attach_card(device_t dev)
 {
@@ -223,13 +251,14 @@ pccard_attach_card(device_t dev)
                 * can be on at a time.
                 */
                ivar = kmalloc(sizeof(struct pccard_ivar), M_DEVBUF,
-                   M_INTWAIT | M_ZERO);
+                   M_WAITOK | M_ZERO);
+               resource_list_init(&ivar->resources);
                child = device_add_child(dev, NULL, -1);
                device_set_ivars(child, ivar);
-               ivar->fcn = pf;
+               ivar->pf = pf;
                pf->dev = child;
                /*
-                * XXX We might want to move the next two lines into
+                * XXX We might want to move the next three lines into
                 * XXX the pccard interface layer.  For the moment, this
                 * XXX is OK, but some drivers want to pick the config
                 * XXX entry to use as well as some address tweaks (mostly
@@ -240,11 +269,13 @@ pccard_attach_card(device_t dev)
                if (sc->sc_enabled_count == 0)
                        POWER_ENABLE_SOCKET(device_get_parent(dev), dev);
                if (pccard_function_enable(pf) == 0 &&
+                   pccard_set_default_descr(child) == 0 &&
                    device_probe_and_attach(child) == 0) {
                        DEVPRINTF((sc->dev, "function %d CCR at %d "
-                           "offset %x: %x %x %x %x, %x %x %x %x, %x\n",
+                           "offset %x mask %x: "
+                           "%x %x %x %x, %x %x %x %x, %x\n",
                            pf->number, pf->pf_ccr_window, pf->pf_ccr_offset,
-                           pccard_ccr_read(pf, 0x00),
+                           pf->ccr_mask, pccard_ccr_read(pf, 0x00),
                        pccard_ccr_read(pf, 0x02), pccard_ccr_read(pf, 0x04),
                        pccard_ccr_read(pf, 0x06), pccard_ccr_read(pf, 0x0A),
                        pccard_ccr_read(pf, 0x0C), pccard_ccr_read(pf, 0x0E),
@@ -263,14 +294,16 @@ pccard_detach_card(device_t dev)
        struct pccard_softc *sc = PCCARD_SOFTC(dev);
        struct pccard_function *pf;
        struct pccard_config_entry *cfe;
+       int state;
 
        /*
         * We are running on either the PCCARD socket's event thread
         * or in user context detaching a device by user request.
         */
        STAILQ_FOREACH(pf, &sc->card.pf_head, pf_list) {
-               int state = device_get_state(pf->dev);
-
+               if (pf->dev == NULL)
+                       continue;
+               state = device_get_state(pf->dev);
                if (state == DS_ATTACHED || state == DS_BUSY)
                        device_detach(pf->dev);
                if (pf->cfe != NULL)
@@ -294,37 +327,41 @@ pccard_detach_card(device_t dev)
 
 static const struct pccard_product *
 pccard_do_product_lookup(device_t bus, device_t dev,
-                        const struct pccard_product *tab, size_t ent_size,
-                        pccard_product_match_fn matchfn)
+    const struct pccard_product *tab, size_t ent_size,
+    pccard_product_match_fn matchfn)
 {
        const struct pccard_product *ent;
        int matches;
-       u_int32_t fcn;
-       u_int32_t vendor;
-       u_int32_t prod;
+       uint32_t vendor;
+       uint32_t prod;
        const char *vendorstr;
        const char *prodstr;
+       const char *cis3str;
+       const char *cis4str;
 
 #ifdef DIAGNOSTIC
        if (sizeof *ent > ent_size)
-               panic("pccard_product_lookup: bogus ent_size %ld",
-                   (long) ent_size);
+               panic("pccard_product_lookup: bogus ent_size %jd",
+                   (intmax_t) ent_size);
 #endif
        vendor = pccard_get_vendor(dev);
        prod = pccard_get_product(dev);
-       fcn = pccard_get_function_number(dev);
        vendorstr = pccard_get_vendor_str(dev);
        prodstr = pccard_get_product_str(dev);
-       for (ent = tab; ent->pp_name != NULL; ent =
+       cis3str = pccard_get_cis3_str(dev);
+       cis4str = pccard_get_cis4_str(dev);
+
+       for (ent = tab; ent->pp_vendor != 0; ent =
            (const struct pccard_product *) ((const char *) ent + ent_size)) {
                matches = 1;
                if (ent->pp_vendor == PCCARD_VENDOR_ANY &&
-                   ent->pp_product == PCCARD_VENDOR_ANY &&
+                   ent->pp_product == PCCARD_PRODUCT_ANY &&
                    ent->pp_cis[0] == NULL &&
                    ent->pp_cis[1] == NULL) {
-                       device_printf(dev,
-                           "Total wildcard entry ignored for %s\n",
-                           ent->pp_name);
+                       if (ent->pp_name)
+                               device_printf(dev,
+                                   "Total wildcard entry ignored for %s\n",
+                                   ent->pp_name);
                        continue;
                }
                if (matches && ent->pp_vendor != PCCARD_VENDOR_ANY &&
@@ -333,15 +370,22 @@ pccard_do_product_lookup(device_t bus, device_t dev,
                if (matches && ent->pp_product != PCCARD_PRODUCT_ANY &&
                    prod != ent->pp_product)
                        matches = 0;
-               if (matches && fcn != ent->pp_expfunc)
-                       matches = 0;
                if (matches && ent->pp_cis[0] &&
-                   strcmp(ent->pp_cis[0], vendorstr) != 0)
+                   (vendorstr == NULL ||
+                   strcmp(ent->pp_cis[0], vendorstr) != 0))
                        matches = 0;
                if (matches && ent->pp_cis[1] &&
-                   strcmp(ent->pp_cis[1], prodstr) != 0)
+                   (prodstr == NULL ||
+                   strcmp(ent->pp_cis[1], prodstr) != 0))
+                       matches = 0;
+               if (matches && ent->pp_cis[2] &&
+                   (cis3str == NULL ||
+                   strcmp(ent->pp_cis[2], cis3str) != 0))
+                       matches = 0;
+               if (matches && ent->pp_cis[3] &&
+                   (cis4str == NULL ||
+                   strcmp(ent->pp_cis[3], cis4str) != 0))
                        matches = 0;
-               /* XXX need to match cis[2] and cis[3] also XXX */
                if (matchfn != NULL)
                        matches = (*matchfn)(dev, ent, matches);
                if (matches)
@@ -350,27 +394,6 @@ pccard_do_product_lookup(device_t bus, device_t dev,
        return (NULL);
 }
 
-static int
-pccard_card_gettype(device_t dev, int *type)
-{
-       struct pccard_softc *sc = PCCARD_SOFTC(dev);
-       struct pccard_function *pf;
-
-       /*
-        * set the iftype to memory if this card has no functions (not yet
-        * probed), or only one function, and that is not initialized yet or
-        * that is memory.
-        */
-       pf = STAILQ_FIRST(&sc->card.pf_head);
-       if (pf == NULL ||
-           (STAILQ_NEXT(pf, pf_list) == NULL &&
-           (pf->cfe == NULL || pf->cfe->iftype == PCCARD_IFTYPE_MEMORY)))
-               *type = PCCARD_IFTYPE_MEMORY;
-       else
-               *type = PCCARD_IFTYPE_IO;
-       return (0);
-}
-
 /*
  * Initialize a PCCARD function.  May be called as long as the function is
  * disabled.
@@ -385,15 +408,13 @@ static void
 pccard_function_init(struct pccard_function *pf)
 {
        struct pccard_config_entry *cfe;
-       int i;
        struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
        struct resource_list *rl = &devi->resources;
        struct resource_list_entry *rle;
        struct resource *r = 0;
        device_t bus;
-       int start;
-       int end;
-       int spaces;
+       u_long start, end, len;
+       int i, rid, spaces;
 
        if (pf->pf_flags & PFF_ENABLED) {
                kprintf("pccard_function_init: function is enabled");
@@ -402,53 +423,70 @@ pccard_function_init(struct pccard_function *pf)
        bus = device_get_parent(pf->dev);
        /* Remember which configuration entry we are using. */
        STAILQ_FOREACH(cfe, &pf->cfe_head, cfe_list) {
-               for (i = 0; i < cfe->num_iospace; i++)
-                       cfe->iores[i] = NULL;
-               cfe->irqres = NULL;
+               if (cfe->iftype != PCCARD_IFTYPE_IO)
+                       continue;
                spaces = 0;
                for (i = 0; i < cfe->num_iospace; i++) {
                        start = cfe->iospace[i].start;
                        if (start)
                                end = start + cfe->iospace[i].length - 1;
                        else
-                               end = ~0;
-                       cfe->iorid[i] = i;
-                       DEVPRINTF((bus, "I/O rid %d start %x end %x\n",
+                               end = ~0UL;
+                       DEVPRINTF((bus, "I/O rid %d start %lx end %lx\n",
                            i, start, end));
-                       r = cfe->iores[i] = bus_alloc_resource(bus,
-                           SYS_RES_IOPORT, &cfe->iorid[i], start, end,
-                           cfe->iospace[i].length,
-                           rman_make_alignment_flags(cfe->iospace[i].length));
-                       if (cfe->iores[i] == NULL)
+                       rid = i;
+                       len = cfe->iospace[i].length;
+                       r = bus_alloc_resource(bus, SYS_RES_IOPORT, &rid,
+                           start, end, len, rman_make_alignment_flags(len));
+                       if (r == NULL)
                                goto not_this_one;
-                       resource_list_add(rl, SYS_RES_IOPORT, cfe->iorid[i],
-                           rman_get_start(r), rman_get_end(r),
+                       resource_list_add(rl, SYS_RES_IOPORT,
+                           rid, rman_get_start(r), rman_get_end(r),
                            cfe->iospace[i].length);
-                       rle = resource_list_find(rl, SYS_RES_IOPORT,
-                           cfe->iorid[i]);
+                       rle = resource_list_find(rl, SYS_RES_IOPORT, rid);
+                       if (rle == NULL)
+                               panic("Cannot add resource rid %d IOPORT", rid);
                        rle->res = r;
                        spaces++;
                }
-               if (cfe->num_memspace > 0) {
-                       /*
-                        * Not implement yet, Fix me.
-                        */
-                       DEVPRINTF((bus, "Memory space not yet implemented.\n"));
+               for (i = 0; i < cfe->num_memspace; i++) {
+                       start = cfe->memspace[i].hostaddr;
+                       if (start)
+                               end = start + cfe->memspace[i].length - 1;
+                       else
+                               end = ~0UL;
+                       DEVPRINTF((bus, "Memory rid %d start %lx end %lx\n",
+                           i, start, end));
+                       rid = i;
+                       len = cfe->memspace[i].length;
+                       r = bus_alloc_resource(bus, SYS_RES_MEMORY, &rid,
+                           start, end, len, rman_make_alignment_flags(len));
+                       if (r == NULL)
+                               goto not_this_one;
+                       resource_list_add(rl, SYS_RES_MEMORY,
+                           rid, rman_get_start(r), rman_get_end(r),
+                           cfe->memspace[i].length);
+                       rle = resource_list_find(rl, SYS_RES_MEMORY, rid);
+                       if (rle == NULL)
+                               panic("Cannot add resource rid %d MEM", rid);
+                       rle->res = r;
+                       spaces++;
                }
                if (spaces == 0) {
-                       DEVPRINTF((bus, "Neither memory nor I/O mampped\n"));
+                       DEVPRINTF((bus, "Neither memory nor I/O mapped\n"));
                        goto not_this_one;
                }
                if (cfe->irqmask) {
-                       cfe->irqrid = 0;
-                       r = cfe->irqres = bus_alloc_resource(bus, SYS_RES_IRQ,
-                           &cfe->irqrid, 0, ~0, 1, 0);
-                       if (cfe->irqres == NULL)
+                       rid = 0;
+                       r = bus_alloc_resource_any(bus, SYS_RES_IRQ, &rid,
+                           RF_SHAREABLE);
+                       if (r == NULL)
                                goto not_this_one;
-                       resource_list_add(rl, SYS_RES_IRQ, cfe->irqrid,
+                       resource_list_add(rl, SYS_RES_IRQ, rid,
                            rman_get_start(r), rman_get_end(r), 1);
-                       rle = resource_list_find(rl, SYS_RES_IRQ,
-                           cfe->irqrid);
+                       rle = resource_list_find(rl, SYS_RES_IRQ, rid);
+                       if (rle == NULL)
+                               panic("Cannot add resource rid %d IRQ", rid);
                        rle->res = r;
                }
                /* If we get to here, we've allocated all we need */
@@ -457,31 +495,9 @@ pccard_function_init(struct pccard_function *pf)
            not_this_one:;
                DEVPRVERBOSE((bus, "Allocation failed for cfe %d\n",
                    cfe->number));
-               /*
-                * Release resources that we partially allocated
-                * from this config entry.
-                */
-               for (i = 0; i < cfe->num_iospace; i++) {
-                       if (cfe->iores[i] != NULL) {
-                               bus_release_resource(bus, SYS_RES_IOPORT,
-                                   cfe->iorid[i], cfe->iores[i]);
-                               rle = resource_list_find(rl, SYS_RES_IOPORT,
-                                   cfe->iorid[i]);
-                               rle->res = NULL;
-                               resource_list_delete(rl, SYS_RES_IOPORT,
-                                   cfe->iorid[i]);
-                       }
-                       cfe->iores[i] = NULL;
-               }
-               if (cfe->irqmask && cfe->irqres != NULL) {
-                       bus_release_resource(bus, SYS_RES_IRQ,
-                           cfe->irqrid, cfe->irqres);
-                       rle = resource_list_find(rl, SYS_RES_IRQ,
-                           cfe->irqrid);
-                       rle->res = NULL;
-                       resource_list_delete(rl, SYS_RES_IRQ, cfe->irqrid);
-                       cfe->irqres = NULL;
-               }
+#if 0 /* YYY */
+               resource_list_purge(rl);
+#endif
        }
 }
 
@@ -505,7 +521,7 @@ pccard_function_free(struct pccard_function *pf)
 
        SLIST_FOREACH(rle, &devi->resources, link) {
                if (rle->res) {
-                       if (rle->res->r_dev != pf->sc->dev)
+                       if (rman_get_device(rle->res) != pf->sc->dev)
                                device_printf(pf->sc->dev,
                                    "function_free: Resource still owned by "
                                    "child, oops. "
@@ -513,7 +529,7 @@ pccard_function_free(struct pccard_function *pf)
                                    rle->type, rle->rid,
                                    rman_get_start(rle->res));
                        BUS_RELEASE_RESOURCE(device_get_parent(pf->sc->dev),
-                           rle->res->r_dev, rle->type, rle->rid, rle->res);
+                           pf->sc->dev, rle->type, rle->rid, rle->res);
                        rle->res = NULL;
                }
        }
@@ -522,33 +538,37 @@ pccard_function_free(struct pccard_function *pf)
 
 static void
 pccard_mfc_adjust_iobase(struct pccard_function *pf, bus_addr_t addr,
-                       bus_addr_t offset, bus_size_t size)
+    bus_addr_t offset, bus_size_t size)
 {
        bus_size_t iosize, tmp;
-       
+
        if (addr != 0) {
                if (pf->pf_mfc_iomax == 0) {
                        pf->pf_mfc_iobase = addr + offset;
-                       pf->pf_mfc_iomax = pf->pf_mfc_iobase  + size;
+                       pf->pf_mfc_iomax = pf->pf_mfc_iobase + size;
                } else {
-                       if (pf->pf_mfc_iobase > addr  + offset)
+                       /* this makes the assumption that nothing overlaps */
+                       if (pf->pf_mfc_iobase > addr + offset)
                                pf->pf_mfc_iobase = addr + offset;
-                       if (pf->pf_mfc_iomax < addr + offset  + size)
+                       if (pf->pf_mfc_iomax < addr + offset + size)
                                pf->pf_mfc_iomax = addr + offset + size;
                }
-       }       
+       }
+
        tmp = pf->pf_mfc_iomax - pf->pf_mfc_iobase;
+       /* round up to nearest (2^n)-1 */
        for (iosize = 1; iosize < tmp; iosize <<= 1)
                ;
        iosize--;
 
+       DEVPRINTF((pf->dev, "MFC: I/O base %#jx IOSIZE %#jx\n",
+           (uintmax_t)pf->pf_mfc_iobase, (uintmax_t)(iosize + 1)));
        pccard_ccr_write(pf, PCCARD_CCR_IOBASE0,
-                        pf->pf_mfc_iobase & 0xff);
+           pf->pf_mfc_iobase & 0xff);
        pccard_ccr_write(pf, PCCARD_CCR_IOBASE1,
-                                (pf->pf_mfc_iobase >> 8) & 0xff);
+           (pf->pf_mfc_iobase >> 8) & 0xff);
        pccard_ccr_write(pf, PCCARD_CCR_IOBASE2, 0);
        pccard_ccr_write(pf, PCCARD_CCR_IOBASE3, 0);
-
        pccard_ccr_write(pf, PCCARD_CCR_IOSIZE, iosize);
 }
 
@@ -639,7 +659,7 @@ pccard_function_enable(struct pccard_function *pf)
 
        pccard_ccr_write(pf, PCCARD_CCR_SOCKETCOPY, 0);
 
-       if (pccard_mfc(pf->sc)) 
+       if (pccard_mfc(pf->sc))
                pccard_mfc_adjust_iobase(pf, 0, 0, 0);
 
 #ifdef PCCARDDEBUG
@@ -697,6 +717,8 @@ pccard_function_disable(struct pccard_function *pf)
                struct pccard_ivar *devi = PCCARD_IVAR(pf->dev);
                struct resource_list_entry *rle =
                    resource_list_find(&devi->resources, SYS_RES_IRQ, 0);
+               if (rle == NULL)
+                       panic("Can't disable an interrupt with no IRQ res\n");
                BUS_TEARDOWN_INTR(dev, pf->dev, rle->res,
                    pf->intr_handler_cookie);
        }
@@ -748,7 +770,7 @@ pccard_compat_do_attach(device_t bus, device_t dev)
        int err;
 
        err = CARD_COMPAT_PROBE(dev);
-       if (err == 0)
+       if (err <= 0)
                err = CARD_COMPAT_ATTACH(dev);
        return (err);
 }
@@ -796,15 +818,8 @@ pccard_suspend(device_t self)
        return (0);
 }
 
-static int
-pccard_shutdown(device_t self)
-{
-       pccard_detach_card(self);
-       bus_generic_shutdown(self);
-       return (0);
-}
-
-static int
+static
+int
 pccard_resume(device_t self)
 {
        return (0);
@@ -858,8 +873,8 @@ pccard_print_child(device_t dev, device_t child)
                    "%ld");
                pccard_print_resources(rl, "drq", SYS_RES_DRQ, PCCARD_NDRQ,
                    "%ld");
-               retval += kprintf(" function %d config %d", devi->fcn->number,
-                   devi->fcn->cfe->number);
+               retval += kprintf(" function %d config %d", devi->pf->number,
+                   devi->pf->cfe->number);
        }
 
        retval += bus_print_child_footer(dev, child);
@@ -869,7 +884,7 @@ pccard_print_child(device_t dev, device_t child)
 
 static int
 pccard_set_resource(device_t dev, device_t child, int type, int rid,
-                u_long start, u_long count)
+    u_long start, u_long count)
 {
        struct pccard_ivar *devi = PCCARD_IVAR(child);
        struct resource_list *rl = &devi->resources;
@@ -926,7 +941,7 @@ pccard_delete_resource(device_t dev, device_t child, int type, int rid)
 
 static int
 pccard_set_res_flags(device_t dev, device_t child, int type, int rid,
-    u_int32_t flags)
+    uint32_t flags)
 {
        return (CARD_SET_RES_FLAGS(device_get_parent(dev), child, type,
            rid, flags));
@@ -934,7 +949,7 @@ pccard_set_res_flags(device_t dev, device_t child, int type, int rid,
 
 static int
 pccard_set_memory_offset(device_t dev, device_t child, int rid,
-    u_int32_t offset, u_int32_t *deltap)
+    uint32_t offset, uint32_t *deltap)
 
 {
        return (CARD_SET_MEMORY_OFFSET(device_get_parent(dev), child, rid,
@@ -945,14 +960,18 @@ static void
 pccard_probe_nomatch(device_t bus, device_t child)
 {
        struct pccard_ivar *devi = PCCARD_IVAR(child);
-       struct pccard_function *func = devi->fcn;
+       struct pccard_function *pf = devi->pf;
        struct pccard_softc *sc = PCCARD_SOFTC(bus);
+       int i;
 
        device_printf(bus, "<unknown card>");
-       kprintf(" (manufacturer=0x%04x, product=0x%04x) at function %d\n",
-         sc->card.manufacturer, sc->card.product, func->number);
-       device_printf(bus, "   CIS info: %s, %s, %s\n", sc->card.cis1_info[0],
-         sc->card.cis1_info[1], sc->card.cis1_info[2]);
+       kprintf(" (manufacturer=0x%04x, product=0x%04x, function_type=%d) "
+           "at function %d\n", sc->card.manufacturer, sc->card.product,
+           pf->function, pf->number);
+       device_printf(bus, "   CIS info: ");
+       for (i = 0; sc->card.cis1_info[i] != NULL && i < 4; i++)
+               kprintf("%s%s", i > 0 ? ", " : "", sc->card.cis1_info[i]);
+       kprintf("\n");
        return;
 }
 
@@ -961,69 +980,90 @@ pccard_child_location_str(device_t bus, device_t child, char *buf,
     size_t buflen)
 {
        struct pccard_ivar *devi = PCCARD_IVAR(child);
-       struct pccard_function *func = devi->fcn;
+       struct pccard_function *pf = devi->pf;
 
-       ksnprintf(buf, buflen, "function=%d", func->number);
+       ksnprintf(buf, buflen, "function=%d", pf->number);
        return (0);
 }
 
+/* XXX Maybe this should be in subr_bus? */
+static void
+pccard_safe_quote(char *dst, const char *src, size_t len)
+{
+       char *walker = dst, *ep = dst + len - 1;
+
+       if (len == 0)
+               return;
+       while (walker < ep)
+       {
+               if (*src == '"') {
+                       if (ep - walker < 2)
+                               break;
+                       *walker++ = '\\';
+               }
+               *walker++ = *src++;
+       }
+       *walker = '\0';
+}
+
 static int
 pccard_child_pnpinfo_str(device_t bus, device_t child, char *buf,
     size_t buflen)
 {
        struct pccard_ivar *devi = PCCARD_IVAR(child);
-       struct pccard_function *func = devi->fcn;
+       struct pccard_function *pf = devi->pf;
        struct pccard_softc *sc = PCCARD_SOFTC(bus);
+       char cis0[128], cis1[128];
 
+       pccard_safe_quote(cis0, sc->card.cis1_info[0], sizeof(cis0));
+       pccard_safe_quote(cis1, sc->card.cis1_info[1], sizeof(cis1));
        ksnprintf(buf, buflen, "manufacturer=0x%04x product=0x%04x "
            "cisvendor=\"%s\" cisproduct=\"%s\" function_type=%d",
-           sc->card.manufacturer, sc->card.product, sc->card.cis1_info[0],
-           sc->card.cis1_info[1], func->function);
+           sc->card.manufacturer, sc->card.product, cis0, cis1, pf->function);
        return (0);
 }
 
 static int
-pccard_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
+pccard_read_ivar(device_t bus, device_t child, int which, u_char *result)
 {
        struct pccard_ivar *devi = PCCARD_IVAR(child);
-       struct pccard_function *func = devi->fcn;
+       struct pccard_function *pf = devi->pf;
        struct pccard_softc *sc = PCCARD_SOFTC(bus);
 
+       if (!pf)
+               panic("No pccard function pointer");
        switch (which) {
        default:
+               return (EINVAL);
        case PCCARD_IVAR_ETHADDR:
-               *result = (uintptr_t)func->pf_funce_lan_nid;
+               bcopy(pf->pf_funce_lan_nid, result, ETHER_ADDR_LEN);
                break;
        case PCCARD_IVAR_VENDOR:
-               *result = sc->card.manufacturer;
+               *(uint32_t *)result = sc->card.manufacturer;
                break;
        case PCCARD_IVAR_PRODUCT:
-               *result = sc->card.product;
+               *(uint32_t *)result = sc->card.product;
                break;
        case PCCARD_IVAR_PRODEXT:
-               *result = sc->card.prodext;
+               *(uint16_t *)result = sc->card.prodext;
                break;
        case PCCARD_IVAR_FUNCTION:
-               *result = func->function;
+               *(uint32_t *)result = pf->function;
                break;
        case PCCARD_IVAR_FUNCTION_NUMBER:
-               if (!func) {
-                       device_printf(bus, "No function number, bug!\n");
-                       return (ENOENT);
-               }
-               *result = func->number;
+               *(uint32_t *)result = pf->number;
                break;
        case PCCARD_IVAR_VENDOR_STR:
-               *result = (uintptr_t)sc->card.cis1_info[0];
+               *(const char **)result = sc->card.cis1_info[0];
                break;
        case PCCARD_IVAR_PRODUCT_STR:
-               *result = (uintptr_t)sc->card.cis1_info[1];
+               *(const char **)result = sc->card.cis1_info[1];
                break;
        case PCCARD_IVAR_CIS3_STR:
-               *result = (uintptr_t)sc->card.cis1_info[2];
+               *(const char **)result = sc->card.cis1_info[2];
                break;
        case PCCARD_IVAR_CIS4_STR:
-               *result = (uintptr_t)sc->card.cis1_info[3];
+               *(const char **)result = sc->card.cis1_info[3];
                break;
        }
        return (0);
@@ -1070,7 +1110,7 @@ pccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
        int isdefault = (start == 0 && end == ~0UL && count == 1);
        struct resource *r = NULL;
 
-
+       /* XXX I'm no longer sure this is right */
        if (passthrough) {
                return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
                    type, rid, start, end, count, flags));
@@ -1080,37 +1120,29 @@ pccard_alloc_resource(device_t dev, device_t child, int type, int *rid,
        rle = resource_list_find(&dinfo->resources, type, *rid);
 
        if (rle == NULL && isdefault)
-               return (NULL);          /* no resource of that type/rid */
-
-       if ((rle == NULL) || (rle->res == NULL)) {
-               
+               return (NULL);  /* no resource of that type/rid */
+       if (rle == NULL || rle->res == NULL) {
+               /* XXX Need to adjust flags */
                r = bus_alloc_resource(dev, type, rid, start, end,
-                           count, rman_make_alignment_flags(count));
+                 count, flags);
                if (r == NULL)
-                       goto bad;
+                   goto bad;
                resource_list_add(&dinfo->resources, type, *rid,
-                           rman_get_start(r), rman_get_end(r), count);
+                 rman_get_start(r), rman_get_end(r), count);
                rle = resource_list_find(&dinfo->resources, type, *rid);
                if (!rle)
-                       goto bad;
+                   goto bad;
                rle->res = r;
        }
-       if (rle->res->r_dev != dev)
+       /*
+        * If dev doesn't own the device, then we can't give this device
+        * out.
+        */
+       if (rman_get_device(rle->res) != dev)
                return (NULL);
-       bus_release_resource(dev, type, *rid, rle->res);
-       rle->res = NULL;
-       switch(type) {
-       case SYS_RES_IOPORT:
-       case SYS_RES_MEMORY:
-               if (!(flags & RF_ALIGNMENT_MASK))
-                       flags |= rman_make_alignment_flags(rle->count);
-               break;
-       case SYS_RES_IRQ:
-               flags |= RF_SHAREABLE;
-               break;
-       }
-       rle->res = resource_list_alloc(&dinfo->resources, dev, child,
-           type, rid, rle->start, rle->end, rle->count, flags);
+       rman_set_device(rle->res, child);
+       if (flags & RF_ACTIVE)
+               BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, rle->res);
        return (rle->res);
 bad:;
        device_printf(dev, "WARNING: Resource not reserved by pccard\n");
@@ -1124,8 +1156,6 @@ pccard_release_resource(device_t dev, device_t child, int type, int rid,
        struct pccard_ivar *dinfo;
        int passthrough = (device_get_parent(child) != dev);
        struct resource_list_entry *rle = 0;
-       int ret;
-       int flags;
 
        if (passthrough)
                return BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
@@ -1145,33 +1175,20 @@ pccard_release_resource(device_t dev, device_t child, int type, int rid,
                device_printf(dev, "Allocated resource not recorded\n");
                return ENOENT;
        }
-
-       ret = BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
-           type, rid, r);
-       switch(type) {
-       case SYS_RES_IOPORT:
-       case SYS_RES_MEMORY:
-               flags = rman_make_alignment_flags(rle->count);
-               break;
-       case SYS_RES_IRQ:
-               flags = RF_SHAREABLE;
-               break;
-       default:
-               flags = 0;
-       }
-       rle->res = bus_alloc_resource(dev, type, &rid,
-           rle->start, rle->end, rle->count, flags);
-       if (rle->res == NULL)
-               device_printf(dev, "release_resource: "
-                   "unable to reaquire resource\n");
-       return ret;
+       /*
+        * Deactivate the resource (since it is being released), and
+        * assign it to the bus.
+        */
+       BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, rle->res);
+       rman_set_device(rle->res, dev);
+       return (0);
 }
 
 static void
 pccard_child_detached(device_t parent, device_t dev)
 {
        struct pccard_ivar *ivar = PCCARD_IVAR(dev);
-       struct pccard_function *pf = ivar->fcn;
+       struct pccard_function *pf = ivar->pf;
 
        pccard_function_disable(pf);
 }
@@ -1194,6 +1211,10 @@ pccard_intr(void *arg)
         * the interrupt will pacify the card enough to keep an
         * interrupt storm from happening.  Of course this won't
         * help in the non-MFC case.
+        *
+        * This has no impact for MPSAFEness of the client drivers.
+        * We register this with whatever flags the intr_handler
+        * was registered with.  All these functions are MPSAFE.
         */
        if (pccard_mfc(pf->sc)) {
                reg = pccard_ccr_read(pf, PCCARD_CCR_STATUS);
@@ -1214,21 +1235,21 @@ pccard_setup_intr(device_t dev, device_t child, struct resource *irq,
 {
        struct pccard_softc *sc = PCCARD_SOFTC(dev);
        struct pccard_ivar *ivar = PCCARD_IVAR(child);
-       struct pccard_function *func = ivar->fcn;
+       struct pccard_function *pf = ivar->pf;
        int err;
 
-       if (func->intr_handler != NULL)
+       if (pf->intr_handler != NULL)
                panic("Only one interrupt handler per function allowed");
        err = bus_generic_setup_intr(dev, child, irq, flags, pccard_intr,
-                                    func, cookiep, serializer);
+                                    pf, cookiep, serializer);
        if (err != 0)
                return (err);
-       func->intr_handler = intr;
-       func->intr_handler_arg = arg;
-       func->intr_handler_cookie = *cookiep;
+       pf->intr_handler = intr;
+       pf->intr_handler_arg = arg;
+       pf->intr_handler_cookie = *cookiep;
        if (pccard_mfc(sc)) {
-               pccard_ccr_write(func, PCCARD_CCR_OPTION,
-                   pccard_ccr_read(func, PCCARD_CCR_OPTION) |
+               pccard_ccr_write(pf, PCCARD_CCR_OPTION,
+                   pccard_ccr_read(pf, PCCARD_CCR_OPTION) |
                    PCCARD_CCR_OPTION_IREQ_ENABLE);
        }
        return (0);
@@ -1240,36 +1261,40 @@ pccard_teardown_intr(device_t dev, device_t child, struct resource *r,
 {
        struct pccard_softc *sc = PCCARD_SOFTC(dev);
        struct pccard_ivar *ivar = PCCARD_IVAR(child);
-       struct pccard_function *func = ivar->fcn;
+       struct pccard_function *pf = ivar->pf;
        int ret;
 
        if (pccard_mfc(sc)) {
-               pccard_ccr_write(func, PCCARD_CCR_OPTION,
-                   pccard_ccr_read(func, PCCARD_CCR_OPTION) &
+               pccard_ccr_write(pf, PCCARD_CCR_OPTION,
+                   pccard_ccr_read(pf, PCCARD_CCR_OPTION) &
                    ~PCCARD_CCR_OPTION_IREQ_ENABLE);
        }
        ret = bus_generic_teardown_intr(dev, child, r, cookie);
        if (ret == 0) {
-               func->intr_handler = NULL;
-               func->intr_handler_arg = NULL;
-               func->intr_handler_cookie = NULL;
+               pf->intr_handler = NULL;
+               pf->intr_handler_arg = NULL;
+               pf->intr_handler_cookie = NULL;
        }
 
        return (ret);
 }
 
 static int
-pccard_activate_resource(device_t brdev, device_t child, int type,
-                       int rid, struct resource *r)
+pccard_activate_resource(device_t brdev, device_t child, int type, int rid,
+    struct resource *r)
 {
        struct pccard_ivar *ivar = PCCARD_IVAR(child);
-       struct pccard_function *pf = ivar->fcn;
-       
+       struct pccard_function *pf = ivar->pf;
+
        switch(type) {
        case SYS_RES_IOPORT:
+               /*
+                * We need to adjust IOBASE[01] and IOSIZE if we're an MFC
+                * card.
+                */
                if (pccard_mfc(pf->sc))
                        pccard_mfc_adjust_iobase(pf, rman_get_start(r), 0,
-                                       rman_get_size(r));
+                           rman_get_size(r));
                break;
        default:
                break;
@@ -1277,13 +1302,20 @@ pccard_activate_resource(device_t brdev, device_t child, int type,
        return (bus_generic_activate_resource(brdev, child, type, rid, r));
 }
 
+static int
+pccard_deactivate_resource(device_t brdev, device_t child, int type,
+    int rid, struct resource *r)
+{
+       /* XXX undo pccard_activate_resource? XXX */
+       return (bus_generic_deactivate_resource(brdev, child, type, rid, r));
+}
 
 static device_method_t pccard_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         pccard_probe),
        DEVMETHOD(device_attach,        pccard_attach),
        DEVMETHOD(device_detach,        pccard_detach),
-       DEVMETHOD(device_shutdown,      pccard_shutdown),
+       DEVMETHOD(device_shutdown,      bus_generic_shutdown),
        DEVMETHOD(device_suspend,       pccard_suspend),
        DEVMETHOD(device_resume,        pccard_resume),
 
@@ -1294,7 +1326,7 @@ static device_method_t pccard_methods[] = {
        DEVMETHOD(bus_alloc_resource,   pccard_alloc_resource),
        DEVMETHOD(bus_release_resource, pccard_release_resource),
        DEVMETHOD(bus_activate_resource, pccard_activate_resource),
-       DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+       DEVMETHOD(bus_deactivate_resource, pccard_deactivate_resource),
        DEVMETHOD(bus_setup_intr,       pccard_setup_intr),
        DEVMETHOD(bus_teardown_intr,    pccard_teardown_intr),
        DEVMETHOD(bus_set_resource,     pccard_set_resource),
@@ -1308,12 +1340,12 @@ static device_method_t pccard_methods[] = {
        /* Card Interface */
        DEVMETHOD(card_set_res_flags,   pccard_set_res_flags),
        DEVMETHOD(card_set_memory_offset, pccard_set_memory_offset),
-       DEVMETHOD(card_get_type,        pccard_card_gettype),
        DEVMETHOD(card_attach_card,     pccard_attach_card),
        DEVMETHOD(card_detach_card,     pccard_detach_card),
        DEVMETHOD(card_compat_do_probe, pccard_compat_do_probe),
        DEVMETHOD(card_compat_do_attach, pccard_compat_do_attach),
        DEVMETHOD(card_do_product_lookup, pccard_do_product_lookup),
+       DEVMETHOD(card_cis_scan,        pccard_scan_cis),
 
        { 0, 0 }
 };
@@ -1329,6 +1361,4 @@ devclass_t        pccard_devclass;
 /* Maybe we need to have a slot device? */
 DRIVER_MODULE(pccard, pcic, pccard_driver, pccard_devclass, 0, 0);
 DRIVER_MODULE(pccard, cbb, pccard_driver, pccard_devclass, 0, 0);
-DRIVER_MODULE(pccard, tcic, pccard_driver, pccard_devclass, 0, 0);
 MODULE_VERSION(pccard, 1);
-/*MODULE_DEPEND(pccard, pcic, 1, 1, 1);*/