From 9c7d357cd4473cb11bcec2d12c0cc13ce874f93c Mon Sep 17 00:00:00 2001 From: imp Date: Fri, 15 Mar 2002 06:41:01 +0000 Subject: Revert most of the recent PCI merge. This has proven to be too unstable for the coming DP1 release. Instead, I'll develop that on the IMP_CB_MERGE branch until it is more stable. --- sys/dev/cardbus/cardbus.c | 982 +++++++++++++++++++++++++++++++++++++++--- sys/dev/cardbus/cardbus_cis.c | 115 ++--- 2 files changed, 971 insertions(+), 126 deletions(-) (limited to 'sys/dev/cardbus') diff --git a/sys/dev/cardbus/cardbus.c b/sys/dev/cardbus/cardbus.c index 0973921..5e58ecc 100644 --- a/sys/dev/cardbus/cardbus.c +++ b/sys/dev/cardbus/cardbus.c @@ -28,11 +28,12 @@ * $FreeBSD$ */ -/* XXX pci_cfgfree vs cardbus_cfgfree */ - /* * Cardbus Bus Driver * + * much of the bus code was stolen directly from sys/pci/pci.c + * (Copyright (c) 1997, Stefan Esser ) + * * Written by Jonathan Chen */ @@ -50,7 +51,6 @@ #include #include #include -#include #include #include @@ -63,13 +63,13 @@ /* sysctl vars */ SYSCTL_NODE(_hw, OID_AUTO, cardbus, CTLFLAG_RD, 0, "CardBus parameters"); -int cardbus_debug = 0; +int cardbus_debug = 0; TUNABLE_INT("hw.cardbus.debug", &cardbus_debug); SYSCTL_INT(_hw_cardbus, OID_AUTO, debug, CTLFLAG_RW, &cardbus_debug, 0, "CardBus debug"); -int cardbus_cis_debug = 0; +int cardbus_cis_debug = 0; TUNABLE_INT("hw.cardbus.cis_debug", &cardbus_cis_debug); SYSCTL_INT(_hw_cardbus, OID_AUTO, cis_debug, CTLFLAG_RW, &cardbus_cis_debug, 0, @@ -86,8 +86,62 @@ static void device_setup_regs(device_t brdev, int b, int s, int f, static int cardbus_attach_card(device_t cbdev); static int cardbus_detach_card(device_t cbdev, int flags); static void cardbus_driver_added(device_t cbdev, driver_t *driver); +static void cardbus_read_extcap(device_t cbdev, pcicfgregs *cfg); +static void cardbus_hdrtypedata(device_t brdev, int b, int s, int f, + pcicfgregs *cfg); +static struct cardbus_devinfo *cardbus_read_device(device_t brdev, int b, + int s, int f); +static int cardbus_freecfg(struct cardbus_devinfo *dinfo); +static void cardbus_print_verbose(struct cardbus_devinfo *dinfo); +static int cardbus_set_resource(device_t cbdev, device_t child, int type, + int rid, u_long start, u_long count, struct resource *res); +static int cardbus_get_resource(device_t cbdev, device_t child, int type, + int rid, u_long *startp, u_long *countp); +static void cardbus_delete_resource(device_t cbdev, device_t child, + int type, int rid); +static int cardbus_set_resource_method(device_t cbdev, device_t child, + int type, int rid, u_long start, u_long count); +static int cardbus_get_resource_method(device_t cbdev, device_t child, + int type, int rid, u_long *startp, u_long *countp); +static void cardbus_delete_resource_method(device_t cbdev, device_t child, + int type, int rid); static void cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo); +static struct resource *cardbus_alloc_resource(device_t cbdev, device_t child, + int type, int *rid, u_long start, u_long end, u_long count, + u_int flags); +static int cardbus_release_resource(device_t cbdev, device_t child, + int type, int rid, struct resource *r); +static int cardbus_setup_intr(device_t cbdev, device_t child, + struct resource *irq, int flags, driver_intr_t *intr, + void *arg, void **cookiep); +static int cardbus_teardown_intr(device_t cbdev, device_t child, + struct resource *irq, void *cookie); +static int cardbus_print_resources(struct resource_list *rl, + const char *name, int type, const char *format); +static int cardbus_print_child(device_t cbdev, device_t child); +static void cardbus_probe_nomatch(device_t cbdev, device_t child); +static int cardbus_read_ivar(device_t cbdev, device_t child, int which, + u_long *result); +static int cardbus_write_ivar(device_t cbdev, device_t child, int which, + uintptr_t value); +static int cardbus_set_powerstate_method(device_t cbdev, device_t child, + int state); +static int cardbus_get_powerstate_method(device_t cbdev, device_t child); +static u_int32_t cardbus_read_config_method(device_t cbdev, + device_t child, int reg, int width); +static void cardbus_write_config_method(device_t cbdev, device_t child, + int reg, u_int32_t val, int width); +static __inline void cardbus_set_command_bit(device_t cbdev, device_t child, + u_int16_t bit); +static __inline void cardbus_clear_command_bit(device_t cbdev, device_t child, + u_int16_t bit); +static void cardbus_enable_busmaster_method(device_t cbdev, device_t child); +static void cardbus_disable_busmaster_method(device_t cbdev, device_t child); +static void cardbus_enable_io_method(device_t cbdev, device_t child, + int space); +static void cardbus_disable_io_method(device_t cbdev, device_t child, + int space); /************************************************************************/ /* Probe/Attach */ @@ -150,6 +204,8 @@ device_setup_regs(device_t brdev, int b, int s, int f, pcicfgregs *cfg) cfg->maxlat = PCIB_READ_CONFIG(brdev, b, s, f, PCIR_MAXLAT, 1); } +#define DETACH_NOWARN 0x800 + static int cardbus_attach_card(device_t cbdev) { @@ -157,11 +213,8 @@ cardbus_attach_card(device_t cbdev) int cardattached = 0; static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ int bus, slot, func; - struct cardbus_devinfo *dinfo; - int cardbusfunchigh = 0; - device_t kid; - cardbus_detach_card(cbdev, 0); /* detach existing cards */ + cardbus_detach_card(cbdev, DETACH_NOWARN); /* detach existing cards */ POWER_ENABLE_SOCKET(brdev, cbdev); bus = pcib_get_bus(cbdev); @@ -179,28 +232,27 @@ cardbus_attach_card(device_t cbdev) } /* For each function, set it up and try to attach a driver to it */ for (slot = 0; slot <= CARDBUS_SLOTMAX; slot++) { - cardbusfunchigh = 0; + int cardbusfunchigh = 0; for (func = 0; func <= cardbusfunchigh; func++) { - dinfo = (struct cardbus_devinfo *) - pci_read_device(brdev, bus, slot, func, - sizeof(struct cardbus_devinfo)); + struct cardbus_devinfo *dinfo = + cardbus_read_device(brdev, bus, slot, func); + if (dinfo == NULL) continue; if (dinfo->pci.cfg.mfdev) cardbusfunchigh = CARDBUS_FUNCMAX; - device_setup_regs(brdev, bus, slot, func, - &dinfo->pci.cfg); - kid = device_add_child(cbdev, NULL, -1); - if (kid == NULL) { + device_setup_regs(brdev, bus, slot, func, &dinfo->pci.cfg); + cardbus_print_verbose(dinfo); + dinfo->pci.cfg.dev = device_add_child(cbdev, NULL, -1); + if (!dinfo->pci.cfg.dev) { DEVPRINTF((cbdev, "Cannot add child!\n")); - pci_freecfg(&dinfo->pci); + cardbus_freecfg(dinfo); continue; } - dinfo->pci.cfg.dev = kid; - device_set_ivars(kid, &dinfo->pci); - cardbus_do_cis(cbdev, kid); - pci_print_verbose(&dinfo->pci); - if (device_probe_and_attach(kid) != 0) { + resource_list_init(&dinfo->pci.resources); + device_set_ivars(dinfo->pci.cfg.dev, dinfo); + cardbus_do_cis(cbdev, dinfo->pci.cfg.dev); + if (device_probe_and_attach(dinfo->pci.cfg.dev) != 0) { /* when fail, release all resources */ cardbus_release_all_resources(cbdev, dinfo); } else @@ -221,22 +273,21 @@ cardbus_detach_card(device_t cbdev, int flags) device_t *devlist; int tmp; int err = 0; - struct cardbus_devinfo *dinfo; - int status; device_get_children(cbdev, &devlist, &numdevs); if (numdevs == 0) { - if (bootverbose) + if (!(flags & DETACH_NOWARN)) { DEVPRINTF((cbdev, "detach_card: no card to detach!\n")); - POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); + POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); + } free(devlist, M_TEMP); return ENOENT; } for (tmp = 0; tmp < numdevs; tmp++) { - dinfo = device_get_ivars(devlist[tmp]); - status = device_get_state(devlist[tmp]); + struct cardbus_devinfo *dinfo = device_get_ivars(devlist[tmp]); + int status = device_get_state(devlist[tmp]); if (status == DS_ATTACHED || status == DS_BUSY) { if (device_detach(dinfo->pci.cfg.dev) == 0 || @@ -246,11 +297,12 @@ cardbus_detach_card(device_t cbdev, int flags) } else { err++; } + cardbus_freecfg(dinfo); } else { cardbus_release_all_resources(cbdev, dinfo); device_delete_child(cbdev, devlist[tmp]); + cardbus_freecfg(dinfo); } - pci_freecfg(&dinfo->pci); } if (err == 0) POWER_DISABLE_SOCKET(device_get_parent(cbdev), cbdev); @@ -261,10 +313,10 @@ cardbus_detach_card(device_t cbdev, int flags) static void cardbus_driver_added(device_t cbdev, driver_t *driver) { + /* XXX check if 16-bit or cardbus! */ int numdevs; device_t *devlist; int tmp, cardattached; - struct cardbus_devinfo *dinfo; device_get_children(cbdev, &devlist, &numdevs); @@ -283,13 +335,14 @@ cardbus_driver_added(device_t cbdev, driver_t *driver) DEVICE_IDENTIFY(driver, cbdev); for (tmp = 0; tmp < numdevs; tmp++) { if (device_get_state(devlist[tmp]) == DS_NOTPRESENT) { + struct cardbus_devinfo *dinfo; dinfo = device_get_ivars(devlist[tmp]); cardbus_release_all_resources(cbdev, dinfo); resource_list_init(&dinfo->pci.resources); cardbus_do_cis(cbdev, dinfo->pci.cfg.dev); - if (device_probe_and_attach(dinfo->pci.cfg.dev) != 0) + if (device_probe_and_attach(dinfo->pci.cfg.dev) != 0) { cardbus_release_all_resources(cbdev, dinfo); - else + } else cardattached++; } } @@ -298,15 +351,837 @@ cardbus_driver_added(device_t cbdev, driver_t *driver) } /************************************************************************/ +/* PCI-Like config reading (copied from pci.c */ +/************************************************************************/ + +/* read configuration header into pcicfgrect structure */ + +static void +cardbus_read_extcap(device_t cbdev, pcicfgregs *cfg) +{ +#define REG(n, w) PCIB_READ_CONFIG(cbdev, cfg->bus, cfg->slot, cfg->func, n, w) + int ptr, nextptr, ptrptr; + + switch (cfg->hdrtype) { + case 0: + ptrptr = 0x34; + break; + case 2: + ptrptr = 0x14; + break; + default: + return; /* no extended capabilities support */ + } + nextptr = REG(ptrptr, 1); /* sanity check? */ + + /* + * Read capability entries. + */ + while (nextptr != 0) { + /* Sanity check */ + if (nextptr > 255) { + printf("illegal PCI extended capability offset %d\n", + nextptr); + return; + } + /* Find the next entry */ + ptr = nextptr; + nextptr = REG(ptr + 1, 1); + + /* Process this entry */ + switch (REG(ptr, 1)) { + case 0x01: /* PCI power management */ + if (cfg->pp_cap == 0) { + cfg->pp_cap = REG(ptr + PCIR_POWER_CAP, 2); + cfg->pp_status = ptr + PCIR_POWER_STATUS; + cfg->pp_pmcsr = ptr + PCIR_POWER_PMCSR; + if ((nextptr - ptr) > PCIR_POWER_DATA) + cfg->pp_data = ptr + PCIR_POWER_DATA; + } + break; + default: + break; + } + } +#undef REG +} + +/* extract header type specific config data */ + +static void +cardbus_hdrtypedata(device_t brdev, int b, int s, int f, pcicfgregs *cfg) +{ +#define REG(n, w) PCIB_READ_CONFIG(brdev, b, s, f, n, w) + switch (cfg->hdrtype) { + case 0: + cfg->subvendor = REG(PCIR_SUBVEND_0, 2); + cfg->subdevice = REG(PCIR_SUBDEV_0, 2); + cfg->nummaps = PCI_MAXMAPS_0; + break; + case 1: + cfg->subvendor = REG(PCIR_SUBVEND_1, 2); + cfg->subdevice = REG(PCIR_SUBDEV_1, 2); + cfg->nummaps = PCI_MAXMAPS_1; + break; + case 2: + cfg->subvendor = REG(PCIR_SUBVEND_2, 2); + cfg->subdevice = REG(PCIR_SUBDEV_2, 2); + cfg->nummaps = PCI_MAXMAPS_2; + break; + } +#undef REG +} + +static struct cardbus_devinfo * +cardbus_read_device(device_t brdev, int b, int s, int f) +{ +#define REG(n, w) PCIB_READ_CONFIG(brdev, b, s, f, n, w) + pcicfgregs *cfg = NULL; + struct cardbus_devinfo *devlist_entry = NULL; + + if (REG(PCIR_DEVVENDOR, 4) != -1) { + devlist_entry = malloc(sizeof(struct cardbus_devinfo), + M_DEVBUF, M_WAITOK | M_ZERO); + if (devlist_entry == NULL) + return (NULL); + + cfg = &devlist_entry->pci.cfg; + + cfg->bus = b; + cfg->slot = s; + cfg->func = f; + cfg->vendor = REG(PCIR_VENDOR, 2); + cfg->device = REG(PCIR_DEVICE, 2); + cfg->cmdreg = REG(PCIR_COMMAND, 2); + cfg->statreg = REG(PCIR_STATUS, 2); + cfg->baseclass = REG(PCIR_CLASS, 1); + cfg->subclass = REG(PCIR_SUBCLASS, 1); + cfg->progif = REG(PCIR_PROGIF, 1); + cfg->revid = REG(PCIR_REVID, 1); + cfg->hdrtype = REG(PCIR_HEADERTYPE, 1); + cfg->cachelnsz = REG(PCIR_CACHELNSZ, 1); + cfg->lattimer = REG(PCIR_LATTIMER, 1); + cfg->intpin = REG(PCIR_INTPIN, 1); + cfg->intline = REG(PCIR_INTLINE, 1); + + cfg->mingnt = REG(PCIR_MINGNT, 1); + cfg->maxlat = REG(PCIR_MAXLAT, 1); + + cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; + cfg->hdrtype &= ~PCIM_MFDEV; + + cardbus_hdrtypedata(brdev, b, s, f, cfg); + + if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) + cardbus_read_extcap(brdev, cfg); + + devlist_entry->pci.conf.pc_sel.pc_bus = cfg->bus; + devlist_entry->pci.conf.pc_sel.pc_dev = cfg->slot; + devlist_entry->pci.conf.pc_sel.pc_func = cfg->func; + devlist_entry->pci.conf.pc_hdr = cfg->hdrtype; + + devlist_entry->pci.conf.pc_subvendor = cfg->subvendor; + devlist_entry->pci.conf.pc_subdevice = cfg->subdevice; + devlist_entry->pci.conf.pc_vendor = cfg->vendor; + devlist_entry->pci.conf.pc_device = cfg->device; + + devlist_entry->pci.conf.pc_class = cfg->baseclass; + devlist_entry->pci.conf.pc_subclass = cfg->subclass; + devlist_entry->pci.conf.pc_progif = cfg->progif; + devlist_entry->pci.conf.pc_revid = cfg->revid; + } + return (devlist_entry); +#undef REG +} + +/* free pcicfgregs structure and all depending data structures */ + +static int +cardbus_freecfg(struct cardbus_devinfo *dinfo) +{ + free(dinfo, M_DEVBUF); + + return (0); +} + +static void +cardbus_print_verbose(struct cardbus_devinfo *dinfo) +{ +#ifndef CARDBUS_DEBUG + if (bootverbose) +#endif /* CARDBUS_DEBUG */ + { + pcicfgregs *cfg = &dinfo->pci.cfg; + + printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", + cfg->vendor, cfg->device, cfg->revid); + printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", + cfg->baseclass, cfg->subclass, cfg->progif, + cfg->hdrtype, cfg->mfdev); +#ifdef CARDBUS_DEBUG + printf("\tcmdreg=0x%04x, statreg=0x%04x, " + "cachelnsz=%d (dwords)\n", + cfg->cmdreg, cfg->statreg, cfg->cachelnsz); + printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), " + "maxlat=0x%02x (%d ns)\n", + cfg->lattimer, cfg->lattimer * 30, + cfg->mingnt, cfg->mingnt * 250, cfg->maxlat, + cfg->maxlat * 250); +#endif /* CARDBUS_DEBUG */ + if (cfg->intpin > 0) + printf("\tintpin=%c, irq=%d\n", + cfg->intpin + 'a' - 1, cfg->intline); + } +} + +/************************************************************************/ /* Resources */ /************************************************************************/ +static int +cardbus_set_resource(device_t cbdev, device_t child, int type, int rid, + u_long start, u_long count, struct resource *res) +{ + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return ENOENT; + + dinfo = device_get_ivars(child); + rl = &dinfo->pci.resources; + rle = resource_list_find(rl, type, rid); + if (rle == NULL) { + resource_list_add(rl, type, rid, start, start + count - 1, + count); + if (res != NULL) { + rle = resource_list_find(rl, type, rid); + rle->res = res; + } + } else { + if (rle->res == NULL) { + } else if (rle->res->r_dev == cbdev && + (!(rman_get_flags(rle->res) & RF_ACTIVE))) { + int f; + f = rman_get_flags(rle->res); + bus_release_resource(cbdev, type, rid, res); + rle->res = bus_alloc_resource(cbdev, type, &rid, + start, start + count - 1, + count, f); + } else { + device_printf(cbdev, "set_resource: resource busy\n"); + return EBUSY; + } + rle->start = start; + rle->end = start + count - 1; + rle->count = count; + if (res != NULL) + rle->res = res; + } + if (device_get_parent(child) == cbdev) + pci_write_config(child, rid, start, 4); + return 0; +} + +static int +cardbus_get_resource(device_t cbdev, device_t child, int type, int rid, + u_long *startp, u_long *countp) +{ + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return ENOENT; + + dinfo = device_get_ivars(child); + rl = &dinfo->pci.resources; + rle = resource_list_find(rl, type, rid); + if (!rle) + return ENOENT; + if (startp) + *startp = rle->start; + if (countp) + *countp = rle->count; + return 0; +} + +static void +cardbus_delete_resource(device_t cbdev, device_t child, int type, int rid) +{ + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + struct resource_list_entry *rle; + + if (device_get_parent(child) != cbdev) + return; + + dinfo = device_get_ivars(child); + rl = &dinfo->pci.resources; + rle = resource_list_find(rl, type, rid); + if (rle) { + if (rle->res) { + if (rle->res->r_dev != cbdev || + rman_get_flags(rle->res) & RF_ACTIVE) { + device_printf(cbdev, "delete_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + return; + } + bus_release_resource(cbdev, type, rid, rle->res); + } + resource_list_delete(rl, type, rid); + } + if (device_get_parent(child) == cbdev) + pci_write_config(child, rid, 0, 4); +} + +static int +cardbus_set_resource_method(device_t cbdev, device_t child, int type, int rid, + u_long start, u_long count) +{ + int ret; + ret = cardbus_set_resource(cbdev, child, type, rid, start, count, NULL); + if (ret != 0) + return ret; + return BUS_SET_RESOURCE(device_get_parent(cbdev), child, type, rid, + start, count); +} + +static int +cardbus_get_resource_method(device_t cbdev, device_t child, int type, int rid, + u_long *startp, u_long *countp) +{ + int ret; + ret = cardbus_get_resource(cbdev, child, type, rid, startp, countp); + if (ret != 0) + return ret; + return BUS_GET_RESOURCE(device_get_parent(cbdev), child, type, rid, + startp, countp); +} + +static void +cardbus_delete_resource_method(device_t cbdev, device_t child, + int type, int rid) +{ + cardbus_delete_resource(cbdev, child, type, rid); + BUS_DELETE_RESOURCE(device_get_parent(cbdev), child, type, rid); +} + static void cardbus_release_all_resources(device_t cbdev, struct cardbus_devinfo *dinfo) { + struct resource_list_entry *rle; + + /* Free all allocated resources */ + SLIST_FOREACH(rle, &dinfo->pci.resources, link) { + if (rle->res) { + if (rle->res->r_dev != cbdev) + device_printf(cbdev, "release_all_resource: " + "Resource still owned by child, oops. " + "(type=%d, rid=%d, addr=%lx)\n", + rle->type, rle->rid, + rman_get_start(rle->res)); + BUS_RELEASE_RESOURCE(device_get_parent(cbdev), + rle->res->r_dev, + rle->type, rle->rid, + rle->res); + rle->res = NULL; + /* + * zero out config so the card won't acknowledge + * access to the space anymore + */ + pci_write_config(dinfo->pci.cfg.dev, rle->rid, 0, 4); + } + } resource_list_free(&dinfo->pci.resources); } +static struct resource * +cardbus_alloc_resource(device_t cbdev, device_t child, int type, + int *rid, u_long start, u_long end, u_long count, u_int flags) +{ + struct cardbus_devinfo *dinfo; + struct resource_list_entry *rle = 0; + int passthrough = (device_get_parent(child) != cbdev); + + if (passthrough) { + return (BUS_ALLOC_RESOURCE(device_get_parent(cbdev), child, + type, rid, start, end, count, flags)); + } + + dinfo = device_get_ivars(child); + rle = resource_list_find(&dinfo->pci.resources, type, *rid); + + if (!rle) + return NULL; /* no resource of that type/rid */ + + if (!rle->res) { + device_printf(cbdev, "WARNING: Resource not reserved by bus\n"); + return NULL; + } else { + /* Release the cardbus hold on the resource */ + if (rle->res->r_dev != cbdev) + return NULL; + bus_release_resource(cbdev, 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; + } + /* Allocate the resource to the child */ + return resource_list_alloc(&dinfo->pci.resources, cbdev, child, + type, rid, rle->start, rle->end, rle->count, flags); + } +} + +static int +cardbus_release_resource(device_t cbdev, device_t child, int type, int rid, + struct resource *r) +{ + struct cardbus_devinfo *dinfo; + int passthrough = (device_get_parent(child) != cbdev); + struct resource_list_entry *rle = 0; + int flags; + int ret; + + if (passthrough) { + return BUS_RELEASE_RESOURCE(device_get_parent(cbdev), child, + type, rid, r); + } + + dinfo = device_get_ivars(child); + /* + * According to the PCI 2.2 spec, devices may share an address + * decoder between memory mapped ROM access and memory + * mapped register access. To be safe, disable ROM access + * whenever it is released. + */ + if (rid == CARDBUS_ROM_REG) { + uint32_t rom_reg; + + rom_reg = pci_read_config(child, rid, 4); + rom_reg &= ~CARDBUS_ROM_ENABLE; + pci_write_config(child, rid, rom_reg, 4); + } + + rle = resource_list_find(&dinfo->pci.resources, type, rid); + + if (!rle) { + device_printf(cbdev, "Allocated resource not found\n"); + return ENOENT; + } + if (!rle->res) { + device_printf(cbdev, "Allocated resource not recorded\n"); + return ENOENT; + } + + ret = BUS_RELEASE_RESOURCE(device_get_parent(cbdev), 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; + } + /* Restore cardbus hold on the resource */ + rle->res = bus_alloc_resource(cbdev, type, &rid, + rle->start, rle->end, rle->count, flags); + if (rle->res == NULL) + device_printf(cbdev, "release_resource: " + "unable to reacquire resource\n"); + return ret; +} + +static int +cardbus_setup_intr(device_t cbdev, device_t child, struct resource *irq, + int flags, driver_intr_t *intr, void *arg, void **cookiep) +{ + int ret; + device_t cdev; + struct cardbus_devinfo *dinfo; + + ret = bus_generic_setup_intr(cbdev, child, irq, flags, intr, arg, + cookiep); + if (ret != 0) + return ret; + + for (cdev = child; cbdev != device_get_parent(cdev); + cdev = device_get_parent(cdev)) + /* NOTHING */; + dinfo = device_get_ivars(cdev); + + return 0; +} + +static int +cardbus_teardown_intr(device_t cbdev, device_t child, struct resource *irq, + void *cookie) +{ + int ret; + device_t cdev; + struct cardbus_devinfo *dinfo; + + ret = bus_generic_teardown_intr(cbdev, child, irq, cookie); + if (ret != 0) + return ret; + + for (cdev = child; cbdev != device_get_parent(cdev); + cdev = device_get_parent(cdev)) + /* NOTHING */; + dinfo = device_get_ivars(cdev); + + return (0); +} + + +/************************************************************************/ +/* Other Bus Methods */ +/************************************************************************/ + +static int +cardbus_print_resources(struct resource_list *rl, const char *name, + int type, const char *format) +{ + struct resource_list_entry *rle; + int printed, retval; + + printed = 0; + retval = 0; + /* Yes, this is kinda cheating */ + SLIST_FOREACH(rle, rl, link) { + if (rle->type == type) { + if (printed == 0) + retval += printf(" %s ", name); + else if (printed > 0) + retval += printf(","); + printed++; + retval += printf(format, rle->start); + if (rle->count > 1) { + retval += printf("-"); + retval += printf(format, rle->start + + rle->count - 1); + } + } + } + return retval; +} + +static int +cardbus_print_child(device_t cbdev, device_t child) +{ + struct cardbus_devinfo *dinfo; + struct resource_list *rl; + pcicfgregs *cfg; + int retval = 0; + + dinfo = device_get_ivars(child); + cfg = &dinfo->pci.cfg; + rl = &dinfo->pci.resources; + + retval += bus_print_child_header(cbdev, child); + + retval += cardbus_print_resources(rl, "port", SYS_RES_IOPORT, "%#lx"); + retval += cardbus_print_resources(rl, "mem", SYS_RES_MEMORY, "%#lx"); + retval += cardbus_print_resources(rl, "irq", SYS_RES_IRQ, "%ld"); + if (device_get_flags(cbdev)) + retval += printf(" flags %#x", device_get_flags(cbdev)); + + retval += printf(" at device %d.%d", pci_get_slot(child), + pci_get_function(child)); + + retval += bus_print_child_footer(cbdev, child); + + return (retval); +} + +static void +cardbus_probe_nomatch(device_t cbdev, device_t child) +{ + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->pci.cfg; + device_printf(cbdev, ""); + printf(" (vendor=0x%04x, dev=0x%04x)", cfg->vendor, cfg->device); + printf(" at %d.%d", pci_get_slot(child), pci_get_function(child)); + if (cfg->intpin > 0 && cfg->intline != 255) { + printf(" irq %d", cfg->intline); + } + printf("\n"); + + return; +} + +static int +cardbus_read_ivar(device_t cbdev, device_t child, int which, u_long *result) +{ + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->pci.cfg; + + switch (which) { + case PCI_IVAR_SUBVENDOR: + *result = cfg->subvendor; + break; + case PCI_IVAR_SUBDEVICE: + *result = cfg->subdevice; + break; + case PCI_IVAR_VENDOR: + *result = cfg->vendor; + break; + case PCI_IVAR_DEVICE: + *result = cfg->device; + break; + case PCI_IVAR_DEVID: + *result = (cfg->device << 16) | cfg->vendor; + break; + case PCI_IVAR_CLASS: + *result = cfg->baseclass; + break; + case PCI_IVAR_SUBCLASS: + *result = cfg->subclass; + break; + case PCI_IVAR_PROGIF: + *result = cfg->progif; + break; + case PCI_IVAR_REVID: + *result = cfg->revid; + break; + case PCI_IVAR_INTPIN: + *result = cfg->intpin; + break; + case PCI_IVAR_IRQ: + *result = cfg->intline; + break; + case PCI_IVAR_BUS: + *result = cfg->bus; + break; + case PCI_IVAR_SLOT: + *result = cfg->slot; + break; + case PCI_IVAR_FUNCTION: + *result = cfg->func; + break; + default: + return ENOENT; + } + return 0; +} + +static int +cardbus_write_ivar(device_t cbdev, device_t child, int which, uintptr_t value) +{ + struct cardbus_devinfo *dinfo; + pcicfgregs *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->pci.cfg; + + switch (which) { + case PCI_IVAR_SUBVENDOR: + case PCI_IVAR_SUBDEVICE: + case PCI_IVAR_VENDOR: + case PCI_IVAR_DEVICE: + case PCI_IVAR_DEVID: + case PCI_IVAR_CLASS: + case PCI_IVAR_SUBCLASS: + case PCI_IVAR_PROGIF: + case PCI_IVAR_REVID: + case PCI_IVAR_INTPIN: + case PCI_IVAR_IRQ: + case PCI_IVAR_BUS: + case PCI_IVAR_SLOT: + case PCI_IVAR_FUNCTION: + return EINVAL; /* disallow for now */ + default: + return ENOENT; + } + return 0; +} + +/************************************************************************/ +/* Compatibility with PCI bus (XXX: Do we need this?) */ +/************************************************************************/ + +/* + * PCI power manangement + */ +static int +cardbus_set_powerstate_method(device_t cbdev, device_t child, int state) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->pci.cfg; + u_int16_t status; + int result; + + if (cfg->pp_cap != 0) { + status = PCI_READ_CONFIG(cbdev, child, cfg->pp_status, 2) + & ~PCIM_PSTAT_DMASK; + result = 0; + switch (state) { + case PCI_POWERSTATE_D0: + status |= PCIM_PSTAT_D0; + break; + case PCI_POWERSTATE_D1: + if (cfg->pp_cap & PCIM_PCAP_D1SUPP) { + status |= PCIM_PSTAT_D1; + } else { + result = EOPNOTSUPP; + } + break; + case PCI_POWERSTATE_D2: + if (cfg->pp_cap & PCIM_PCAP_D2SUPP) { + status |= PCIM_PSTAT_D2; + } else { + result = EOPNOTSUPP; + } + break; + case PCI_POWERSTATE_D3: + status |= PCIM_PSTAT_D3; + break; + default: + result = EINVAL; + } + if (result == 0) + PCI_WRITE_CONFIG(cbdev, child, cfg->pp_status, + status, 2); + } else { + result = ENXIO; + } + return (result); +} + +static int +cardbus_get_powerstate_method(device_t cbdev, device_t child) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->pci.cfg; + u_int16_t status; + int result; + + if (cfg->pp_cap != 0) { + status = PCI_READ_CONFIG(cbdev, child, cfg->pp_status, 2); + switch (status & PCIM_PSTAT_DMASK) { + case PCIM_PSTAT_D0: + result = PCI_POWERSTATE_D0; + break; + case PCIM_PSTAT_D1: + result = PCI_POWERSTATE_D1; + break; + case PCIM_PSTAT_D2: + result = PCI_POWERSTATE_D2; + break; + case PCIM_PSTAT_D3: + result = PCI_POWERSTATE_D3; + break; + default: + result = PCI_POWERSTATE_UNKNOWN; + break; + } + } else { + /* No support, device is always at D0 */ + result = PCI_POWERSTATE_D0; + } + return (result); +} + +static u_int32_t +cardbus_read_config_method(device_t cbdev, device_t child, int reg, int width) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->pci.cfg; + + return PCIB_READ_CONFIG(device_get_parent(cbdev), + cfg->bus, cfg->slot, cfg->func, reg, width); +} + +static void +cardbus_write_config_method(device_t cbdev, device_t child, int reg, + u_int32_t val, int width) +{ + struct cardbus_devinfo *dinfo = device_get_ivars(child); + pcicfgregs *cfg = &dinfo->pci.cfg; + + PCIB_WRITE_CONFIG(device_get_parent(cbdev), + cfg->bus, cfg->slot, cfg->func, reg, val, width); +} + +static __inline void +cardbus_set_command_bit(device_t cbdev, device_t child, u_int16_t bit) +{ + u_int16_t command; + + command = PCI_READ_CONFIG(cbdev, child, PCIR_COMMAND, 2); + command |= bit; + PCI_WRITE_CONFIG(cbdev, child, PCIR_COMMAND, command, 2); +} + +static __inline void +cardbus_clear_command_bit(device_t cbdev, device_t child, u_int16_t bit) +{ + u_int16_t command; + + command = PCI_READ_CONFIG(cbdev, child, PCIR_COMMAND, 2); + command &= ~bit; + PCI_WRITE_CONFIG(cbdev, child, PCIR_COMMAND, command, 2); +} + +static void +cardbus_enable_busmaster_method(device_t cbdev, device_t child) +{ + cardbus_set_command_bit(cbdev, child, PCIM_CMD_BUSMASTEREN); +} + +static void +cardbus_disable_busmaster_method(device_t cbdev, device_t child) +{ + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_BUSMASTEREN); +} + +static void +cardbus_enable_io_method(device_t cbdev, device_t child, int space) +{ + switch (space) { + case SYS_RES_IOPORT: + cardbus_set_command_bit(cbdev, child, PCIM_CMD_PORTEN); + break; + case SYS_RES_MEMORY: + cardbus_set_command_bit(cbdev, child, PCIM_CMD_MEMEN); + break; + } +} + +static void +cardbus_disable_io_method(device_t cbdev, device_t child, int space) +{ + switch (space) { + case SYS_RES_IOPORT: + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_PORTEN); + break; + case SYS_RES_MEMORY: + cardbus_clear_command_bit(cbdev, child, PCIM_CMD_MEMEN); + break; + } +} + static device_method_t cardbus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cardbus_probe), @@ -317,22 +1192,21 @@ static device_method_t cardbus_methods[] = { DEVMETHOD(device_resume, cardbus_resume), /* Bus interface */ - DEVMETHOD(bus_print_child, pci_print_child), - DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), - DEVMETHOD(bus_read_ivar, pci_read_ivar), - DEVMETHOD(bus_write_ivar, pci_write_ivar), + DEVMETHOD(bus_print_child, cardbus_print_child), + DEVMETHOD(bus_probe_nomatch, cardbus_probe_nomatch), + DEVMETHOD(bus_read_ivar, cardbus_read_ivar), + DEVMETHOD(bus_write_ivar, cardbus_write_ivar), DEVMETHOD(bus_driver_added, cardbus_driver_added), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - - DEVMETHOD(bus_get_resource_list,pci_get_resource_list), - DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), - DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), - DEVMETHOD(bus_delete_resource, pci_delete_resource), - DEVMETHOD(bus_alloc_resource, pci_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_alloc_resource, cardbus_alloc_resource), + DEVMETHOD(bus_release_resource, cardbus_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + DEVMETHOD(bus_setup_intr, cardbus_setup_intr), + DEVMETHOD(bus_teardown_intr, cardbus_teardown_intr), + + DEVMETHOD(bus_set_resource, cardbus_set_resource_method), + DEVMETHOD(bus_get_resource, cardbus_get_resource_method), + DEVMETHOD(bus_delete_resource, cardbus_delete_resource_method), /* Card Interface */ DEVMETHOD(card_attach_card, cardbus_attach_card), @@ -341,14 +1215,14 @@ static device_method_t cardbus_methods[] = { DEVMETHOD(card_cis_free, cardbus_cis_free), /* Cardbus/PCI interface */ - DEVMETHOD(pci_read_config, pci_read_config_method), - DEVMETHOD(pci_write_config, pci_write_config_method), - DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), - DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), - DEVMETHOD(pci_enable_io, pci_enable_io_method), - DEVMETHOD(pci_disable_io, pci_disable_io_method), - DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), - DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), + DEVMETHOD(pci_read_config, cardbus_read_config_method), + DEVMETHOD(pci_write_config, cardbus_write_config_method), + DEVMETHOD(pci_enable_busmaster, cardbus_enable_busmaster_method), + DEVMETHOD(pci_disable_busmaster, cardbus_disable_busmaster_method), + DEVMETHOD(pci_enable_io, cardbus_enable_io_method), + DEVMETHOD(pci_disable_io, cardbus_disable_io_method), + DEVMETHOD(pci_get_powerstate, cardbus_get_powerstate_method), + DEVMETHOD(pci_set_powerstate, cardbus_set_powerstate_method), {0,0} }; diff --git a/sys/dev/cardbus/cardbus_cis.c b/sys/dev/cardbus/cardbus_cis.c index 162b166..ba56430 100644 --- a/sys/dev/cardbus/cardbus_cis.c +++ b/sys/dev/cardbus/cardbus_cis.c @@ -413,7 +413,7 @@ cardbus_read_tuple_init(device_t cbdev, device_t child, u_int32_t *start, switch (CARDBUS_CIS_SPACE(*start)) { case CARDBUS_CIS_ASI_TUPLE: /* CIS in tuple space need no initialization */ - return (NULL); + return ((struct resource*)~0UL); case CARDBUS_CIS_ASI_BAR0: case CARDBUS_CIS_ASI_BAR1: case CARDBUS_CIS_ASI_BAR2: @@ -595,24 +595,24 @@ cardbus_alloc_resources(device_t cbdev, device_t child) { struct cardbus_devinfo *dinfo = device_get_ivars(child); int count; - struct resource_list *rl = &dinfo->pci.resources; struct resource_list_entry *rle; struct resource_list_entry **barlist; int tmp; u_int32_t mem_psize = 0, mem_nsize = 0, io_size = 0; struct resource *res; - u_int32_t start, end; - int rid, flags, irq; + u_int32_t start,end; + int rid, flags; count = 0; - SLIST_FOREACH(rle, rl, link) + SLIST_FOREACH(rle, &dinfo->pci.resources, link) { count++; + } if (count == 0) return (0); barlist = malloc(sizeof(struct resource_list_entry*) * count, M_DEVBUF, M_WAITOK); count = 0; - SLIST_FOREACH(rle, rl, link) { + SLIST_FOREACH(rle, &dinfo->pci.resources, link) { barlist[count] = rle; if (rle->type == SYS_RES_IOPORT) { io_size += rle->count; @@ -654,11 +654,6 @@ cardbus_alloc_resources(device_t cbdev, device_t child) res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, (dinfo->mprefetchable & dinfo->mbelow1mb)?0xFFFFF:~0UL, mem_psize, flags); - if (res == NULL) { /* XXX need cleanup*/ - device_printf(cbdev, "Unable to allocate memory for " - "prefetchable memory.\n"); - return (ENOMEM); - } start = rman_get_start(res); end = rman_get_end(res); DEVPRINTF((cbdev, "Prefetchable memory at %x-%x\n", start, end)); @@ -684,22 +679,20 @@ cardbus_alloc_resources(device_t cbdev, device_t child) DEVPRINTF((cbdev, "Cannot pre-allocate " "prefetchable memory, will try as " "non-prefetchable.\n")); - continue; + } else { + barlist[tmp]->start = + rman_get_start(barlist[tmp]->res); + barlist[tmp]->end = + rman_get_end(barlist[tmp]->res); + pci_write_config(child, + barlist[tmp]->rid, + barlist[tmp]->start, 4); + DEVPRINTF((cbdev, "Prefetchable memory " + "rid=%x at %lx-%lx\n", + barlist[tmp]->rid, + barlist[tmp]->start, + barlist[tmp]->end)); } - barlist[tmp]->start = - rman_get_start(barlist[tmp]->res); - barlist[tmp]->end = - rman_get_end(barlist[tmp]->res); - pci_write_config(child, - barlist[tmp]->rid, - barlist[tmp]->start, 4); - bus_release_resource(cbdev, SYS_RES_MEMORY, - barlist[tmp]->rid, barlist[tmp]->res); - DEVPRINTF((cbdev, "Prefetchable memory " - "rid=%x at %lx-%lx\n", - barlist[tmp]->rid, - barlist[tmp]->start, - barlist[tmp]->end)); } } } @@ -726,11 +719,6 @@ cardbus_alloc_resources(device_t cbdev, device_t child) res = bus_alloc_resource(cbdev, SYS_RES_MEMORY, &rid, 0, ((~dinfo->mprefetchable) & dinfo->mbelow1mb)?0xFFFFF:~0UL, mem_nsize, flags); - if (res == NULL) { /* XXX need cleanup*/ - device_printf(cbdev, "Unable to allocate memory for " - "non-prefetchable memory.\n"); - return (ENOMEM); - } start = rman_get_start(res); end = rman_get_end(res); DEVPRINTF((cbdev, "Non-prefetchable memory at %x-%x\n", @@ -759,9 +747,6 @@ cardbus_alloc_resources(device_t cbdev, device_t child) barlist[tmp]->res); pci_write_config(child, barlist[tmp]->rid, barlist[tmp]->start, 4); - bus_release_resource(cbdev, SYS_RES_MEMORY, - barlist[tmp]->rid, barlist[tmp]->res); - barlist[tmp]->res = NULL; DEVPRINTF((cbdev, "Non-prefetchable memory " "rid=%x at %lx-%lx (%lx)\n", barlist[tmp]->rid, barlist[tmp]->start, @@ -789,19 +774,14 @@ cardbus_alloc_resources(device_t cbdev, device_t child) * (XXX: Perhaps there might be a better way to do this?) */ rid = 0; - res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0, ~0UL, - io_size, flags); - if (res == NULL) { /* XXX need cleanup*/ - device_printf(cbdev, "Unable to allocate I/O ports\n"); - return (ENOMEM); - } + res = bus_alloc_resource(cbdev, SYS_RES_IOPORT, &rid, 0, + (dinfo->ibelow1mb)?0xFFFFF:~0UL, io_size, flags); start = rman_get_start(res); end = rman_get_end(res); DEVPRINTF((cbdev, "IO port at %x-%x\n", start, end)); /* * Now that we know the region is free, release it and hand it - * out piece by piece. XXX Need to interlock with the RM - * so we don't race here. + * out piece by piece. */ bus_release_resource(cbdev, SYS_RES_IOPORT, rid, res); for (tmp = 0; tmp < count; tmp++) { @@ -821,32 +801,26 @@ cardbus_alloc_resources(device_t cbdev, device_t child) rman_get_start(barlist[tmp]->res); barlist[tmp]->end = rman_get_end(barlist[tmp]->res); - pci_write_config(child, barlist[tmp]->rid, - barlist[tmp]->start, 4); - bus_release_resource(cbdev, SYS_RES_IOPORT, - barlist[tmp]->rid, barlist[tmp]->res); - barlist[tmp]->res = NULL; - DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n", - barlist[tmp]->rid, barlist[tmp]->start, - barlist[tmp]->end)); + pci_write_config(child, barlist[tmp]->rid, + barlist[tmp]->start, 4); + DEVPRINTF((cbdev, "IO port rid=%x at %lx-%lx\n", + barlist[tmp]->rid, barlist[tmp]->start, + barlist[tmp]->end)); } } } /* Allocate IRQ */ + /* XXX: Search CIS for IRQ description */ rid = 0; res = bus_alloc_resource(cbdev, SYS_RES_IRQ, &rid, 0, ~0UL, 1, RF_SHAREABLE); - if (res == NULL) { /* XXX need cleanup*/ - device_printf(cbdev, "Unable to allocate IRQ\n"); - return (ENOMEM); - } - irq = rman_get_start(res); - resource_list_add(rl, SYS_RES_IRQ, rid, irq, irq, 1); - dinfo->pci.cfg.intline = irq; - pci_write_config(child, PCIR_INTLINE, irq, 1); - printf("Allocating IRQ %d\n", irq); - bus_release_resource(cbdev, SYS_RES_IRQ, rid, res); + resource_list_add(&dinfo->pci.resources, SYS_RES_IRQ, rid, + rman_get_start(res), rman_get_end(res), 1); + rle = resource_list_find(&dinfo->pci.resources, SYS_RES_IRQ, rid); + rle->res = res; + dinfo->pci.cfg.intline = rman_get_start(res); + pci_write_config(child, PCIR_INTLINE, rman_get_start(res), 1); return (0); } @@ -859,17 +833,15 @@ static void cardbus_add_map(device_t cbdev, device_t child, int reg) { struct cardbus_devinfo *dinfo = device_get_ivars(child); - struct resource_list *rl = &dinfo->pci.resources; + struct resource_list_entry *rle; u_int32_t size; u_int32_t testval; int type; - testval = pci_read_config(child, reg, 4); - type = (testval & 1) ? SYS_RES_IOPORT : SYS_RES_MEMORY; - if (resource_list_find(rl, type, reg) != NULL) - return; - - /* XXX Should just be able to use pci_add_map */ + SLIST_FOREACH(rle, &dinfo->pci.resources, link) { + if (rle->rid == reg) + return; + } if (reg == CARDBUS_ROM_REG) testval = CARDBUS_ROM_ADDRMASK; @@ -888,9 +860,9 @@ cardbus_add_map(device_t cbdev, device_t child, int reg) type = SYS_RES_IOPORT; size = CARDBUS_MAPREG_MEM_SIZE(testval); - device_printf(cbdev, "BAR not in CIS: type = %d, id=%x, size=%x\n", - type, reg, size); - resource_list_add(rl, type, reg, 0UL, ~0UL, size); + device_printf(cbdev, "Resource not specified in CIS: id=%x, size=%x\n", + reg, size); + resource_list_add(&dinfo->pci.resources, type, reg, 0UL, ~0UL, size); } static void @@ -911,8 +883,7 @@ cardbus_pickup_maps(device_t cbdev, device_t child) } for (q = &cardbus_quirks[0]; q->devid; q++) { - if (q->devid == ((dinfo->pci.cfg.device << 16) | - dinfo->pci.cfg.vendor) + if (q->devid == ((dinfo->pci.cfg.device << 16) | dinfo->pci.cfg.vendor) && q->type == CARDBUS_QUIRK_MAP_REG) { cardbus_add_map(cbdev, child, q->arg1); } -- cgit v1.1