static void cfi_disk_read(struct cfi_softc *sc, struct bio *bp) { long resid; KASSERT(sc->sc_width == 1 || sc->sc_width == 2 || sc->sc_width == 4, ("sc_width %d", sc->sc_width)); if (sc->sc_writing) { bp->bio_error = cfi_block_finish(sc); if (bp->bio_error) { bp->bio_flags |= BIO_ERROR; goto done; } } if (bp->bio_offset > sc->sc_size) { bp->bio_flags |= BIO_ERROR; bp->bio_error = EIO; goto done; } resid = bp->bio_bcount; if (sc->sc_width == 1) { uint8_t *dp = (uint8_t *)bp->bio_data; while (resid > 0 && bp->bio_offset < sc->sc_size) { *dp++ = cfi_read_raw(sc, bp->bio_offset); bp->bio_offset += 1, resid -= 1; } } else if (sc->sc_width == 2) { uint16_t *dp = (uint16_t *)bp->bio_data; while (resid > 0 && bp->bio_offset < sc->sc_size) { *dp++ = cfi_read_raw(sc, bp->bio_offset); bp->bio_offset += 2, resid -= 2; } } else { uint32_t *dp = (uint32_t *)bp->bio_data; while (resid > 0 && bp->bio_offset < sc->sc_size) { *dp++ = cfi_read_raw(sc, bp->bio_offset); bp->bio_offset += 4, resid -= 4; } } bp->bio_resid = resid; done: biodone(bp); }
/* * Begin writing into a new block/sector. We read the sector into * memory and keep updating that, until we move into another sector * or the process stops writing. At that time we write the whole * sector to flash (see cfi_block_finish). To avoid unneeded erase * cycles, keep a pristine copy of the sector on hand. */ int cfi_block_start(struct cfi_softc *sc, u_int ofs) { union { uint8_t *x8; uint16_t *x16; uint32_t *x32; } ptr; u_int rofs, rsz; uint32_t val; int r; rofs = 0; for (r = 0; r < sc->sc_regions; r++) { rsz = sc->sc_region[r].r_blocks * sc->sc_region[r].r_blksz; if (ofs < rofs + rsz) break; rofs += rsz; } if (r == sc->sc_regions) return (EFAULT); sc->sc_wrbufsz = sc->sc_region[r].r_blksz; sc->sc_wrbuf = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK); sc->sc_wrofs = ofs - (ofs - rofs) % sc->sc_wrbufsz; /* Read the block from flash for byte-serving. */ ptr.x8 = sc->sc_wrbuf; for (r = 0; r < sc->sc_wrbufsz; r += sc->sc_width) { val = cfi_read_raw(sc, sc->sc_wrofs + r); switch (sc->sc_width) { case 1: *(ptr.x8)++ = val; break; case 2: *(ptr.x16)++ = val; break; case 4: *(ptr.x32)++ = val; break; } } sc->sc_wrbufcpy = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK); memcpy(sc->sc_wrbufcpy, sc->sc_wrbuf, sc->sc_wrbufsz); sc->sc_writing = 1; return (0); }
static int cfi_devread(struct cdev *dev, struct uio *uio, int ioflag) { union { uint8_t x8[4]; uint16_t x16[2]; uint32_t x32[1]; } buf; struct cfi_softc *sc; u_int ofs; uint32_t val; int error; sc = dev->si_drv1; error = (sc->sc_writing) ? cfi_block_finish(sc) : 0; if (!error) error = (uio->uio_offset > sc->sc_size) ? EIO : 0; while (error == 0 && uio->uio_resid > 0 && uio->uio_offset < sc->sc_size) { ofs = uio->uio_offset; val = cfi_read_raw(sc, ofs); switch (sc->sc_width) { case 1: buf.x8[0] = val; break; case 2: buf.x16[0] = val; break; case 4: buf.x32[0] = val; break; } ofs &= sc->sc_width - 1; error = uiomove(buf.x8 + ofs, MIN(uio->uio_resid, sc->sc_width - ofs), uio); } return (error); }