static int cardbus_attach_card(device_t cbdev) { device_t brdev = device_get_parent(cbdev); device_t child; int bus, domain, slot, func; int cardattached = 0; int cardbusfunchigh = 0; struct cardbus_softc *sc; sc = device_get_softc(cbdev); cardbus_detach_card(cbdev); /* detach existing cards */ POWER_ENABLE_SOCKET(brdev, cbdev); domain = pcib_get_domain(cbdev); bus = pcib_get_bus(cbdev); slot = 0; /* For each function, set it up and try to attach a driver to it */ for (func = 0; func <= cardbusfunchigh; func++) { struct cardbus_devinfo *dinfo; dinfo = (struct cardbus_devinfo *) pci_read_device(brdev, domain, bus, slot, func, sizeof(struct cardbus_devinfo)); if (dinfo == NULL) continue; if (dinfo->pci.cfg.mfdev) cardbusfunchigh = PCI_FUNCMAX; child = device_add_child(cbdev, NULL, -1); if (child == NULL) { DEVPRINTF((cbdev, "Cannot add child!\n")); pci_freecfg((struct pci_devinfo *)dinfo); continue; } dinfo->pci.cfg.dev = child; resource_list_init(&dinfo->pci.resources); device_set_ivars(child, dinfo); cardbus_device_create(sc, dinfo, cbdev, child); if (cardbus_do_cis(cbdev, child) != 0) DEVPRINTF((cbdev, "Warning: Bogus CIS ignored\n")); pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 0); pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); cardbus_device_setup_regs(&dinfo->pci.cfg); pci_add_resources(cbdev, child, 1, dinfo->mprefetchable); pci_print_verbose(&dinfo->pci); if (device_probe_and_attach(child) == 0) cardattached++; else pci_cfg_save(dinfo->pci.cfg.dev, &dinfo->pci, 1); } if (cardattached > 0) return (0); /* POWER_DISABLE_SOCKET(brdev, cbdev); */ return (ENOENT); }
static struct resource * cardbus_read_tuple_init(device_t cbdev, device_t child, uint32_t *start, int *rid) { struct resource *res; uint32_t space; space = *start & PCIM_CIS_ASI_MASK; switch (space) { case PCIM_CIS_ASI_CONFIG: DEVPRINTF((cbdev, "CIS in PCI config space\n")); /* CIS in PCI config space need no initialization */ return (CIS_CONFIG_SPACE); case PCIM_CIS_ASI_BAR0: case PCIM_CIS_ASI_BAR1: case PCIM_CIS_ASI_BAR2: case PCIM_CIS_ASI_BAR3: case PCIM_CIS_ASI_BAR4: case PCIM_CIS_ASI_BAR5: *rid = PCIR_BAR(space - PCIM_CIS_ASI_BAR0); DEVPRINTF((cbdev, "CIS in BAR %#x\n", *rid)); break; case PCIM_CIS_ASI_ROM: *rid = PCIR_BIOS; DEVPRINTF((cbdev, "CIS in option rom\n")); break; default: device_printf(cbdev, "Unable to read CIS: Unknown space: %d\n", space); return (NULL); } /* allocate the memory space to read CIS */ res = bus_alloc_resource_any(child, SYS_RES_MEMORY, rid, rman_make_alignment_flags(4096) | RF_ACTIVE); if (res == NULL) { device_printf(cbdev, "Unable to allocate resource " "to read CIS.\n"); return (NULL); } DEVPRINTF((cbdev, "CIS Mapped to %#lx\n", rman_get_start(res))); /* Flip to the right ROM image if CIS is in ROM */ if (space == PCIM_CIS_ASI_ROM) { uint32_t imagesize; uint32_t imagebase = 0; uint32_t pcidata; uint16_t romsig; int romnum = 0; int imagenum; imagenum = (*start & PCIM_CIS_ROM_MASK) >> 28; for (romnum = 0;; romnum++) { romsig = bus_read_2(res, imagebase + CARDBUS_EXROM_SIGNATURE); if (romsig != 0xaa55) { device_printf(cbdev, "Bad header in rom %d: " "[%x] %04x\n", romnum, imagebase + CARDBUS_EXROM_SIGNATURE, romsig); cardbus_read_tuple_finish(cbdev, child, *rid, res); *rid = 0; return (NULL); } /* * If this was the Option ROM image that we were * looking for, then we are done. */ if (romnum == imagenum) break; /* Find out where the next Option ROM image is */ pcidata = imagebase + bus_read_2(res, imagebase + CARDBUS_EXROM_DATA_PTR); imagesize = bus_read_2(res, pcidata + CARDBUS_EXROM_DATA_IMAGE_LENGTH); if (imagesize == 0) { /* * XXX some ROMs seem to have this as zero, * can we assume this means 1 block? */ device_printf(cbdev, "Warning, size of Option " "ROM image %d is 0 bytes, assuming 512 " "bytes.\n", romnum); imagesize = 1; } /* Image size is in 512 byte units */ imagesize <<= 9; if ((bus_read_1(res, pcidata + CARDBUS_EXROM_DATA_INDICATOR) & 0x80) != 0) { device_printf(cbdev, "Cannot find CIS in " "Option ROM\n"); cardbus_read_tuple_finish(cbdev, child, *rid, res); *rid = 0; return (NULL); } imagebase += imagesize; } *start = imagebase + (*start & PCIM_CIS_ADDR_MASK); } else {
static int cbb_pci_attach(device_t brdev) { static int curr_bus_number = 2; /* XXX EVILE BAD (see below) */ struct cbb_softc *sc = (struct cbb_softc *)device_get_softc(brdev); struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; int rid; device_t parent; uint32_t pribus; parent = device_get_parent(brdev); mtx_init(&sc->mtx, device_get_nameunit(brdev), "cbb", MTX_DEF); sc->chipset = cbb_chipset(pci_get_devid(brdev), NULL); sc->dev = brdev; sc->cbdev = NULL; sc->exca[0].pccarddev = NULL; sc->domain = pci_get_domain(brdev); sc->secbus = pci_read_config(brdev, PCIR_SECBUS_2, 1); sc->subbus = pci_read_config(brdev, PCIR_SUBBUS_2, 1); sc->pribus = pcib_get_bus(parent); SLIST_INIT(&sc->rl); cbb_powerstate_d0(brdev); rid = CBBR_SOCKBASE; sc->base_res = bus_alloc_resource_any(brdev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->base_res) { device_printf(brdev, "Could not map register memory\n"); mtx_destroy(&sc->mtx); return (ENOMEM); } else { DEVPRINTF((brdev, "Found memory at %08lx\n", rman_get_start(sc->base_res))); } sc->bst = rman_get_bustag(sc->base_res); sc->bsh = rman_get_bushandle(sc->base_res); exca_init(&sc->exca[0], brdev, sc->bst, sc->bsh, CBB_EXCA_OFFSET); sc->exca[0].flags |= EXCA_HAS_MEMREG_WIN; sc->exca[0].chipset = EXCA_CARDBUS; sc->chipinit = cbb_chipinit; sc->chipinit(sc); /*Sysctls*/ sctx = device_get_sysctl_ctx(brdev); soid = device_get_sysctl_tree(brdev); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "domain", CTLFLAG_RD, &sc->domain, 0, "Domain number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "pribus", CTLFLAG_RD, &sc->pribus, 0, "Primary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "secbus", CTLFLAG_RD, &sc->secbus, 0, "Secondary bus number"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "subbus", CTLFLAG_RD, &sc->subbus, 0, "Subordinate bus number"); #if 0 SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "memory", CTLFLAG_RD, &sc->subbus, 0, "Memory window open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "premem", CTLFLAG_RD, &sc->subbus, 0, "Prefetch memroy window open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io1", CTLFLAG_RD, &sc->subbus, 0, "io range 1 open"); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "io2", CTLFLAG_RD, &sc->subbus, 0, "io range 2 open"); #endif /* * This is a gross hack. We should be scanning the entire pci * tree, assigning bus numbers in a way such that we (1) can * reserve 1 extra bus just in case and (2) all sub busses * are in an appropriate range. */ DEVPRINTF((brdev, "Secondary bus is %d\n", sc->secbus)); pribus = pci_read_config(brdev, PCIR_PRIBUS_2, 1); if (sc->secbus == 0 || sc->pribus != pribus) { if (curr_bus_number <= sc->pribus) curr_bus_number = sc->pribus + 1; if (pribus != sc->pribus) { DEVPRINTF((brdev, "Setting primary bus to %d\n", sc->pribus)); pci_write_config(brdev, PCIR_PRIBUS_2, sc->pribus, 1); } sc->secbus = curr_bus_number++; sc->subbus = curr_bus_number++; DEVPRINTF((brdev, "Secondary bus set to %d subbus %d\n", sc->secbus, sc->subbus)); pci_write_config(brdev, PCIR_SECBUS_2, sc->secbus, 1); pci_write_config(brdev, PCIR_SUBBUS_2, sc->subbus, 1); } /* attach children */ sc->cbdev = device_add_child(brdev, "cardbus", -1); if (sc->cbdev == NULL) DEVPRINTF((brdev, "WARNING: cannot add cardbus bus.\n")); else if (device_probe_and_attach(sc->cbdev) != 0) DEVPRINTF((brdev, "WARNING: cannot attach cardbus bus!\n")); sc->exca[0].pccarddev = device_add_child(brdev, "pccard", -1); if (sc->exca[0].pccarddev == NULL) DEVPRINTF((brdev, "WARNING: cannot add pccard bus.\n")); else if (device_probe_and_attach(sc->exca[0].pccarddev) != 0) DEVPRINTF((brdev, "WARNING: cannot attach pccard bus.\n")); /* Map and establish the interrupt. */ rid = 0; sc->irq_res = bus_alloc_resource_any(brdev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(brdev, "Unable to map IRQ...\n"); goto err; } if (bus_setup_intr(brdev, sc->irq_res, INTR_TYPE_AV | INTR_MPSAFE, cbb_pci_filt, NULL, sc, &sc->intrhand)) { device_printf(brdev, "couldn't establish interrupt\n"); goto err; } /* reset 16-bit pcmcia bus */ exca_clrb(&sc->exca[0], EXCA_INTR, EXCA_INTR_RESET); /* turn off power */ cbb_power(brdev, CARD_OFF); /* CSC Interrupt: Card detect interrupt on */ cbb_setb(sc, CBB_SOCKET_MASK, CBB_SOCKET_MASK_CD); /* reset interrupt */ cbb_set(sc, CBB_SOCKET_EVENT, cbb_get(sc, CBB_SOCKET_EVENT)); if (bootverbose) cbb_print_config(brdev); /* Start the thread */ if (kproc_create(cbb_event_thread, sc, &sc->event_thread, 0, 0, "%s event thread", device_get_nameunit(brdev))) { device_printf(brdev, "unable to create event thread.\n"); panic("cbb_create_event_thread"); } sc->sc_root_token = root_mount_hold(device_get_nameunit(sc->dev)); return (0); err: if (sc->irq_res) bus_release_resource(brdev, SYS_RES_IRQ, 0, sc->irq_res); if (sc->base_res) { bus_release_resource(brdev, SYS_RES_MEMORY, CBBR_SOCKBASE, sc->base_res); } mtx_destroy(&sc->mtx); return (ENOMEM); }