/*
 * Generic code for programming a the epi3 personality on a plug-in module
 *
 * Copyright 2010 Allied Telesis Labs
 */

#include <common.h>
#include <config.h>
#include <command.h>
#include <epi3.h>
#include <diag.h>
#include <malloc.h>
#include <bootmenu.h>
#include <pci.h>
#include <i2c.h>
#include "diag_epi3_module.h"

static struct epi3_mod_ops function_table[EPI3_TYPE_MAX];

static char *
module_type_str (enum epi3_type type)
{
	switch (type) {
	case EPI3_TYPE_BASE:
		return "Base";
	case EPI3_TYPE_XEM:
		return "XEM";
	case EPI3_TYPE_PSU:
		return "PSU";
	case EPI3_TYPE_EM:
		return "EM";
	default:
		return "Unknown";
	}
}

int
diag_epi3_module_register (enum epi3_type type, struct epi3_mod_ops *funcs)
{
	if (!funcs)
		return -1;

	printf ("EPI3 module registering %s\n", module_type_str(type));

	if (funcs->init_comms)
		function_table[type].init_comms = funcs->init_comms;
	if (funcs->deinit_comms)
		function_table[type].deinit_comms = funcs->deinit_comms;
	if (funcs->display)
		function_table[type].display = funcs->display;
	if (funcs->program)
		function_table[type].program = funcs->program;
	if (funcs->erase)
		function_table[type].erase = funcs->erase;

	return 0;
}

int
diag_epi3_module_init_comms (enum epi3_type type, int index)
{
	if (function_table[type].init_comms) {
		return function_table[type].init_comms(index);
	}

	return 0;
}

int
diag_epi3_module_deinit_comms (enum epi3_type type, int index)
{
	if (function_table[type].deinit_comms) {
		return function_table[type].deinit_comms(index);
	}

	return 0;
}

int
diag_epi3_module_display (enum epi3_type type, int index)
{
	if (function_table[type].display) {
		return function_table[type].display(index);
	}

	return 0;
}

int
diag_epi3_module_program (enum epi3_type type, int index)
{
	if (function_table[type].program) {
		return function_table[type].program(index);
	}

	return 0;
}

int
diag_epi3_module_erase (enum epi3_type type, int doit, int index)
{
	if (function_table[type].erase) {
		return function_table[type].erase(doit, index);
	}

	return 0;
}

void
diag_epi3_module_init()
{
	memset (function_table, 0, sizeof(function_table));
#ifdef CONFIG_NUM_XEMS
	diag_epi3_xem_init();
#endif
#ifdef CONFIG_DIAG_EPI3_PSU
	diag_epi3_psu_init();
#endif
}

int
diag_epi3_module_submenu (enum epi3_type type, int index)
{
	char key;
	u8 quit;
	char *type_str = module_type_str (type);

	if (diag_epi3_module_init_comms (type, index)) {
		diag_printf ("Error: %s %d didn't start\n", type_str, index);
		return 1;
	}

	quit = 0;
	while (!quit) {
		diag_printf ("\n\nPersonality Menu (%s %d):\n\n", type_str, index);
		diag_printf ("  0. Previous menu\n"
		     "  ----------------------------------\n"
		     "  1. Display personality\n"
		     "  2. Program personality\n");
		if (getenv("developer"))
			diag_printf ("  3. Erase personality area\n");
		diag_printf ("\nEnter selection ==> ");

		key = serial_getc ();
		if (key >= '0' && key <= '9')
		{
			serial_putc (key);
			serial_putc ('\n');
			serial_putc ('\n');
		}

		switch (key)
		{
		case '0':
			quit = 1;
			break;
		case '1':
			diag_epi3_module_display (type, index);
			break;
		case '2':
			diag_epi3_module_program (type, index);
			break;
		case '3':
			if (getenv("developer"))
				diag_epi3_module_erase (type, 0, index);
			break;
		default:
		    break;
		}
	}

	diag_epi3_module_deinit_comms (type, index);
	return 0;

}
