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); }
int acpi_pci_suspend(device_t dev) { int dstate, error, i, numdevs; device_t acpi_dev, child, *devlist; struct pci_devinfo *dinfo; acpi_dev = devclass_get_device(devclass_find("acpi"), 0); device_get_children(dev, &devlist, &numdevs); /* * Save the PCI configuration space for each child and set the * device in the appropriate power state for this sleep state. */ for (i = 0; i < numdevs; i++) { child = devlist[i]; dinfo = (struct pci_devinfo *)device_get_ivars(child); pci_cfg_save(child, dinfo, 0); } /* * Suspend devices before potentially powering them down. */ error = bus_generic_suspend(dev); if (error) { kfree(devlist, M_TEMP); return (error); } /* * Always set the device to D3. If ACPI suggests a different * power state, use it instead. If ACPI is not present, the * firmware is responsible for managing device power. Skip * children who aren't attached since they are powered down * separately. Only manage type 0 devices for now. */ for (i = 0; acpi_dev && i < numdevs; i++) { child = devlist[i]; dinfo = (struct pci_devinfo *)device_get_ivars(child); if (device_is_attached(child) && dinfo->cfg.hdrtype == 0) { dstate = PCI_POWERSTATE_D3; ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate); pci_set_powerstate(child, dstate); } } kfree(devlist, M_TEMP); return (0); }
static void cardbus_driver_added(device_t cbdev, driver_t *driver) { int numdevs; device_t *devlist; device_t dev; int i; struct cardbus_devinfo *dinfo; DEVICE_IDENTIFY(driver, cbdev); if (device_get_children(cbdev, &devlist, &numdevs) != 0) return; /* * If there are no drivers attached, but there are children, * then power the card up. */ for (i = 0; i < numdevs; i++) { dev = devlist[i]; if (device_get_state(dev) != DS_NOTPRESENT) break; } if (i > 0 && i == numdevs) POWER_ENABLE_SOCKET(device_get_parent(cbdev), cbdev); for (i = 0; i < numdevs; i++) { dev = devlist[i]; if (device_get_state(dev) != DS_NOTPRESENT) continue; dinfo = device_get_ivars(dev); pci_print_verbose(&dinfo->pci); if (bootverbose) printf("pci%d:%d:%d:%d: reprobing on driver added\n", dinfo->pci.cfg.domain, dinfo->pci.cfg.bus, dinfo->pci.cfg.slot, dinfo->pci.cfg.func); pci_cfg_restore(dinfo->pci.cfg.dev, &dinfo->pci); if (device_probe_and_attach(dev) != 0) pci_cfg_save(dev, &dinfo->pci, 1); } free(devlist, M_TEMP); }