/*
   Xbox XBE bootloader

    Original code by Michael Steil & anonymous
    VESA Framebuffer code by Milosch Meriac
	Modified to boot shadow bioses by Phoenix

	Note that this is a very modified version, not created
	nor endorsed by the xbox-linux team.
*/

#include <stdlib.h>
#include <BootUSB.h>
#include <string.h>
#include <fb.h>
#include <sys/xboxkrnl.h>
#include <sys/types.h>
#include <sys/nttypes.h>

#include <Hermes.h>
#include <H_Conv.h>

#include "ntfile.h"
#include "debug.h"
#include "pconfig.h"

#include "bitmapfont.h"

extern void DoSplash();
extern void loadbios(unsigned char *rom, CONFIGENTRY *entry);
extern void Dash();

CONFIGENTRY *entry;

HermesHandle converter;
HermesHandle clearer;
HermesFormat *form;

// Sets the led color based on the sequence from the config file.
// 'r' = red
// 'g' = green
// 'o' = orange
// 'x' = off
// This code is derived directly from the blink.c code
// (C) 2002-11-11 Georg Lukas <georg@boerde.de>
void setLED(PUCHAR LedSequence)
{
	int reg, r, g;

	r = g = 0;
	while (*LedSequence) {
		r *= 2;
		g *= 2;
		switch (*LedSequence) {
		case 'r' : r++; break;
		case 'g' : g++; break;
		case 'o' : r++; g++; break;
		}
		LedSequence++;
	}
	//printf("collected flags: r=%02x g=%02x\n", r, g);
	reg = ((r<<4) & 0xF0) + (g & 0xF);

	HalWriteSMBusValue(0x20, 0x08, FALSE, reg);
	HalWriteSMBusValue(0x20, 0x07, FALSE, 0x01);
}

void mainthread(PVOID parm1, PVOID parm2);

//perhaps theres a better way to handle a failure case, here?
void winmain(void) {
	HANDLE hThread = 0;
	ULONG Id = 0;
	LARGE_INTEGER Timeout;
	ULONG Status;
	
	Timeout.QuadPart = 0;


	if(!NT_SUCCESS(PsCreateSystemThreadEx(&hThread,
					0,
					65536,
					0,
					&Id,
					NULL,
					NULL,
					FALSE,
					FALSE, 
					(PVOID)&mainthread))) {
		
		HalReturnToFirmware(RebootQuick);
	}
	while(1) {
		Status = NtWaitForSingleObjectEx(hThread, 1 /* UserMode */ ,FALSE,&Timeout);
		if(Status == STATUS_SUCCESS) {
			NtClose(hThread);
			HalReturnToFirmware(RebootQuick);
		}
	}
}

void mainthread(PVOID parm1, PVOID parm2) {
	int i=0;
	//UCHAR state = 0;

	//use the parameters a bit, just to get rid of warnings
	parm1 = parm2;
	parm2 = parm1;

	BootVga(0); // FIXME, use VIDEO_MODE_640x480

	printk("\n\n\n");
	printk("Phoenix Bios Loader v1.3.5 INTERNAL!\n");
	printk("Official Forums: http://forums.maxconsole.com\n\n");

	printk("Starting USB\n");
	BootStartUSB();

	
	if(!RemapDrive("\\??\\P:",NULL)) {
		Die("Error Remapping Drive");
	}

	// parse the configuration file
	entry = GetConfig("P:\\");

	// If led is specified, set it
//	if (strlen(entry->szLED) > 0)
//	{
//		printk("Setting led: %s\n", entry->szLED);
//		setLED(entry->szLED);
//	}

	printk("Starting Hermes\n");
	if(!Hermes_Init())
	{
		Die("Error initializing Hermes");
	}
	
	printk("Hermes_ConverterInstance\n");
	converter = Hermes_ConverterInstance(HERMES_CONVERT_DITHER); //HERMES_CONVERT_DITHER
	if(!converter)
	{
		Die("Error initializing Converter");
	}

	printk("Hermes_ClearerInstance\n");
	clearer = Hermes_ClearerInstance();
	if(!clearer)
	{
		Die("Error initializing Clearer");
	}
	
	
	printk("Hermes_FormatNew\n");
	form = Hermes_FormatNew(32,
			0x000000FF,
			0x0000FF00,
			0x00FF0000,
			0xFF000000,0);
	if(!form)
	{
		Die("Could not initialize screen format");
	}

	
	// Only do intro the 1st time
	if (!entry->DebugFlag)
	{
			DoSplash();
	}



	printk("Press A now to enter selection menu!\n");
	for(i=0;i<entry->timeout;i++)
	{
		USBGetEvents();
		if(risefall_xpad_BUTTON(TRIGGER_XPAD_KEY_A) == 1)
		{
			Dash();
			break;
		}
	}
	

//	printk("Stopping USB\n");
//	BootStopUSB();
	
	printk("Stopping Hermes\n");

	Hermes_ConverterReturn(converter);
	Hermes_ClearerReturn(clearer);
	Hermes_FormatFree(form);
// ED Crash on my box
//	Hermes_Done();
	
	// Check Tray State and load appropriate bios
	/*
	HalReadSMBusValue(0x20, 0x03, 0, &state, 1, FALSE);
	if (state == 0x10 && strlen(entry->szAltRom) > 0)
	{
		printk("Loading Alternate Rom: %s\n", entry->szAltRom);
		loadbios(entry->szAltRom, entry);
	} 
	else 
	{
	*/
		printk("Loading Rom: %s\n", entry->szRom);
		loadbios(entry->szRom, entry);
	//}

	

}
