/* Copyright 2013-2014 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __LIBFFS_H
#define __LIBFFS_H

#include <libflash/libflash.h>
#include <libflash/blocklevel.h>

/* FFS handle, opaque */
struct ffs_handle;
struct ffs_hdr;
struct ffs_entry;
struct ffs_entry_user;

/**
 * struct ffs_entry_user - User data entries
 *
 * Usable in memory representation of a struct __ffs_entry_user
 *
 *  @chip:		Chip Select (0,1)
 *  @compressType:	Compression Indication/alg (0=not compressed)
 *  @dataInteg:		Indicates Data Integrity mechanism
 *  @verCheck:		Indicates Version check type
 *  @miscFlags:		Misc Partition related Flags
 */
struct ffs_entry_user {
	uint8_t chip;
	uint8_t compresstype;
	uint16_t datainteg;
	uint8_t vercheck;
	uint8_t miscflags;
};

/* Error codes:
 *
 * < 0 = flash controller errors
 *   0 = success
 * > 0 = libffs / libflash errors
 */
#define FFS_ERR_BAD_MAGIC	100
#define FFS_ERR_BAD_VERSION	101
#define FFS_ERR_BAD_CKSUM	102
#define FFS_ERR_PART_NOT_FOUND	103
#define FFS_ERR_BAD_ECC		104
#define FFS_ERR_BAD_SIZE	105
#define FFS_ERR_BAD_PART_NAME	106
#define FFS_ERR_BAD_PART_BASE	107
#define FFS_ERR_BAD_PART_SIZE	108
#define FFS_ERR_BAD_PART_PID	109

/* The maximum length of the partition name */
#define FFS_PART_NAME_MAX   15
/* Old version of the name DEPRECATED */
#define PART_NAME_MAX   15

/*
 * Flag bit definitions
 */
#define FFS_FLAGS_PROTECTED	0x0001
#define FFS_FLAGS_U_BOOT_ENV	0x0002

/* Data integrity flags */
#define FFS_ENRY_INTEG_ECC 0x8000

/*
 * User verCheck definitions
 */
#define FFS_VERCHECK_SHA512V 0x80
#define FFS_VERCHECK_SHA512EC 0x40

/*
 * User miscFlags
 */
#define FFS_MISCFLAGS_PRESERVED 0x80
#define FFS_MISCFLAGS_READONLY 0x40
#define FFS_MISCFLAGS_BACKUP 0x20
#define FFS_MISCFLAGS_REPROVISION 0x10
#define FFS_MISCFLAGS_VOLATILE 0x08
#define FFS_MISCFLAGS_CLEARECC 0x04
#define FFS_MISCFLAGS_GOLDEN 0x01


int ffs_string_to_entry_user(const char *flags, int nflags,
		struct ffs_entry_user *user);
char *ffs_entry_user_to_string(struct ffs_entry_user *user);

bool has_ecc(struct ffs_entry *ent);

bool has_flag(struct ffs_entry *ent, uint16_t flag);

/* Init */

int ffs_init(uint32_t offset, uint32_t max_size, struct blocklevel_device *bl,
		struct ffs_handle **ffs, bool mark_ecc);

/*
 * Initialise a new ffs_handle to the "OTHER SIDE".
 * Reuses the underlying blocklevel_device.
 */
int ffs_next_side(struct ffs_handle *ffs, struct ffs_handle **new_ffs,
		bool mark_ecc);

/*
 * There are quite a few ways one might consider two ffs_handles to be the
 * same. For the purposes of this function we are trying to detect a fairly
 * specific scenario:
 * Consecutive calls to ffs_next_side() may succeed but have gone circular.
 * It is possible that the OTHER_SIDE partition in one TOC actually points
 * back to the TOC of the first ffs_handle.
 * This function compares for this case, therefore the requirements are
 * simple, the underlying blocklevel_devices must be the same along with
 * the toc_offset and the max_size.
 */
bool ffs_equal(struct ffs_handle *one, struct ffs_handle *two);

void ffs_close(struct ffs_handle *ffs);

int ffs_lookup_part(struct ffs_handle *ffs, const char *name,
		    uint32_t *part_idx);

int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx,
		  char **name, uint32_t *start,
		  uint32_t *total_size, uint32_t *act_size, bool *ecc);

struct ffs_entry *ffs_entry_get(struct ffs_handle *ffs, uint32_t index);

int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx,
			uint32_t act_size);

int ffs_hdr_new(uint32_t block_size, uint32_t block_count,
		struct ffs_entry **e, struct ffs_hdr **r);

int ffs_hdr_add_side(struct ffs_hdr *hdr);

int ffs_entry_new(const char *name, uint32_t base, uint32_t size, struct ffs_entry **r);

struct ffs_entry *ffs_entry_put(struct ffs_entry *ent);

int ffs_entry_user_set(struct ffs_entry *ent, struct ffs_entry_user *user);

int ffs_entry_set_act_size(struct ffs_entry *ent, uint32_t actual_size);


struct ffs_entry_user ffs_entry_user_get(struct ffs_entry *ent);

int ffs_entry_add(struct ffs_hdr *hdr, struct ffs_entry *entry);

int ffs_hdr_finalise(struct blocklevel_device *bl, struct ffs_hdr *hdr);

void ffs_hdr_free(struct ffs_hdr *hdr);
#endif /* __LIBFFS_H */
