/*
 * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
 *
 * This file is released under the terms of GPL v2 and any later version.
 * See the file COPYING in the root directory of the source tree for details.
 *
 *
 * This is a userspace Linux utility that, when run on the Treo 680, will
 * program u-boot to flash.  The docg4 driver *must* be loaded with the
 * reliable_mode and ignore_badblocks parameters enabled:
 *
 *        modprobe docg4 ignore_badblocks=1 reliable_mode=1
 *
 * This utility writes the concatenated spl + u-boot image to the start of the
 * mtd device in the format expected by the IPL/SPL.  The image file and mtd
 * device node are passed to the utility as arguments.  The blocks must have
 * been erased beforehand.
 *
 * When you compile this, note that it links to libmtd from mtd-utils, so ensure
 * that your include and lib paths include this.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <mtd/mtd-user.h>
#include "libmtd.h"

#define RELIABLE_BLOCKSIZE  0x10000 /* block capacity in reliable mode */
#define STANDARD_BLOCKSIZE  0x40000 /* block capacity in normal mode */
#define PAGESIZE 512
#define PAGES_PER_BLOCK 512
#define OOBSIZE 7		/* available to user (16 total) */

uint8_t ff_oob[OOBSIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};

/* this is the magic number the IPL looks for (ASCII "BIPO") */
uint8_t page0_oob[OOBSIZE] = {'B', 'I', 'P', 'O', 0xff, 0xff, 0xff};

int main(int argc, char * const argv[])
{
	int devfd, datafd, num_blocks, block;
	off_t file_size;
	libmtd_t mtd_desc;
	struct mtd_dev_info devinfo;
	uint8_t *blockbuf;
	char response[8];

	if (argc != 3) {
		printf("usage: %s <image file> <mtd dev node>\n", argv[0]);
		return -EINVAL;
	}

	mtd_desc = libmtd_open();
	if (mtd_desc == NULL) {
		int errsv = errno;
		fprintf(stderr, "can't initialize libmtd\n");
		return -errsv;
	}

	/* open the spl image file and mtd device */
	datafd = open(argv[1], O_RDONLY);
	if (datafd == -1) {
		int errsv = errno;
		perror(argv[1]);
		return -errsv;
	}
	devfd = open(argv[2], O_WRONLY);
	if (devfd == -1) {
		int errsv = errno;
		perror(argv[2]);
		return -errsv;
	}
	if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) {
		int errsv = errno;
		perror(argv[2]);
		return -errsv;
	}

	/* determine the number of blocks needed by the image */
	file_size = lseek(datafd, 0, SEEK_END);
	if (file_size == (off_t)-1) {
		int errsv = errno;
		perror("lseek");
		return -errsv;
	}
	num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE;
	file_size = lseek(datafd, 0, SEEK_SET);
	if (file_size == (off_t)-1) {
		int errsv = errno;
		perror("lseek");
		return -errsv;
	}
	printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt);
	printf("U-boot will occupy %d blocks\n", num_blocks);
	if (num_blocks > devinfo.eb_cnt) {
		fprintf(stderr, "Insufficient blocks on partition\n");
		return -EINVAL;
	}

	printf("IMPORTANT: These blocks must be in an erased state!\n");
	printf("Do you want to proceed?\n");
	scanf("%s", response);
	if ((response[0] != 'y') && (response[0] != 'Y')) {
		printf("Exiting\n");
		close(devfd);
		close(datafd);
		return 0;
	}

	blockbuf = calloc(RELIABLE_BLOCKSIZE, 1);
	if (blockbuf == NULL) {
		int errsv = errno;
		perror("calloc");
		return -errsv;
	}

	for (block = 0; block < num_blocks; block++) {
		int ofs, page;
		uint8_t *pagebuf = blockbuf, *buf = blockbuf;
		uint8_t *oobbuf = page0_oob; /* magic num in oob of 1st page */
		size_t len = RELIABLE_BLOCKSIZE;
		int ret;

		/* read data for one block from file */
		while (len) {
			ssize_t read_ret = read(datafd, buf, len);
			if (read_ret == -1) {
				int errsv = errno;
				if (errno == EINTR)
					continue;
				perror("read");
				return -errsv;
			} else if (read_ret == 0) {
				break; /* EOF */
			}
			len -= read_ret;
			buf += read_ret;
		}

		printf("Block %d: writing\r", block + 1);
		fflush(stdout);

		for (page = 0, ofs = 0;
		     page < PAGES_PER_BLOCK;
		     page++, ofs += PAGESIZE) {
			if (page & 0x04)  /* Odd-numbered 2k page */
				continue; /* skipped in reliable mode */

			ret = mtd_write(mtd_desc, &devinfo, devfd, block, ofs,
					pagebuf, PAGESIZE, oobbuf, OOBSIZE,
					MTD_OPS_PLACE_OOB);
			if (ret) {
				fprintf(stderr,
					"\nmtd_write returned %d on block %d, ofs %x\n",
					ret, block + 1, ofs);
				return -EIO;
			}
			oobbuf = ff_oob;  /* oob for subsequent pages */

			if (page & 0x01)  /* odd-numbered subpage */
				pagebuf += PAGESIZE;
		}
	}

	printf("\nDone\n");

	close(devfd);
	close(datafd);
	free(blockbuf);
	return 0;
}
