static int nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) { struct chip_geom *cg; device_t nandbus; int start_page, count, off, err = 0; uint8_t *ptr, *tmp; nand_debug(NDBG_CDEV, "Read from chip%d [%p] at %d\n", chip->num, chip, offset); nandbus = device_get_parent(chip->dev); NANDBUS_LOCK(nandbus); NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); cg = &chip->chip_geom; start_page = offset_to_page(cg, offset); off = offset_to_page_off(cg, offset); count = (len > cg->page_size - off) ? cg->page_size - off : len; ptr = (uint8_t *)buf; while (len > 0) { if (len < cg->page_size) { tmp = malloc(cg->page_size, M_NAND, M_WAITOK); if (!tmp) { err = ENOMEM; break; } err = NAND_READ_PAGE(chip->dev, start_page, tmp, cg->page_size, 0); if (err) { free(tmp, M_NAND); break; } bcopy(tmp + off, ptr, count); free(tmp, M_NAND); } else { err = NAND_READ_PAGE(chip->dev, start_page, ptr, cg->page_size, 0); if (err) break; } len -= count; start_page++; ptr += count; count = (len > cg->page_size) ? cg->page_size : len; off = 0; } NANDBUS_UNLOCK(nandbus); return (err); }
static int nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) { struct chip_geom *cg; device_t nandbus; int off, start_page, err = 0; uint8_t *ptr; nand_debug(NDBG_CDEV, "Write to chip %d [%p] at %d\n", chip->num, chip, offset); nandbus = device_get_parent(chip->dev); NANDBUS_LOCK(nandbus); NANDBUS_SELECT_CS(device_get_parent(chip->dev), chip->num); cg = &chip->chip_geom; start_page = offset_to_page(cg, offset); off = offset_to_page_off(cg, offset); if (off != 0 || (len % cg->page_size) != 0) { printf("Not aligned write start [0x%08x] size [0x%08x]\n", off, len); NANDBUS_UNLOCK(nandbus); return (EINVAL); } ptr = (uint8_t *)buf; while (len > 0) { err = NAND_PROGRAM_PAGE(chip->dev, start_page, ptr, cg->page_size, 0); if (err) break; len -= cg->page_size; start_page++; ptr += cg->page_size; } NANDBUS_UNLOCK(nandbus); return (err); }
static int nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, struct thread *td) { struct nand_chip *chip; struct chip_geom *cg; struct nand_oob_rw *oob_rw = NULL; struct nand_raw_rw *raw_rw = NULL; device_t nandbus; size_t bufsize = 0, len = 0; size_t raw_size; off_t off; uint8_t *buf = NULL; int ret = 0; uint8_t status; chip = (struct nand_chip *)ndisk->d_drv1; cg = &chip->chip_geom; nandbus = device_get_parent(chip->dev); if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { raw_rw = (struct nand_raw_rw *)data; raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); /* Check if len is not bigger than chip size */ if (raw_rw->len > raw_size) return (EFBIG); /* * Do not ask for too much memory, in case of large transfers * read/write in 16-pages chunks */ bufsize = 16 * (cg->page_size + cg->oob_size); if (raw_rw->len < bufsize) bufsize = raw_rw->len; buf = malloc(bufsize, M_NAND, M_WAITOK); len = raw_rw->len; off = 0; } switch (cmd) { case NAND_IO_ERASE: ret = nand_erase_blocks(chip, ((off_t *)data)[0], ((off_t *)data)[1]); break; case NAND_IO_OOB_READ: oob_rw = (struct nand_oob_rw *)data; ret = nand_oob_access(chip, oob_rw->page, 0, oob_rw->len, oob_rw->data, 0); break; case NAND_IO_OOB_PROG: oob_rw = (struct nand_oob_rw *)data; ret = nand_oob_access(chip, oob_rw->page, 0, oob_rw->len, oob_rw->data, 1); break; case NAND_IO_GET_STATUS: NANDBUS_LOCK(nandbus); ret = NANDBUS_GET_STATUS(nandbus, &status); if (ret == 0) *(uint8_t *)data = status; NANDBUS_UNLOCK(nandbus); break; case NAND_IO_RAW_PROG: while (len > 0) { if (len < bufsize) bufsize = len; ret = copyin(raw_rw->data + off, buf, bufsize); if (ret) break; ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, bufsize); if (ret) break; len -= bufsize; off += bufsize; } break; case NAND_IO_RAW_READ: while (len > 0) { if (len < bufsize) bufsize = len; ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, bufsize); if (ret) break; ret = copyout(buf, raw_rw->data + off, bufsize); if (ret) break; len -= bufsize; off += bufsize; } break; case NAND_IO_GET_CHIP_PARAM: nand_get_chip_param(chip, (struct chip_param_io *)data); break; default: printf("Unknown nand_ioctl request \n"); ret = EIO; } if (buf) free(buf, M_NAND); return (ret); }
static int nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, struct thread *td) { struct nand_chip *chip; struct nand_oob_rw *oob_rw = NULL; struct nand_raw_rw *raw_rw = NULL; device_t nandbus; uint8_t *buf = NULL; int ret = 0; uint8_t status; chip = (struct nand_chip *)ndisk->d_drv1; nandbus = device_get_parent(chip->dev); if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { raw_rw = (struct nand_raw_rw *)data; buf = malloc(raw_rw->len, M_NAND, M_WAITOK); } switch (cmd) { case NAND_IO_ERASE: ret = nand_erase_blocks(chip, ((off_t *)data)[0], ((off_t *)data)[1]); break; case NAND_IO_OOB_READ: oob_rw = (struct nand_oob_rw *)data; ret = nand_oob_access(chip, oob_rw->page, 0, oob_rw->len, oob_rw->data, 0); break; case NAND_IO_OOB_PROG: oob_rw = (struct nand_oob_rw *)data; ret = nand_oob_access(chip, oob_rw->page, 0, oob_rw->len, oob_rw->data, 1); break; case NAND_IO_GET_STATUS: NANDBUS_LOCK(nandbus); ret = NANDBUS_GET_STATUS(nandbus, &status); if (ret == 0) *(uint8_t *)data = status; NANDBUS_UNLOCK(nandbus); break; case NAND_IO_RAW_PROG: copyin(raw_rw->data, buf, raw_rw->len); ret = nand_prog_pages_raw(chip, raw_rw->off, buf, raw_rw->len); break; case NAND_IO_RAW_READ: ret = nand_read_pages_raw(chip, raw_rw->off, buf, raw_rw->len); copyout(buf, raw_rw->data, raw_rw->len); break; case NAND_IO_GET_CHIP_PARAM: nand_get_chip_param(chip, (struct chip_param_io *)data); break; default: printf("Unknown nand_ioctl request \n"); ret = EIO; } if (buf) free(buf, M_NAND); return (ret); }