Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
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);
}