/*
 *  Copyright (C) 2006 Jean-Baptiste Note
 *  Copyright (C) 2002 Intersil Americas Inc.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#ifndef _HAS_BOOTREC_H
#define _HAS_BOOTREC_H

#include <linux/kernel.h>

/*
 * This file contains the definitions for Boot Records that
 * are used to identify (software/hardware) components.
 *
 * NOTE: All bootrecords start at a 32 bit aligned address
 * so the structs should NOT be packed
 */

#define BR_MAX_BRA_SIZE		512	/* size in bytes */

#define BR_CODE_MIN			0x80000000
#define BR_CODE_COMPONENT_ID		0x80000001
#define BR_CODE_COMPONENT_VERSION	0x80000002
#define BR_CODE_DEPENDENT_IF		0x80000003
#define BR_CODE_EXPOSED_IF		0x80000004
#define BR_CODE_DESCR			0x80000101
#define BR_CODE_MAX			0x8FFFFFFF
#define BR_CODE_END_OF_BRA		0xFF0000FF
#define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF

#ifndef VER_STRING_SIZE
#define VER_STRING_SIZE 6		/* size in 24 bit words */
#endif

/*
 * Each boot record is identified by a unique code, followed
 * by the length (in 32 bit words) of the data in the record.
 */
struct s_bootrec_hdr {
	uint32_t code;
	uint32_t length;
};

/* Generic bootrecord structure that can be mapped to each bootrecord */
struct s_bootrecord {
	struct s_bootrec_hdr hdr;
	char data[];
};

/* The Component ID is a unique identification of the component
 * Component IDs are defined in "interface.h"
 */

/* endianness-independent */
/* FIXME : is there a nice way to write this constant in C from
   something like
   { 'F', 'M', 'A', 'C' }
   { 'L', 'M', '8', '6' }
*/
#define FW_FMAC 0x464d4143
#define FW_LM86 0x4c4d3836
#define FW_LM87 0x4c4d3837
#define FW_LM20 0x4c4d3230

struct s_bootrec_comp_id {
	struct s_bootrec_hdr hdr;
	uint32_t id;
};

/* The Version String is a zero terminated ASCII string */
struct s_bootrec_comp_ver {
	struct s_bootrec_hdr hdr;
	char ver_string[VER_STRING_SIZE * sizeof(uint32_t)];
};

/*
 * Interfaces are defined by the following scheme
 *
 *  -----------------------------------------------------
 * | 16 bits |  16 bits |  16 bits |  16 bits |  16 bits |
 * |  role   |   if ID  |  variant | btm comp | top comp |
 *  -----------------------------------------------------
 *
 * Role and Interface IDs are defined in "interface.h"
 */

/*
 * The dependent interface defines which interfaces a component
 * needs for its proper operation. These can be mached against
 * the exposed interfaces of other components that are available.
 */
struct s_bootrec_dep_if {
	uint16_t role;
	uint16_t if_id;
	uint16_t variant;
} __attribute__((packed));

/*
 * The exposed interface defines which interfaces a component
 * offers to other components. Bottom and Top compatibility define
 * with which variants this interface is compatible with.
 */
struct s_bootrec_exp_if {
	uint16_t role;
	uint16_t if_id;
	uint16_t variant;
	uint16_t btm_compat;
	uint16_t top_compat;
} __attribute__((packed));

void islsm_print_exp_if(struct s_bootrec_exp_if *, unsigned int);

/*
 * The description interface defines several properties of the
 * component, such as memory layout. I'd guess the structure itself is
 * hardware-dependent.
 */

#define ISLSM_BRA_RATE_TABLE_SIZE 20
struct s_bootrec_descr {
	uint32_t unk1;
	uint32_t frame_mem_start;
	uint32_t frame_mem_end;
	int16_t  bound0;
	uint16_t val0;
	int16_t  bound1;
	uint16_t val1;
	uint8_t  rate_table[ISLSM_BRA_RATE_TABLE_SIZE];
} __attribute__((packed));

/* The Bootrecord End defines the end of the bootrecords.
 * No bootrecords will follow after this one
 */
struct s_bootrec_end {
	struct s_bootrec_hdr hdr;
	uint16_t CRC;
	uint16_t pad;
	uint32_t MD5[4];
};


/*
 * Some magic numbers
 */
#define PACK_MAGIC 0x5041434b
#define FW_VERSION_STRING_LEN 70

/* Some inline helper functions */

static inline int safe_bootrecord(const struct s_bootrecord *bootrec, char *end_of_data) {
	uint32_t length = le32_to_cpu(bootrec->hdr.length);
	if (end_of_data < bootrec->data ||
	    end_of_data < (char *)bootrec + length * sizeof(uint32_t))
		return -1;
	return 0;
}

/*
 * Returns 0 if the passed bootrecord is valid, -1 otherwise.
 */
static inline int valid_bootrecord(const struct s_bootrecord *bootrec)
{
	uint32_t length = le32_to_cpu(bootrec->hdr.length);
	uint32_t code = le32_to_cpu(bootrec->hdr.code);
	/* length too big */
	if (length > (BR_MAX_BRA_SIZE / sizeof(uint32_t))) {
		printk(KERN_ERR "bra parsing: bootrecord too long (length=%u)\n", length);
		return -1;
	}

	if(code == BR_CODE_END_OF_BRA)
		return 0;

	/* no valid code */
	if((code < BR_CODE_MIN) || (code > BR_CODE_MAX)) {
		printk(KERN_ERR "bra_parsing: Bootrecord illegal code\n");
		return -1;
	 }

	return 0;
}

/*
 * Returns the number of dependent interfaces in a bootrecord
 * result < 0 if no valid dependent interface bootrecord is passed
 */
static inline int nof_dep_interfaces(const struct s_bootrecord *bootrec)
{
	uint32_t length = le32_to_cpu(bootrec->hdr.length);
	uint32_t code = le32_to_cpu(bootrec->hdr.code);

	if((code != BR_CODE_DEPENDENT_IF) || (valid_bootrecord(bootrec)))
		return -1;

	return (length * sizeof(uint32_t)) / sizeof(struct s_bootrec_dep_if);
}

/*
 * Returns the number of exposed interfaces in a bootrecord.
 * result < 0 if no valid exposed interface bootrecord is passed
 */
static inline int nof_exp_interfaces(const struct s_bootrecord *bootrec)
{
	uint32_t length = le32_to_cpu(bootrec->hdr.length);
	uint32_t code = le32_to_cpu(bootrec->hdr.code);

	if((code != BR_CODE_EXPOSED_IF) || valid_bootrecord(bootrec))
		return -1;

	return (length * sizeof(uint32_t)) / sizeof(struct s_bootrec_exp_if);
}

/*
 * Returns the size in bytes of a bootrecord, including the header.
 */
static inline int bootrecord_size(const struct s_bootrecord *bootrec)
{
	uint32_t length = le32_to_cpu(bootrec->hdr.length);
	return (sizeof(struct s_bootrec_hdr) + (length * sizeof(uint32_t)));
}

/*
 * Returns a pointer to the next bootrecord
 */
static inline struct s_bootrecord *next_bootrecord(const struct s_bootrecord *bootrec)
{
	struct s_bootrecord *next;

	next = (struct s_bootrecord *)((uint8_t *)bootrec + bootrecord_size(bootrec));
	return next;
}

//----------------
// Interface Roles
//----------------
// The interface Role can be client or server
#define BR_IF_ROLE_SERVER		0x0000
#define BR_IF_ROLE_CLIENT		0x8000

//---------------
// Interface ID's
//---------------
// The interface ID is a unique identification of a specific interface.
// The following values are reserved: 0x0000, 0x0002
//					0x0000	Reserved
#define BR_IF_ID_ISL36356A		0x0001	// Interface between BR_COMP_ID_ISL36356A <-> Firmware
//					0x0002	Reserved
#define BR_IF_ID_MVC			0x0003	// MAC Virtual Coprocessor
#define BR_IF_ID_SNMP_IF		0x0004	// SNMP Interface between Application <-> Firmware
#define BR_IF_ID_SNWNMP_IF		0x0005	// SNWNMP Interface between Application <-> Firmware
#define BR_IF_ID_HTTP_IF		0x0006	// HTTP Interface between Application <-> Firmware
#define BR_IF_ID_MANUF_TST_IF		0x0007	// Manufacturing and Test Interface between Application <-> Firmware
#define BR_IF_ID_DEBUG_IF		0x0008	// PolDebug Interface between Application <-> Firmware
// The PRODUCT and OEM interface are conceptual interfaces for product differentiation
#define BR_IF_ID_PRODUCT_IF		0x0009
#define BR_IF_ID_OEM_IF			0x000A
#define BR_IF_ID_PCIHOST_IF		0x000B  // Host PCI Interface
#define BR_IF_ID_PCI3877_IF		BR_IF_ID_PCIHOST_IF	// 3877 <-> Host PCI Interface
#define BR_IF_ID_DAP1_MAP		BR_IF_ID_PCIHOST_IF	// Interface between BR_COMP_ID_DAP1 <-> Micro AP Firmware
#define BR_IF_ID_ISL37704C		0x000C	// Interface between BR_COMP_ID_ISL37704C <-> Firmware
#define BR_IF_ID_ISL37700M		BR_IF_ID_ISL37704C	// Interface between BR_COMP_ID_ISL37700M <-> Firmware
#define BR_IF_ID_TFTP			0x000D	// TFTP Interface Application <-> Firmware
#define BR_IF_ID_STFTP			0x000E	// STFTP Interface between Application <-> Firmware
#define BR_IF_ID_ISL39000		0x000F  // Interface between BR_COMP_ID_ISL39000 <-> Firmware
#define BR_IF_ID_ISL39000M              BR_IF_ID_ISL39000  // Interface between BR_COMP_ID_ISL39000M <-> Firmware
#define BR_IF_ID_ISL39300A              0x0010  // Interface between BR_COMP_ID_ISL39300A <-> Firmware
#define BR_IF_ID_BOOT_IF		0x0011  // Interface of bootloader and remaining firmware
#define BR_IF_ID_DBO1                   BR_IF_ID_BOOT_IF  // Interface between BR_COMP_ID_DBO1 <-> Firmware
//					0x0012  Reserved
#define BR_IF_ID_FS_IF			0x0013	// File set interface (size, format, etc)
#define BR_IF_ID_DAP1_FS		BR_IF_ID_FS_IF	// Interface between BR_COMP_ID_DAP1 <-> File Set
//					0x0014  Reserved
//					0x0015  Reserved
#define BR_IF_ID_ISL37700_UAP_IF        0x0016	// Interface between ISL37700 uAP firmware <-> Firmware
#define BR_IF_ID_ISL39000_UAP_IF        0x0017  // Interface between ISL39000 uAP firmware <-> Firmware
// The Primary PRODUCT and Primary OEM interface are conceptual interfaces for product differentiation
#define BR_IF_ID_PRIMARY_PRODUCT_IF     0x0018
#define BR_IF_ID_PRIMARY_OEM_IF         0x0019
#define BR_IF_ID_LMAC_IF		0x001A	// Interface exposed by LMAC, see doc. 553265


#endif /* _HAS_BOOTREC_H */
