static void atpic_isa_identify(driver_t *drv, device_t parent) { device_t child; child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, drv->name, -1); device_set_driver(child, drv); isa_set_logicalid(child, atpic_ids[0].ip_id); isa_set_vendorid(child, atpic_ids[0].ip_id); bus_set_resource(child, SYS_RES_IOPORT, ATPIC_MASTER, IO_ICU1, 2); bus_set_resource(child, SYS_RES_IOPORT, ATPIC_SLAVE, IO_ICU2, 2); /* ISA interrupts are routed through external interrupt 0. */ bus_set_resource(child, SYS_RES_IRQ, 0, PIC_IRQ_EXT(0), 1); }
static void es1888_identify(driver_t *driver, device_t parent) { /* * Only use this on alpha since PNPBIOS is a better solution on x86. */ #ifdef __alpha__ u_int32_t lo, hi; device_t dev; es1888_set_port(0x220); if (es1888_reset(0x220)) return; /* * Check identification bytes for es1888. */ if (es1888_dspwr(0x220, 0xe7)) return; hi = es1888_get_byte(0x220); lo = es1888_get_byte(0x220); if (hi != 0x68 || (lo & 0xf0) != 0x80) return; /* * Program irq and drq. */ if (es1888_dspwr(0x220, 0xc6) /* enter extended mode */ || es1888_dspwr(0x220, 0xb1) /* write register b1 */ || es1888_dspwr(0x220, 0x14) /* enable irq 5 */ || es1888_dspwr(0x220, 0xb2) /* write register b1 */ || es1888_dspwr(0x220, 0x18)) /* enable drq 1 */ return; /* * Create the device and program its resources. */ dev = BUS_ADD_CHILD(parent, ISA_ORDER_PNP, NULL, -1); bus_set_resource(dev, SYS_RES_IOPORT, 0, 0x220, 0x10); bus_set_resource(dev, SYS_RES_IRQ, 0, 5, 1); bus_set_resource(dev, SYS_RES_DRQ, 0, 1, 1); isa_set_vendorid(dev, PNP_EISAID("ESS1888")); isa_set_logicalid(dev, PNP_EISAID("ESS1888")); #endif }
static void isa_setup_children(device_t dev, phandle_t parent) { struct isa_regs *regs; struct resource_list *rl; device_t cdev; u_int64_t end, start; ofw_isa_intr_t *intrs, rintr; phandle_t node; uint32_t *drqs, *regidx; int i, ndrq, nintr, nreg, nregidx, rid, rtype; char *name; /* * Loop through children and fake up PnP devices for them. * Their resources are added as fully mapped and specified because * adjusting the resources and the resource list entries respectively * in isa_alloc_resource() causes trouble with drivers which use * rman_get_start(), pass-through or allocate and release resources * multiple times, etc. Adjusting the resources might be better off * in a bus_activate_resource method but the common ISA code doesn't * allow for an isa_activate_resource(). */ for (node = OF_child(parent); node != 0; node = OF_peer(node)) { if ((OF_getprop_alloc(node, "name", 1, (void **)&name)) == -1) continue; /* * Keyboard and mouse controllers hang off of the `8042' * node but we have no real use for the `8042' itself. */ if (strcmp(name, "8042") == 0) { isa_setup_children(dev, node); free(name, M_OFWPROP); continue; } for (i = 0; ofw_isa_pnp_map[i].name != NULL; i++) if (strcmp(ofw_isa_pnp_map[i].name, name) == 0) break; if (ofw_isa_pnp_map[i].name == NULL) { device_printf(dev, "no PnP map entry for node " "0x%lx: %s\n", (unsigned long)node, name); free(name, M_OFWPROP); continue; } if ((cdev = BUS_ADD_CHILD(dev, ISA_ORDER_PNPBIOS, NULL, -1)) == NULL) panic("isa_setup_children: BUS_ADD_CHILD failed"); isa_set_logicalid(cdev, ofw_isa_pnp_map[i].id); isa_set_vendorid(cdev, ofw_isa_pnp_map[i].id); rl = BUS_GET_RESOURCE_LIST(dev, cdev); nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)®s); for (i = 0; i < nreg; i++) { start = ISA_REG_PHYS(®s[i]); end = start + regs[i].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } if (nreg == -1 && parent != isab_node) { /* * The "reg" property still might be an index into * the set of registers of the parent device like * with the nodes hanging off of the `8042' node. */ nregidx = OF_getprop_alloc(node, "reg", sizeof(*regidx), (void **)®idx); if (nregidx > 2) panic("isa_setup_children: impossible number " "of register indices"); if (nregidx != -1 && (nreg = OF_getprop_alloc(parent, "reg", sizeof(*regs), (void **)®s)) >= nregidx) { for (i = 0; i < nregidx; i++) { start = ISA_REG_PHYS(®s[regidx[i]]); end = start + regs[regidx[i]].size - 1; rtype = ofw_isa_range_map(isab_ranges, isab_nrange, &start, &end, NULL); rid = 0; while (resource_list_find(rl, rtype, rid) != NULL) rid++; bus_set_resource(cdev, rtype, rid, start, end - start + 1); } } if (regidx != NULL) free(regidx, M_OFWPROP); } if (regs != NULL) free(regs, M_OFWPROP); nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), (void **)&intrs); for (i = 0; i < nintr; i++) { if (intrs[i] > 7) panic("isa_setup_children: intr too large"); rintr = ofw_isa_route_intr(device_get_parent(dev), node, &isa_iinfo, intrs[i]); if (rintr == PCI_INVALID_IRQ) { device_printf(dev, "could not map ISA " "interrupt %d for node 0x%lx: %s\n", intrs[i], (unsigned long)node, name); continue; } bus_set_resource(cdev, SYS_RES_IRQ, i, rintr, 1); } if (intrs != NULL) free(intrs, M_OFWPROP); ndrq = OF_getprop_alloc(node, "dma-channel", sizeof(*drqs), (void **)&drqs); for (i = 0; i < ndrq; i++) bus_set_resource(cdev, SYS_RES_DRQ, i, drqs[i], 1); if (drqs != NULL) free(drqs, M_OFWPROP); /* * Devices using DMA hang off of the `dma' node instead of * directly from the ISA bridge node. */ if (strcmp(name, "dma") == 0) isa_setup_children(dev, node); free(name, M_OFWPROP); } }
static void 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]; child = BUS_ADD_CHILD(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); 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); 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; } if (sc->rnum == 0) device_delete_child(parent, child); else if (sc->rnum == 1) device_set_desc(child, "ISA Option ROM"); else device_set_desc(child, "ISA Option ROMs"); }
/* * 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); }