/* * read from SONIC data buffer. */ void snc_nec16_copyfrombuf(struct snc_softc *sc, void *dst, u_int32_t offset, size_t size) { bus_space_tag_t memt = sc->sc_memt; bus_space_handle_t memh = sc->sc_memh; u_int16_t noffset; u_int8_t* bptr = dst; noffset = snc_nec16_select_bank(sc, offset, 0); /* XXX: should check if offset + size < 0x2000. */ bus_space_barrier(memt, memh, noffset, size, BUS_SPACE_BARRIER_READ); if (size > 3) { if (noffset & 3) { size_t asize = 4 - (noffset & 3); bus_space_read_region_1(memt, memh, noffset, bptr, asize); bptr += asize; noffset += asize; size -= asize; } bus_space_read_region_4(memt, memh, noffset, (u_int32_t *) bptr, size >> 2); bptr += size & ~3; noffset += size & ~3; size &= 3; } if (size) bus_space_read_region_1(memt, memh, noffset, bptr, size); }
static u_int8_t * podulebus_get_chunk(struct podulebus_attach_args *pa, int type) { int i; struct podulebus_chunk *pc; u_int8_t *chunk; for (i = 0; i < pa->pa_nchunks; i++) { pc = &pa->pa_chunks[i]; if (pc->pc_type == type) { chunk = malloc( pc->pc_length + 1, M_DEVBUF, M_WAITOK); #if NPODLOADER > 0 if (pc->pc_useloader) podloader_read_region(pa, pc->pc_offset, chunk, pc->pc_length); else #endif bus_space_read_region_1(pa->pa_sync_t, pa->pa_sync_h, pc->pc_offset, chunk, pc->pc_length); chunk[pc->pc_length] = 0; return chunk; } } return NULL; }
static void tels016_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = sc->sc_maps[1].t; bus_space_handle_t h = sc->sc_maps[1].h; bus_space_read_region_1(t, h, offset[what], buf, size); }
/*---------------------------------------------------------------------------* * Teles S0/16 fifo read routine *---------------------------------------------------------------------------*/ static void tels016_read_fifo(struct l1_softc *sc, int what, void *buf, size_t size) { bus_space_tag_t t = rman_get_bustag(sc->sc_resources.mem); bus_space_handle_t h = rman_get_bushandle(sc->sc_resources.mem); bus_space_read_region_1(t, h, offset[what], buf, size); }
int flashread(dev_t dev, struct uio *uio, int flag) { struct flash_softc *sc; bus_space_tag_t iot; bus_space_handle_t ioh; bus_size_t off; int total; int count; int error; sc = device_lookup_private(&athflash_cd, minor(dev)); iot = sc->sc_iot; ioh = sc->sc_ioh; off = uio->uio_offset; total = min(sc->sc_size - off, uio->uio_resid); while (total > 0) { count = min(sc->sc_sector_size, uio->uio_resid); bus_space_read_region_1(iot, ioh, off, sc->sc_buf, count); if ((error = uiomove(sc->sc_buf, count, uio)) != 0) return error; off += count; total -= count; } return 0; }
static void cfi_chip_query_1(struct cfi * const cfi) { uint8_t data[0x80]; bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data, __arraycount(data)); CFI_DUMP_QRY(0, data, sizeof(data), 1); CFI_QRY_UNPACK_COMMON(cfi, data, uint8_t); }
static void ie_copyin(struct ie_softc *sc, void *dst, int offset, size_t size) { if (size == 0) /* This *can* happen! */ return; #if 0 bus_space_read_region_1(sc->bt, sc->bh, offset, dst, size); #else /* A minor optimisation ;-) */ memcpy(dst, (void *) ((u_long) sc->bh + (u_long) offset), size); #endif }
static int cfi_0002_read_page(device_t self, flash_off_t offset, uint8_t *datap) { struct nor_softc * const sc = device_private(self); KASSERT(sc != NULL); KASSERT(sc->sc_nor_if != NULL); struct cfi *cfi = (struct cfi * const)sc->sc_nor_if->private; KASSERT(cfi != NULL); struct nor_chip * const chip = &sc->sc_chip; KASSERT(chip != NULL); KASSERT(chip->nc_page_mask != 0); KASSERT((offset & ~chip->nc_page_mask) == 0); KASSERT (chip->nc_page_size != 0); KASSERT((chip->nc_page_size & ((1 << cfi->cfi_portwidth) - 1)) == 0); CFI_0002_STATS_INC(cfi, read_page); bus_size_t count = chip->nc_page_size >> cfi->cfi_portwidth; /* #words/page */ int error = cfi_0002_busy_wait(cfi, offset, cfi_0002_time_dflt(cfi)); if (error != 0) return error; switch(cfi->cfi_portwidth) { case 0: bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, offset, (uint8_t *)datap, count); break; case 1: bus_space_read_region_2(cfi->cfi_bst, cfi->cfi_bsh, offset, (uint16_t *)datap, count); break; case 2: bus_space_read_region_4(cfi->cfi_bst, cfi->cfi_bsh, offset, (uint32_t *)datap, count); break; default: panic("%s: bad port width %d\n", __func__, cfi->cfi_portwidth); }; return 0; }
static void podulebus_read_chunks(struct podulebus_attach_args *pa, int useloader) { u_int8_t chunk[8]; u_int ptr, nchunks, type, length, offset; nchunks = pa->pa_nchunks; if (useloader) ptr = 0; else ptr = EXTECID_SIZE + IRQPTR_SIZE; for (;;) { #if NPODLOADER > 0 if (useloader) podloader_read_region(pa, ptr, chunk, 8); else #endif bus_space_read_region_1(pa->pa_sync_t, pa->pa_sync_h, ptr, chunk, 8); ptr += 8; type = chunk[0]; length = chunk[1] | chunk[2] << 8 | chunk[3] << 16; if (length == 0) break; offset = chunk[4] | chunk[5] << 8 | chunk[6] << 16 | chunk[7] << 24; if ((offset + length) > PODULE_GAP) continue; nchunks++; pa->pa_chunks = realloc(pa->pa_chunks, nchunks * sizeof(*pa->pa_chunks), M_DEVBUF, M_WAITOK); pa->pa_chunks[nchunks-1].pc_type = type; pa->pa_chunks[nchunks-1].pc_length = length; pa->pa_chunks[nchunks-1].pc_offset = offset; pa->pa_chunks[nchunks-1].pc_useloader = useloader; } pa->pa_nchunks = nchunks; }
static void cfi_jedec_id_1(struct cfi * const cfi) { struct cfi_jedec_id_data *idp = &cfi->cfi_id_data; uint8_t data[0x10]; bus_space_read_region_1(cfi->cfi_bst, cfi->cfi_bsh, 0, data, __arraycount(data)); CFI_DUMP_JEDEC(0, data, sizeof(data), 1); idp->id_mid = (uint16_t)data[0]; idp->id_did[0] = (uint16_t)data[1]; idp->id_did[1] = (uint16_t)data[0xe]; idp->id_did[2] = (uint16_t)data[0xf]; idp->id_prot_state = (uint16_t)data[2]; idp->id_indicators = (uint16_t)data[3]; /* software bits, upper and lower */ idp->id_swb_lo = data[0xc]; idp->id_swb_hi = data[0xd]; }
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"); }
static void podulebus_probe_podule(struct device *self, int slotnum) { struct podulebus_softc *sc = (struct podulebus_softc *)self; bus_space_tag_t id_bst; bus_space_handle_t id_bsh; int ecid, w; u_int8_t extecid[EXTECID_SIZE]; struct podulebus_attach_args pa; bzero(&pa, sizeof(pa)); id_bst = sc->sc_ioc.ioc_sync_t; bus_space_subregion(id_bst, sc->sc_ioc.ioc_sync_h, slotnum * PODULE_GAP, PODULE_GAP, &id_bsh); ecid = bus_space_read_1(id_bst, id_bsh, 0); /* Skip empty or strange slots */ if (ecid & (ECID_NOTPRESENT | ECID_NONCONF)) return; if ((ecid & ECID_ID_MASK) == ECID_ID_EXTEND) { pa.pa_fast_t = sc->sc_ioc.ioc_fast_t; bus_space_subregion(pa.pa_fast_t, sc->sc_ioc.ioc_fast_h, slotnum * PODULE_GAP, PODULE_GAP, &pa.pa_fast_h); pa.pa_medium_t = sc->sc_ioc.ioc_medium_t; bus_space_subregion(pa.pa_medium_t, sc->sc_ioc.ioc_medium_h, slotnum * PODULE_GAP, PODULE_GAP, &pa.pa_medium_h); pa.pa_slow_t = sc->sc_ioc.ioc_slow_t; bus_space_subregion(pa.pa_slow_t, sc->sc_ioc.ioc_slow_h, slotnum * PODULE_GAP, PODULE_GAP, &pa.pa_slow_h); pa.pa_sync_t = sc->sc_ioc.ioc_sync_t; bus_space_subregion(pa.pa_sync_t, sc->sc_ioc.ioc_sync_h, slotnum * PODULE_GAP, PODULE_GAP, &pa.pa_sync_h); /* XXX This is a hack! */ pa.pa_mod_t = &iobus_bs_tag; bus_space_map(pa.pa_mod_t, (bus_addr_t)MEMC_IO_BASE + slotnum * (PODULE_GAP << 2), (PODULE_GAP << 2), 0, &pa.pa_mod_h); bus_space_read_region_1(id_bst, id_bsh, 0, extecid, EXTECID_SIZE); /* XXX If you thought that was a hack... */ pa.pa_mod_base = pa.pa_mod_h; pa.pa_fast_base = pa.pa_fast_h; pa.pa_medium_base = pa.pa_medium_h; pa.pa_slow_base = pa.pa_slow_h; pa.pa_sync_base = pa.pa_sync_h; pa.pa_ecid = ecid; pa.pa_flags1 = extecid[EXTECID_F1]; pa.pa_manufacturer = (extecid[EXTECID_MLO] | extecid[EXTECID_MHI] << 8); pa.pa_product = (extecid[EXTECID_PLO] | extecid[EXTECID_PHI] << 8); pa.pa_slotnum = slotnum; pa.pa_ih = slotnum; if (pa.pa_flags1 & EXTECID_F1_CD) { w = pa.pa_flags1 & EXTECID_F1_W_MASK; if (w != EXTECID_F1_W_8BIT) { /* RISC OS 3 can't handle this either. */ printf("%s:%d: ROM is not 8 bits wide; " "ignoring it\n", self->dv_xname, pa.pa_slotnum); } else { podulebus_read_chunks(&pa, 0); pa.pa_descr = podulebus_get_chunk(&pa, CHUNK_DEV_DESCR); } } pa.pa_slotflags = 0; config_found_sm_loc(self, "podulebus", NULL, &pa, podulebus_print, podulebus_submatch); if (pa.pa_chunks) FREE(pa.pa_chunks, M_DEVBUF); if (pa.pa_descr) FREE(pa.pa_descr, M_DEVBUF); if (pa.pa_loader) FREE(pa.pa_loader, M_DEVBUF); } else printf("%s:%d: non-extended podule ignored.\n", self->dv_xname, slotnum); }
int gprioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) { int unit = GPRUNIT(dev); struct gpr_softc *sc = gpr_cd.cd_devs[unit]; int error; DPRINTF(("%s: cmd %d, flags 0x%x\n", __func__, cmd, flags)); switch (cmd) { case GPR_RESET: case GPR_SELECT: case GPR_POWER: case GPR_CLOSE: if ((flags & FWRITE) == 0) return (EACCES); default: break; } switch (cmd) { case GPR_RESET: /* * To reset and power up the reader, set bit 0 in the * HAP register for at least 5us and wait for 20ms. */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL, GPR400_RESET); delay(10); bus_space_write_1(sc->sc_iot, sc->sc_ioh, GPR400_HAP_CTRL, 0); tsleep(sc, PWAIT, "gpreset", hz / 40); /* FALLTHROUGH */ case GPR_SELECT: error = tlvput(sc, GPR400_SELECT, "\x02", 1); break; case GPR_POWER: { u_int8_t *mode; if (*(int *)addr) mode = "\x01"; /* Standby */ else mode = "\x00"; /* Power down */ error = tlvput(sc, GPR400_POWER, mode, 1); } break; case GPR_CLOSE: error = tlvput(sc, GPR400_CLOSE, (u_int8_t *)0, 0); break; case GPR_RAM: { struct gpr400_ram r; bus_space_read_region_1(sc->sc_memt, sc->sc_memh, sc->sc_offset, (u_int8_t *)&r, sizeof(struct gpr400_ram)); error = copyout(&r, addr, sizeof(struct gpr400_ram)); } break; case GPR_CMD: case GPR_OPEN: case GPR_STATUS: case GPR_TLV: default: error = EINVAL; break; }; return (error); }
void bmdstrategy(struct buf *bp) { int unit = BMD_UNIT(bp->b_dev); struct bmd_softc *sc; int offset, disksize, resid; int page, pg_offset, pg_resid; void *data; if (unit >= bmd_cd.cd_ndevs) { bp->b_error = ENXIO; goto done; } sc = device_lookup_private(&bmd_cd, BMD_UNIT(bp->b_dev)); if (sc == NULL) { bp->b_error = ENXIO; goto done; } DPRINTF(("bmdstrategy: %s blkno %d bcount %ld:", (bp->b_flags & B_READ) ? "read " : "write", bp->b_blkno, bp->b_bcount)); bp->b_resid = bp->b_bcount; offset = (bp->b_blkno << DEV_BSHIFT); disksize = sc->sc_maxpage * BMD_PAGESIZE; if (offset >= disksize) { /* EOF if read, EIO if write */ if (bp->b_flags & B_READ) goto done; bp->b_error = EIO; goto done; } resid = bp->b_resid; if (resid > disksize - offset) resid = disksize - offset; data = bp->b_data; do { page = offset / BMD_PAGESIZE; pg_offset = offset % BMD_PAGESIZE; /* length */ pg_resid = MIN(resid, BMD_PAGESIZE - pg_offset); /* switch bank page */ bus_space_write_1(sc->sc_iot, sc->sc_ioh, BMD_PAGE, page); /* XXX we should use DMA transfer? */ if ((bp->b_flags & B_READ)) { bus_space_read_region_1(sc->sc_iot, sc->sc_bank, pg_offset, data, pg_resid); } else { bus_space_write_region_1(sc->sc_iot, sc->sc_bank, pg_offset, data, pg_resid); } data = (char *)data + pg_resid; offset += pg_resid; resid -= pg_resid; bp->b_resid -= pg_resid; } while (resid > 0); DPRINTF(("\n")); done: biodone(bp); }
int gem_pci_enaddr(struct gem_softc *sc, struct pci_attach_args *pa) { struct pci_vpd *vpd; bus_space_handle_t romh; bus_space_tag_t romt; bus_size_t romsize = 0; u_int8_t buf[32]; pcireg_t address; int dataoff, vpdoff; int rv = -1; if (pci_mapreg_map(pa, PCI_ROM_REG, PCI_MAPREG_TYPE_MEM, 0, &romt, &romh, 0, &romsize, 0)) return (-1); address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); if (bcmp(buf, gem_promhdr, sizeof(gem_promhdr))) goto fail; dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8); if (dataoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); if (bcmp(buf, gem_promdat, sizeof(gem_promdat)) || bcmp(buf + PROMDATA_DATA2, gem_promdat2, sizeof(gem_promdat2))) goto fail; vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8); if (vpdoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); /* * The VPD of gem is not in PCI 2.2 standard format. The length * in the resource header is in big endian. */ vpd = (struct pci_vpd *)(buf + 3); if (!PCI_VPDRES_ISLARGE(buf[0]) || PCI_VPDRES_LARGE_NAME(buf[0]) != PCI_VPDRES_TYPE_VPD) goto fail; if (vpd->vpd_key0 != 'N' || vpd->vpd_key1 != 'A') goto fail; bcopy(buf + 6, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); rv = 0; fail: if (romsize != 0) bus_space_unmap(romt, romh, romsize); address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address &= ~PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); return (rv); }
void aspattach(struct device *parent, struct device *self, void *aux) { struct confargs *ca = aux; struct asp_softc *sc = (struct asp_softc *)self; struct gsc_attach_args ga; bus_space_handle_t ioh; uint32_t irr; int s; /* * Map the ASP interrupt registers. */ if (bus_space_map(ca->ca_iot, ca->ca_hpa + ASP_REG_INT, sizeof(struct asp_trs), 0, &ioh)) panic("aspattach: can't map interrupt registers."); sc->sc_trs = (struct asp_trs *)ioh; /* * Map the ASP miscellaneous registers. */ if (bus_space_map(ca->ca_iot, ca->ca_hpa + ASP_REG_MISC, sizeof(struct asp_hwr), 0, &ioh)) panic("aspattach: can't map miscellaneous registers."); sc->sc_hw = (struct asp_hwr *)ioh; /* * Map the Ethernet address and read it out. */ if (bus_space_map(ca->ca_iot, ca->ca_hpa + ASP_ETHER_ADDR, sizeof(ga.ga_ether_address), 0, &ioh)) panic("aspattach: can't map EEPROM."); bus_space_read_region_1(ca->ca_iot, ioh, 0, ga.ga_ether_address, sizeof(ga.ga_ether_address)); bus_space_unmap(ca->ca_iot, ioh, sizeof(ga.ga_ether_address)); machine_ledaddr = &sc->sc_trs->asp_cled; machine_ledword = asp_spus[sc->sc_trs->asp_spu].ledword; /* reset ASP */ /* sc->sc_hw->asp_reset = 1; */ /* delay(400000); */ s = splhigh(); viper_setintrwnd(1 << ca->ca_irq); sc->sc_trs->asp_imr = ~0; irr = sc->sc_trs->asp_irr; sc->sc_trs->asp_imr = 0; splx(s); printf (": %s rev %d, lan %d scsi %d\n", asp_spus[sc->sc_trs->asp_spu].name, sc->sc_hw->asp_version, sc->sc_trs->asp_lan, sc->sc_trs->asp_scsi); /* Establish the interrupt register. */ hp700_intr_reg_establish(&sc->sc_int_reg); sc->sc_int_reg.int_reg_mask = &sc->sc_trs->asp_imr; sc->sc_int_reg.int_reg_req = &sc->sc_trs->asp_irr; /* Attach the GSC bus. */ ga.ga_ca = *ca; /* clone from us */ ga.ga_name = "gsc"; ga.ga_int_reg = &sc->sc_int_reg; ga.ga_fix_args = asp_fix_args; ga.ga_fix_args_cookie = sc; ga.ga_scsi_target = sc->sc_trs->asp_scsi; config_found(self, &ga, gscprint); }
/* * Bus read region operations. */ void bs_through_bs_rr_1(bus_space_tag_t t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t *addr, bus_size_t count) { bus_space_read_region_1(t->bs_base, bsh, offset, addr, count); }
/* * Given a NIC memory source address and a host memory destination * address, copy 'amount' from NIC to host using shared memory. * This routine accesses things as 8 bit quantities. */ void ed_shmem_readmem8(struct ed_softc *sc, bus_size_t src, uint8_t *dst, uint16_t amount) { bus_space_read_region_1(sc->mem_bst, sc->mem_bsh, src, dst, amount); }
int cas_pci_enaddr(struct cas_softc *sc, struct pci_attach_args *pa) { struct pci_vpd_largeres *res; struct pci_vpd *vpd; bus_space_handle_t romh; bus_space_tag_t romt; bus_size_t romsize; u_int8_t buf[32], *desc; pcireg_t address, mask; int dataoff, vpdoff, len; int rv = -1; address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, 0xfffffffe); mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address |= PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); romt = pa->pa_memt; romsize = PCI_ROM_SIZE(mask); if (bus_space_map(romt, PCI_ROM_ADDR(address), romsize, 0, &romh)) { romsize = 0; goto fail; } bus_space_read_region_1(romt, romh, 0, buf, sizeof(buf)); if (bcmp(buf, cas_promhdr, sizeof(cas_promhdr))) goto fail; dataoff = buf[PROMHDR_PTR_DATA] | (buf[PROMHDR_PTR_DATA + 1] << 8); if (dataoff < 0x1c) goto fail; bus_space_read_region_1(romt, romh, dataoff, buf, sizeof(buf)); if (bcmp(buf, cas_promdat, sizeof(cas_promdat)) || bcmp(buf + PROMDATA_DATA2, cas_promdat2, sizeof(cas_promdat2))) goto fail; vpdoff = buf[PROMDATA_PTR_VPD] | (buf[PROMDATA_PTR_VPD + 1] << 8); if (vpdoff < 0x1c) goto fail; next: bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); if (!PCI_VPDRES_ISLARGE(buf[0])) goto fail; res = (struct pci_vpd_largeres *)buf; vpdoff += sizeof(*res); len = ((res->vpdres_len_msb << 8) + res->vpdres_len_lsb); switch(PCI_VPDRES_LARGE_NAME(res->vpdres_byte0)) { case PCI_VPDRES_TYPE_IDENTIFIER_STRING: /* Skip identifier string. */ vpdoff += len; goto next; case PCI_VPDRES_TYPE_VPD: while (len > 0) { bus_space_read_region_1(romt, romh, vpdoff, buf, sizeof(buf)); vpd = (struct pci_vpd *)buf; vpdoff += sizeof(*vpd) + vpd->vpd_len; len -= sizeof(*vpd) + vpd->vpd_len; /* * We're looking for an "Enhanced" VPD... */ if (vpd->vpd_key0 != 'Z') continue; desc = buf + sizeof(*vpd); /* * ...which is an instance property... */ if (desc[0] != 'I') continue; desc += 3; /* * ...that's a byte array with the proper * length for a MAC address... */ if (desc[0] != 'B' || desc[1] != ETHER_ADDR_LEN) continue; desc += 2; /* * ...named "local-mac-address". */ if (strcmp(desc, "local-mac-address") != 0) continue; desc += strlen("local-mac-address") + 1; bcopy(desc, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); rv = 0; } break; default: goto fail; } fail: if (romsize != 0) bus_space_unmap(romt, romh, romsize); address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG); address &= ~PCI_ROM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address); return (rv); }
int hme_pci_attach(device_t dev) { struct hme_pci_softc *hsc; struct hme_softc *sc; bus_space_tag_t memt; bus_space_handle_t memh; int i, error = 0; #if !(defined(__powerpc__) || defined(__sparc64__)) device_t *children, ebus_dev; struct resource *ebus_rres; int j, slot; #endif pci_enable_busmaster(dev); /* * Some Sun HMEs do have their intpin register bogusly set to 0, * although it should be 1. Correct that. */ if (pci_get_intpin(dev) == 0) pci_set_intpin(dev, 1); hsc = device_get_softc(dev); sc = &hsc->hsc_hme; sc->sc_dev = dev; sc->sc_flags |= HME_PCI; mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); /* * Map five register banks: * * bank 0: HME SEB registers: +0x0000 * bank 1: HME ETX registers: +0x2000 * bank 2: HME ERX registers: +0x4000 * bank 3: HME MAC registers: +0x6000 * bank 4: HME MIF registers: +0x7000 * */ i = PCIR_BAR(0); hsc->hsc_sres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, RF_ACTIVE); if (hsc->hsc_sres == NULL) { device_printf(dev, "could not map device registers\n"); error = ENXIO; goto fail_mtx; } i = 0; hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_SHAREABLE | RF_ACTIVE); if (hsc->hsc_ires == NULL) { device_printf(dev, "could not allocate interrupt\n"); error = ENXIO; goto fail_sres; } memt = rman_get_bustag(hsc->hsc_sres); memh = rman_get_bushandle(hsc->hsc_sres); sc->sc_sebt = sc->sc_etxt = sc->sc_erxt = sc->sc_mact = sc->sc_mift = memt; bus_space_subregion(memt, memh, 0x0000, 0x1000, &sc->sc_sebh); bus_space_subregion(memt, memh, 0x2000, 0x1000, &sc->sc_etxh); bus_space_subregion(memt, memh, 0x4000, 0x1000, &sc->sc_erxh); bus_space_subregion(memt, memh, 0x6000, 0x1000, &sc->sc_mach); bus_space_subregion(memt, memh, 0x7000, 0x1000, &sc->sc_mifh); #if defined(__powerpc__) || defined(__sparc64__) OF_getetheraddr(dev, sc->sc_enaddr); #else /* * Dig out VPD (vital product data) and read NA (network address). * * The PCI HME is a PCIO chip, which is composed of two functions: * function 0: PCI-EBus2 bridge, and * function 1: HappyMeal Ethernet controller. * * The VPD of HME resides in the Boot PROM (PCI FCode) attached * to the EBus bridge and can't be accessed via the PCI capability * pointer. * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) * chapter 2 describes the data structure. * * We don't have a MI EBus driver since no EBus device exists * (besides the FCode PROM) on add-on HME boards. The ``no driver * attached'' message for function 0 therefore is what is expected. */ #define PCI_ROMHDR_SIZE 0x1c #define PCI_ROMHDR_SIG 0x00 #define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */ #define PCI_ROMHDR_PTR_DATA 0x18 #define PCI_ROM_SIZE 0x18 #define PCI_ROM_SIG 0x00 #define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */ /* reversed */ #define PCI_ROM_VENDOR 0x04 #define PCI_ROM_DEVICE 0x06 #define PCI_ROM_PTR_VPD 0x08 #define PCI_VPDRES_BYTE0 0x00 #define PCI_VPDRES_ISLARGE(x) ((x) & 0x80) #define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f) #define PCI_VPDRES_TYPE_VPD 0x10 /* large */ #define PCI_VPDRES_LARGE_LEN_LSB 0x01 #define PCI_VPDRES_LARGE_LEN_MSB 0x02 #define PCI_VPDRES_LARGE_DATA 0x03 #define PCI_VPD_SIZE 0x03 #define PCI_VPD_KEY0 0x00 #define PCI_VPD_KEY1 0x01 #define PCI_VPD_LEN 0x02 #define PCI_VPD_DATA 0x03 #define HME_ROM_READ_N(n, offs) bus_space_read_ ## n (memt, memh, (offs)) #define HME_ROM_READ_1(offs) HME_ROM_READ_N(1, (offs)) #define HME_ROM_READ_2(offs) HME_ROM_READ_N(2, (offs)) #define HME_ROM_READ_4(offs) HME_ROM_READ_N(4, (offs)) /* Search accompanying EBus bridge. */ slot = pci_get_slot(dev); if (device_get_children(device_get_parent(dev), &children, &i) != 0) { device_printf(dev, "could not get children\n"); error = ENXIO; goto fail_sres; } ebus_dev = NULL; for (j = 0; j < i; j++) { if (pci_get_class(children[j]) == PCIC_BRIDGE && pci_get_vendor(children[j]) == PCI_VENDOR_SUN && pci_get_device(children[j]) == PCI_PRODUCT_SUN_EBUS && pci_get_slot(children[j]) == slot) { ebus_dev = children[j]; break; } } if (ebus_dev == NULL) { device_printf(dev, "could not find EBus bridge\n"); error = ENXIO; goto fail_children; } /* Map EBus bridge PROM registers. */ i = PCIR_BAR(0); if ((ebus_rres = bus_alloc_resource_any(ebus_dev, SYS_RES_MEMORY, &i, RF_ACTIVE)) == NULL) { device_printf(dev, "could not map PROM registers\n"); error = ENXIO; goto fail_children; } memt = rman_get_bustag(ebus_rres); memh = rman_get_bushandle(ebus_rres); /* Read PCI Expansion ROM header. */ if (HME_ROM_READ_2(PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC || (i = HME_ROM_READ_2(PCI_ROMHDR_PTR_DATA)) < PCI_ROMHDR_SIZE) { device_printf(dev, "unexpected PCI Expansion ROM header\n"); error = ENXIO; goto fail_rres; } /* Read PCI Expansion ROM data. */ if (HME_ROM_READ_4(i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC || HME_ROM_READ_2(i + PCI_ROM_VENDOR) != pci_get_vendor(dev) || HME_ROM_READ_2(i + PCI_ROM_DEVICE) != pci_get_device(dev) || (j = HME_ROM_READ_2(i + PCI_ROM_PTR_VPD)) < i + PCI_ROM_SIZE) { device_printf(dev, "unexpected PCI Expansion ROM data\n"); error = ENXIO; goto fail_rres; } /* * Read PCI VPD. * SUNW,hme cards have a single large resource VPD-R tag * containing one NA. SUNW,qfe cards have four large resource * VPD-R tags containing one NA each (all four HME chips share * the same PROM). * The VPD used on both cards is not in PCI 2.2 standard format * however. The length in the resource header is in big endian * and the end tag is non-standard (0x79) and followed by an * all-zero "checksum" byte. Sun calls this a "Fresh Choice * Ethernet" VPD... */ /* Look at the end tag to determine whether this is a VPD with 4 NAs. */ if (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + ETHER_ADDR_LEN) != 0x79 && HME_ROM_READ_1(j + 4 * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + ETHER_ADDR_LEN)) == 0x79) /* Use the Nth NA for the Nth HME on this SUNW,qfe. */ j += slot * (PCI_VPDRES_LARGE_DATA + PCI_VPD_SIZE + ETHER_ADDR_LEN); if (PCI_VPDRES_ISLARGE(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) == 0 || PCI_VPDRES_LARGE_NAME(HME_ROM_READ_1(j + PCI_VPDRES_BYTE0)) != PCI_VPDRES_TYPE_VPD || (HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_LSB) << 8 | HME_ROM_READ_1(j + PCI_VPDRES_LARGE_LEN_MSB)) != PCI_VPD_SIZE + ETHER_ADDR_LEN || HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY0) != 0x4e /* N */ || HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_KEY1) != 0x41 /* A */ || HME_ROM_READ_1(j + PCI_VPDRES_LARGE_DATA + PCI_VPD_LEN) != ETHER_ADDR_LEN) { device_printf(dev, "unexpected PCI VPD\n"); error = ENXIO; goto fail_rres; } bus_space_read_region_1(memt, memh, j + PCI_VPDRES_LARGE_DATA + PCI_VPD_DATA, sc->sc_enaddr, ETHER_ADDR_LEN); fail_rres: bus_release_resource(ebus_dev, SYS_RES_MEMORY, rman_get_rid(ebus_rres), ebus_rres); fail_children: free(children, M_TEMP); if (error != 0) goto fail_sres; #endif sc->sc_burst = 64; /* XXX */ /* * call the main configure */ if ((error = hme_config(sc)) != 0) { device_printf(dev, "could not be configured\n"); goto fail_ires; } if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET | INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) { device_printf(dev, "couldn't establish interrupt\n"); hme_detach(sc); goto fail_ires; } return (0); fail_ires: bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(hsc->hsc_ires), hsc->hsc_ires); fail_sres: bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(hsc->hsc_sres), hsc->hsc_sres); fail_mtx: mtx_destroy(&sc->sc_lock); return (error); }