static void vtpci_probe_and_attach_child(struct vtpci_softc *sc) { device_t dev, child; dev = sc->vtpci_dev; child = sc->vtpci_child_dev; if (child == NULL) return; if (device_get_state(child) != DS_NOTPRESENT) return; if (device_probe(child) != 0) return; vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER); if (device_attach(child) != 0) { vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_FAILED); vtpci_reset(sc); vtpci_release_child_resources(sc); /* Reset status for future attempt. */ vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_ACK); } else { vtpci_set_status(dev, VIRTIO_CONFIG_STATUS_DRIVER_OK); VIRTIO_ATTACH_COMPLETED(child); } }
/* * Locate the ACPI timer using the FADT, set up and allocate the I/O resources * we will be using. */ static int acpi_timer_identify(driver_t *driver, device_t parent) { device_t dev; /* * Just try once, do nothing if the 'acpi' bus is rescanned. */ if (device_get_state(parent) == DS_ATTACHED) return (0); ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (acpi_disabled("timer") || (acpi_quirks & ACPI_Q_TIMER) || acpi_timer_dev) return (ENXIO); if ((dev = BUS_ADD_CHILD(parent, parent, 0, "acpi_timer", 0)) == NULL) { device_printf(parent, "could not add acpi_timer0\n"); return (ENXIO); } acpi_timer_dev = dev; return (0); }
static int isahint_identify(driver_t *driver, device_t parent) { int i; static char buf[] = "isaXXX"; /* * If the parent bus is already attached we are being called to * rescan. We do not suppot rescanning the hints, just return * success. */ if (device_get_state(parent) == DS_ATTACHED) return(0); if (device_get_state(parent) == DS_INPROGRESS) return(0); /* * Add all devices configured to be attached to parent. */ ksprintf(buf, "isa%d", device_get_unit(parent)); for (i = resource_query_string(-1, "at", buf); i != -1; i = resource_query_string(i, "at", buf)) { if (strcmp(resource_query_name(i), "atkbd") == 0) continue; /* old GENERIC kludge */ isahint_add_device(parent, resource_query_name(i), resource_query_unit(i)); } /* * and isa? */ for (i = resource_query_string(-1, "at", "isa"); i != -1; i = resource_query_string(i, "at", "isa")) { if (strcmp(resource_query_name(i), "atkbd") == 0) continue; /* old GENERIC kludge */ isahint_add_device(parent, resource_query_name(i), resource_query_unit(i)); } return(0); }
/* * Locate the ACPI timer using the FADT, set up and allocate the I/O resources * we will be using. */ static int acpi_hpet_identify(driver_t *driver, device_t parent) { ACPI_TABLE_HPET *hpet; ACPI_TABLE_HEADER *hdr; ACPI_STATUS status; device_t child; /* * Just try once, do nothing if the 'acpi' bus is rescanned. */ if (device_get_state(parent) == DS_ATTACHED) return 0; ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__); /* Only one HPET device can be added. */ if (devclass_get_device(acpi_hpet_devclass, 0)) return ENXIO; /* Currently, ID and minimum clock tick info is unused. */ status = AcpiGetTable(ACPI_SIG_HPET, 1, &hdr); if (ACPI_FAILURE(status)) return ENXIO; /* * The unit number could be derived from hdr->Sequence but we only * support one HPET device. */ hpet = (ACPI_TABLE_HPET *)hdr; if (hpet->Sequence != 0) { kprintf("ACPI HPET table warning: Sequence is non-zero (%d)\n", hpet->Sequence); } child = BUS_ADD_CHILD(parent, parent, 0, "acpi_hpet", 0); if (child == NULL) { device_printf(parent, "%s: can't add acpi_hpet0\n", __func__); return ENXIO; } /* Record a magic value so we can detect this device later. */ acpi_set_magic(child, (uintptr_t)&acpi_hpet_devclass); acpi_hpet_res_start = hpet->Address.Address; if (bus_set_resource(child, SYS_RES_MEMORY, 0, hpet->Address.Address, HPET_MEM_WIDTH, -1)) { device_printf(child, "could not set iomem resources: " "0x%jx, %d\n", (uintmax_t)hpet->Address.Address, HPET_MEM_WIDTH); return ENOMEM; } 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); }
static int rp_pcishutdown(device_t dev) { CONTROLLER_t *ctlp; if (device_get_state(dev) == DS_BUSY) return (EBUSY); ctlp = device_get_softc(dev); rp_pcireleaseresource(ctlp); return (0); }
/* * Locate the ACPI timer using the FADT, set up and allocate the I/O resources * we will be using. */ static int acpi_timer_identify(driver_t *driver, device_t parent) { device_t dev; u_long rlen, rstart; int rid, rtype; /* * Just try once, do nothing if the 'acpi' bus is rescanned. */ if (device_get_state(parent) == DS_ATTACHED) return (0); ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); if (acpi_disabled("timer") || (acpi_quirks & ACPI_Q_TIMER) || acpi_timer_dev) return (ENXIO); if ((dev = BUS_ADD_CHILD(parent, parent, 0, "acpi_timer", 0)) == NULL) { device_printf(parent, "could not add acpi_timer0\n"); return (ENXIO); } acpi_timer_dev = dev; switch (AcpiGbl_FADT.XPmTimerBlock.SpaceId) { case ACPI_ADR_SPACE_SYSTEM_MEMORY: rtype = SYS_RES_MEMORY; break; case ACPI_ADR_SPACE_SYSTEM_IO: rtype = SYS_RES_IOPORT; break; default: return (ENXIO); } rid = 0; rlen = AcpiGbl_FADT.PmTimerLength; rstart = AcpiGbl_FADT.XPmTimerBlock.Address; if (bus_set_resource(dev, rtype, rid, rstart, rlen, -1)) { device_printf(dev, "couldn't set resource (%s 0x%lx+0x%lx)\n", (rtype == SYS_RES_IOPORT) ? "port" : "mem", rstart, rlen); return (ENXIO); } return (0); }
static int create_a_copy(device_t atkbdc, device_t me) { device_t psm; u_long irq; /* find the PS/2 mouse device instance under the keyboard controller */ psm = device_find_child(atkbdc, PSM_DRIVER_NAME, device_get_unit(atkbdc)); if (psm == NULL) return ENXIO; if (device_get_state(psm) != DS_NOTPRESENT) return 0; /* move our resource to the found device */ irq = bus_get_resource_start(me, SYS_RES_IRQ, 0); bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); /* ...then probe and attach it */ return device_probe_and_attach(psm); }
static int psmcpnp_attach(device_t dev) { device_t atkbdc; int rid; /* find the keyboard controller, which may be on acpi* or isa* bus */ atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME), device_get_unit(dev)); if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED)) { create_a_copy(atkbdc, dev); } else { /* * If we don't have the AT keyboard controller yet, * just reserve the IRQ for later use... * (See psmidentify() above.) */ rid = 0; bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE); } return 0; }
static int xenbus_probe_children(device_t dev) { device_t *kids; struct xenbus_device_ivars *ivars; int i, count; /* * Probe any new devices and register watches for any that * attach successfully. Since part of the protocol which * establishes a connection with the other end is interrupt * driven, we sleep until the device reaches a stable state * (closed or connected). */ if (device_get_children(dev, &kids, &count) == 0) { for (i = 0; i < count; i++) { if (device_get_state(kids[i]) != DS_NOTPRESENT) continue; if (device_probe_and_attach(kids[i])) continue; ivars = device_get_ivars(kids[i]); register_xenbus_watch( &ivars->xd_otherend_watch); sx_xlock(&ivars->xd_lock); while (ivars->xd_state != XenbusStateClosed && ivars->xd_state != XenbusStateConnected) sx_sleep(&ivars->xd_state, &ivars->xd_lock, 0, "xdattach", 0); sx_xunlock(&ivars->xd_lock); } free(kids, M_TEMP); } return (0); }
/* * Quiz the PnP BIOS, build a list of PNP IDs and resource data. */ static int pnpbios_identify(driver_t *driver, device_t parent) { struct PnPBIOS_table *pt = PnPBIOStable; struct bios_args args; struct pnp_sysdev *pd; struct pnp_sysdevargs *pda; uint16_t ndevs, bigdev; int error, currdev; uint8_t *devnodebuf, tag; uint32_t *devid, *compid; int idx, left; device_t dev; /* * Umm, we aren't going to rescan the PnP BIOS to look for new additions. */ if (device_get_state(parent) == DS_ATTACHED) return (0); /* no PnP BIOS information */ if (pt == NULL) return (ENXIO); /* ACPI already active */ if (devclass_get_softc(devclass_find("ACPI"), 0) != NULL) return (ENXIO); bzero(&args, sizeof(args)); args.seg.code16.base = BIOS_PADDRTOVADDR(pt->pmentrybase); args.seg.code16.limit = 0xffff; /* XXX ? */ args.seg.data.base = BIOS_PADDRTOVADDR(pt->pmdataseg); args.seg.data.limit = 0xffff; args.entry = pt->pmentryoffset; if ((error = bios16(&args, PNP_COUNT_DEVNODES, &ndevs, &bigdev)) || (args.r.eax & 0xff)) kprintf("pnpbios: error %d/%x getting device count/size limit\n", error, args.r.eax); ndevs &= 0xff; /* clear high byte garbage */ if (bootverbose) kprintf("pnpbios: %d devices, largest %d bytes\n", ndevs, bigdev); devnodebuf = kmalloc(bigdev + (sizeof(struct pnp_sysdevargs) - sizeof(struct pnp_sysdev)), M_DEVBUF, M_INTWAIT); pda = (struct pnp_sysdevargs *)devnodebuf; pd = &pda->node; for (currdev = 0, left = ndevs; (currdev != 0xff) && (left > 0); left--) { bzero(pd, bigdev); pda->next = currdev; /* get current configuration */ if ((error = bios16(&args, PNP_GET_DEVNODE, &pda->next, &pda->node, 1))) { kprintf("pnpbios: error %d making BIOS16 call\n", error); break; } if (bootverbose) kprintf("pnp_get_devnode cd=%d nxt=%d size=%d handle=%d devid=%08x type=%02x%02x%02x, attrib=%04x\n", currdev, pda->next, pd->size, pd->handle, pd->devid, pd->type[0], pd->type[1], pd->type[2], pd->attrib); if ((error = (args.r.eax & 0xff))) { if (bootverbose) kprintf("pnpbios: %s 0x%x fetching node %d\n", error & 0x80 ? "error" : "warning", error, currdev); if (error & 0x80) break; } currdev = pda->next; if (pd->size < sizeof(struct pnp_sysdev)) { kprintf("pnpbios: bogus system node data, aborting scan\n"); break; } /* * Ignore PICs so that we don't have to worry about the PICs * claiming IRQs to prevent their use. The PIC drivers * already ensure that invalid IRQs are not used. */ if (!strcmp(pnp_eisaformat(pd->devid), "PNP0000")) /* ISA PIC */ continue; if (!strcmp(pnp_eisaformat(pd->devid), "PNP0003")) /* APIC */ continue; /* Add the device and parse its resources */ dev = BUS_ADD_CHILD(parent, parent, ISA_ORDER_PNP, NULL, -1); isa_set_vendorid(dev, pd->devid); isa_set_logicalid(dev, pd->devid); /* * It appears that some PnP BIOS doesn't allow us to re-enable * the embedded system device once it is disabled. We shall * mark all system device nodes as "cannot be disabled", regardless * of actual settings in the device attribute byte. XXX */ #if 0 isa_set_configattr(dev, ((pd->attrib & PNPATTR_NODISABLE) ? 0 : ISACFGATTR_CANDISABLE) | ((!(pd->attrib & PNPATTR_NOCONFIG) && PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC) ? ISACFGATTR_DYNAMIC : 0)); #endif isa_set_configattr(dev, (!(pd->attrib & PNPATTR_NOCONFIG) && PNPATTR_CONFIG(pd->attrib) != PNPATTR_CONFIG_STATIC) ? ISACFGATTR_DYNAMIC : 0); ISA_SET_CONFIG_CALLBACK(parent, dev, pnpbios_set_config, 0); pnp_parse_resources(dev, &pd->devdata[0], pd->size - sizeof(struct pnp_sysdev), 0); if (!device_get_desc(dev)) device_set_desc_copy(dev, pnp_eisaformat(pd->devid)); /* Find device IDs */ devid = &pd->devid; compid = NULL; /* look for a compatible device ID too */ left = pd->size - sizeof(struct pnp_sysdev); idx = 0; while (idx < left) { tag = pd->devdata[idx++]; if (PNP_RES_TYPE(tag) == 0) { /* Small resource */ switch (PNP_SRES_NUM(tag)) { case PNP_TAG_COMPAT_DEVICE: compid = (uint32_t *)(pd->devdata + idx); if (bootverbose) kprintf("pnpbios: node %d compat ID 0x%08x\n", pd->handle, *compid); /* FALLTHROUGH */ case PNP_TAG_END: idx = left; break; default: idx += PNP_SRES_LEN(tag); break; } } else /* Large resource, skip it */ idx += *(uint16_t *)(pd->devdata + idx) + 2; } if (bootverbose) { kprintf("pnpbios: handle %d device ID %s (%08x)", pd->handle, pnp_eisaformat(*devid), *devid); if (compid != NULL) kprintf(" compat ID %s (%08x)", pnp_eisaformat(*compid), *compid); kprintf("\n"); } } return (0); }
/** * \brief Verify the existance of attached device instances and perform * probe/attach processing for newly arrived devices. * * \param dev The NewBus device representing this XenBus bus. * * \return On success, 0. Otherwise an errno value indicating the * type of failure. */ static int xenbusb_probe_children(device_t dev) { device_t *kids; struct xenbus_device_ivars *ivars; int i, count, error; if (device_get_children(dev, &kids, &count) == 0) { for (i = 0; i < count; i++) { if (device_get_state(kids[i]) != DS_NOTPRESENT) { /* * We already know about this one. * Make sure it's still here. */ xenbusb_verify_device(dev, kids[i]); continue; } error = device_probe_and_attach(kids[i]); if (error == ENXIO) { struct xenbusb_softc *xbs; /* * We don't have a PV driver for this device. * However, an emulated device we do support * may share this backend. Hide the node from * XenBus until the next rescan, but leave it's * state unchanged so we don't inadvertently * prevent attachment of any emulated device. */ xenbusb_delete_child(dev, kids[i]); /* * Since the XenStore state of this device * still indicates a pending attach, manually * release it's hold on the boot process. */ xbs = device_get_softc(dev); xenbusb_release_confighook(xbs); continue; } else if (error) { /* * Transition device to the closed state * so the world knows that attachment will * not occur. */ xenbus_set_state(kids[i], XenbusStateClosed); /* * Remove our record of this device. * So long as it remains in the closed * state in the XenStore, we will not find * it again. The state will only change * if the control domain actively reconfigures * this device. */ xenbusb_delete_child(dev, kids[i]); continue; } /* * Augment default newbus provided dynamic sysctl * variables with the standard ivar contents of * XenBus devices. */ xenbusb_device_sysctl_init(kids[i]); /* * Now that we have a driver managing this device * that can receive otherend state change events, * hook up a watch for them. */ ivars = device_get_ivars(kids[i]); xs_register_watch(&ivars->xd_otherend_watch); xs_register_watch(&ivars->xd_local_watch); } free(kids, M_TEMP); } return (0); }
static int orm_identify(driver_t* driver, device_t parent) { bus_space_handle_t bh; bus_space_tag_t bt; device_t child; u_int32_t chunk = IOMEM_START; struct resource *res; int rid; u_int32_t rom_size; struct orm_softc *sc; u_int8_t buf[3]; /* * rescanning the isa bus, do nothing */ if (device_get_state(parent) == DS_ATTACHED) return (0); /* * Otherwise see if it exists */ child = BUS_ADD_CHILD(parent, parent, ISA_ORDER_SENSITIVE, "orm", -1); device_set_driver(child, driver); isa_set_logicalid(child, ORM_ID); isa_set_vendorid(child, ORM_ID); sc = device_get_softc(child); sc->rnum = 0; while (chunk < IOMEM_END) { bus_set_resource(child, SYS_RES_MEMORY, sc->rnum, chunk, IOMEM_STEP, -1); rid = sc->rnum; res = bus_alloc_resource_any(child, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (res == NULL) { bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); chunk += IOMEM_STEP; continue; } bt = rman_get_bustag(res); bh = rman_get_bushandle(res); bus_space_read_region_1(bt, bh, 0, buf, sizeof(buf)); /* * We need to release and delete the resource since we're * changing its size, or the rom isn't there. There * is a checksum field in the ROM to prevent false * positives. However, some common hardware (IBM thinkpads) * neglects to put a valid checksum in the ROM, so we do * not double check the checksum here. On the ISA bus * areas that have no hardware read back as 0xff, so the * tests to see if we have 0x55 followed by 0xaa are * generally sufficient. */ bus_release_resource(child, SYS_RES_MEMORY, rid, res); bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); if (buf[0] != 0x55 || buf[1] != 0xAA || (buf[2] & 0x03) != 0) { chunk += IOMEM_STEP; continue; } rom_size = buf[2] << 9; bus_set_resource(child, SYS_RES_MEMORY, sc->rnum, chunk, rom_size, -1); rid = sc->rnum; res = bus_alloc_resource_any(child, SYS_RES_MEMORY, &rid, 0); if (res == NULL) { bus_delete_resource(child, SYS_RES_MEMORY, sc->rnum); chunk += IOMEM_STEP; continue; } sc->rid[sc->rnum] = rid; sc->res[sc->rnum] = res; sc->rnum++; chunk += rom_size; } /* * note: sc becomes invalid after we delete the child. */ if (sc->rnum == 0) { device_delete_child(parent, child); return (ENXIO); } if (sc->rnum == 1) device_set_desc(child, "ISA Option ROM"); else device_set_desc(child, "ISA Option ROMs"); return (0); }
static int xenbus_resume(device_t dev) { device_t *kids; struct xenbus_device_ivars *ivars; int i, count, error; char *statepath; xb_init_comms(); xs_resume(); /* * We must re-examine each device and find the new path for * its backend. */ if (device_get_children(dev, &kids, &count) == 0) { for (i = 0; i < count; i++) { if (device_get_state(kids[i]) == DS_NOTPRESENT) continue; ivars = device_get_ivars(kids[i]); unregister_xenbus_watch( &ivars->xd_otherend_watch); ivars->xd_state = XenbusStateInitialising; /* * Find the new backend details and * re-register our watch. */ free(ivars->xd_otherend_path, M_DEVBUF); error = xenbus_gather(XBT_NIL, ivars->xd_node, "backend-id", "%i", &ivars->xd_otherend_id, "backend", NULL, &ivars->xd_otherend_path, NULL); if (error) return (error); DEVICE_RESUME(kids[i]); statepath = malloc(strlen(ivars->xd_otherend_path) + strlen("/state") + 1, M_DEVBUF, M_WAITOK); sprintf(statepath, "%s/state", ivars->xd_otherend_path); free(ivars->xd_otherend_watch.node, M_DEVBUF); ivars->xd_otherend_watch.node = statepath; register_xenbus_watch( &ivars->xd_otherend_watch); #if 0 /* * Can't do this yet since we are running in * the xenwatch thread and if we sleep here, * we will stop delivering watch notifications * and the device will never come back online. */ sx_xlock(&ivars->xd_lock); while (ivars->xd_state != XenbusStateClosed && ivars->xd_state != XenbusStateConnected) sx_sleep(&ivars->xd_state, &ivars->xd_lock, 0, "xdresume", 0); sx_xunlock(&ivars->xd_lock); #endif } free(kids, M_TEMP); } return (0); }