//////////////////////////////////////////////////
//* Custom Firmware Extender For 3.71 Firmware *//
//////////////////////////////////////////////////

#include <psptypes.h>
#include <pspkernel.h>
#include <stdio.h>
#include <string.h>

#include "../include/systemctrl_se.h"
#include "../include/pspmodulemgr_kernel.h"
#include "../include/systemctrl.h"

#include "main.h"
#include "screenshot.h"
#include "conf.h"
#include "translateButtons.h"

#include "blit.h"

PSP_MODULE_INFO("cfe_vsh_mod", 0x1000, 1, 1);
PSP_MAIN_THREAD_ATTR(0);
PSP_MAIN_THREAD_STACK_SIZE_KB(0);

#define HOSTFSDRIVER_NAME "USBHostFSDriver"
#define HOSTFSDRIVER_PID  (0x1C9)

#define PSP_USBBUS_DRIVERNAME "USBBusDriver"
#define PSP_USBSTOR_DRIVERNAME "USBStor_Driver"
#define PSP_USB_ACTIVATED              0x200

char strBuf0[64];
char strBuf1[64];
char strBuf2[64];
char strBuf3[64];
char strBuf4[64];
char strBuf5[64];
char strBuf6[64];
char strBuf7[64];
char strBuf8[64];
char strBuf9[64];

char strMsg[128];

int showMsg = 0;
int showUsbhostMenu = 0;
int showHelp = 0;

int cpuSpeed = 222;
int webBrowserLoaded = 0;
int usbMass = 0;
int usbModules = 0;
int firstBoot = 0;
int stopSleepMode = 0;
int usbhostLoaded = 0;
int menuDone = 0;
int kill_display = 0;

int usePspFat = 0;

int usbmodloaded = 0;

char fullpath[30][128];
char fullpath_ms0[30][128];
int num = 0;

u32 state;
u32 retVal;

SceCtrlData pad;
SceCtrlData padIso;
unsigned int pad_old;

SceUID main_thid;
SceUID display_thid;

CONFIGFILE config;

int cleanExit;

int showStreamMenu = 0;

int build_args(char *args, const char *execfile, int argc, char **argv)
{
	int loc = 0;
	int i;

	strcpy(args, execfile);
	loc += strlen(execfile) + 1;
	for(i = 0; i < argc; i++)
	{
		strcpy(&args[loc], argv[i]);
		printf("Arg %i => %s\n", i, argv[i]);
		loc += strlen(argv[i]) + 1;
	}

	return loc;
}

int loadStartModule(const char *name, int argc, char **argv)
{
	SceUID modid;
	int status;
	char args[128];
	int len;

	modid = sceKernelLoadModule(name, 0, NULL);
	if(modid >= 0)
	{
		len = build_args(args, name, argc, argv);
		modid = sceKernelStartModule(modid, len, (void *) args, &status, NULL);
	}
	else
	{
		printf("lsm: Error loading module %s\n", name);
	}

	return modid;
}

int loadNetHost()
{
	//int ARGC;
	char *argv[5];
	//int argc = ARGC;
	
	char param0[]="192.168.1.2";
	char param1[]="7513";
	char param2[]="1";
	char param3[]="1";
	char param4[]="1";
	
	argv[0] = param0;
	argv[1] = param1;
	argv[2] = param2;
	argv[3] = param3;
	argv[4] = param4;
	
	//argv[argc] = NULL;
	
	
	loadStartModule("ms0:/seplugins/cfe/nethostfs_371.prx", 5, &argv);
	
	return 0;
}

int unloadStopModule(char *modname)
{
	SceModule *mod;

	while ((mod = sceKernelFindModuleByName(modname)))
	{
		sceKernelStopModule(mod->modid, 0, NULL, NULL, NULL);
		sceKernelUnloadModule(mod->modid);
	}

	return 0;

}

int doBlit(char *msg)
{
	strcpy(strMsg, msg);
	showMsg=1;
	return 0;
}	

int showFps = 0;

int display_thread(SceSize args, void *argp)
{
    while(1) 
	{
		if(showFps) {
			//sprintf(strBuf0,"%03d fps",sceDisplay_driver_13AA96B7()/1000.0f);
			sprintf(strBuf0,"fps: %d.%03d",sceDisplay_driver_13AA96B7(),sceDisplay_driver_13AA96B7()* 1000.0f);
			blit_string(1, 1, strBuf0,0xffffff,0x000000);
		}
		
		if(kill_display) 
		{
			sceKernelExitDeleteThread(0);
		}
		
		if(showMsg)
		{
			blit_string(1,33,strMsg,0xffffff,0x000000);
			showMsg++;
			if(showMsg==600) showMsg=0;			
		}
		
		if(showUsbhostMenu)
		{
			blit_string(1, 26, "Press L/R to change iso",0xffffff,0x000000);
			blit_string(1, 28, "Press Home to launch selected",0xffffff,0x000000);
			blit_string(1, 30, "Press Circle to cancel",0xffffff,0x000000);
			blit_string(1, 32, fullpath[num],0xffffff,0x000000);
		}
		
		if(showHelp)
		{
			blit_string(1, 9, "Custom Firmware Extender 1.8",0xffffff,0x000000);
			blit_string(1, 10, "==========================================",0xffffff,0x000000);
			blit_string(1, 12, strBuf0,0xffffff,0x000000);
			blit_string(1, 14, strBuf1,0xffffff,0x000000);
			blit_string(1, 16, strBuf2,0xffffff,0x000000);
			blit_string(1, 18, strBuf3,0xffffff,0x000000);
			blit_string(1, 20, strBuf4,0xffffff,0x000000);
			blit_string(1, 22, strBuf5,0xffffff,0x000000);
			blit_string(1, 24, strBuf6,0xffffff,0x000000);
			blit_string(1, 26, strBuf7,0xffffff,0x000000);
			//blit_string(1, 28, strBuf8,0xffffff,0x000000);
			blit_string(1, 28, strBuf9,0xffffff,0x000000);
			blit_string(1, 30, "Circle = Hide This Help",0xffffff,0x000000);
		}
		
		if(showStreamMenu==1)
		{
			blit_string(1, 26, "  Streaming mode to use (Home = proceed, Circle = cancel)",0xffffff,0x000000);
			blit_string(1, 28, "  > Usbhostfs Iso redirection",0x000000,0xffffff);
			//blit_string(1, 28, "    Usbhostfs Homebrew redirection",0x000000,0xffffff);
			blit_string(1, 30, "    Nethostfs Iso redirection",0xffffff,0x000000);
			blit_string(1, 32, "    Nethostfs Homebrew redirection",0xffffff,0x000000);			
		}
		if(showStreamMenu==2)
		{
			blit_string(1, 26, "  Streaming mode to use (Home = proceed, Circle = cancel)",0xffffff,0x000000);
			blit_string(1, 28, "    Usbhostfs Iso redirection",0xffffff,0x000000);
			//blit_string(1, 28, "  > Usbhostfs Homebrew redirection",0x000000,0xffffff);
			blit_string(1, 30, "  > Nethostfs Iso redirection",0x000000,0xffffff);
			blit_string(1, 32, "    Nethostfs Homebrew redirection",0xffffff,0x000000);			
		}
		if(showStreamMenu==3)
		{
			blit_string(1, 26, "  Streaming mode to use (Home = proceed, Circle = cancel)",0xffffff,0x000000);
			blit_string(1, 28, "    Usbhostfs Iso redirection",0xffffff,0x000000);
			//blit_string(1, 28, "    Usbhostfs Homebrew redirection",0x000000,0xffffff);
			blit_string(1, 30, "    Nethostfs Iso redirection",0xffffff,0x000000);
			blit_string(1, 32, "  > Nethostfs Homebrew redirection",0x000000,0xffffff);			
		}
		/*if(showStreamMenu==4)
		{
			blit_string(1, 24, "  Streaming mode to use (Home = proceed, Circle = cancel)",0xffffff,0x000000);
			//blit_string(1, 26, "    Usbhostfs Iso redirection",0xffffff,0x000000);
			blit_string(1, 28, "    Usbhostfs Homebrew redirection",0x000000,0xffffff);
			blit_string(1, 30, "    Nethostfs Iso redirection",0xffffff,0x000000);
			blit_string(1, 32, "  > Nethostfs Homebrew redirection",0x000000,0xffffff);			
		}*/

		sceKernelDelayThread(2000);
    }
	return 0;
}

int loadUsb(void) {

	if(!usbModules) 
	{
		if(!usbmodloaded) {
			loadStartModule("flash0:/kd/semawm.prx", 0, NULL);
			loadStartModule("flash0:/kd/usbstor.prx", 0, NULL);
			loadStartModule("flash0:/kd/usbstormgr.prx", 0, NULL);
			loadStartModule("flash0:/kd/usbstorms.prx", 0, NULL);
			loadStartModule("flash0:/kd/usbstorboot.prx", 0, NULL);
			usbmodloaded=1;
		}
		
		retVal = sceUsb_driver_AE5DE6AF(PSP_USBBUS_DRIVERNAME, 0, 0); //sceUsbStart
		if (retVal != 0) {
			printf("Error starting USB Bus driver\n");
			sceKernelSleepThread();
		}
		retVal = sceUsb_driver_AE5DE6AF(PSP_USBSTOR_DRIVERNAME, 0, 0); //sceUsbStart
		if (retVal != 0) {
			printf("Error starting USB Mass Storage driver\n");
			sceKernelSleepThread();
		}
		retVal = sceUsbstorBoot_E58818A8(0x800000); //sceUsbstorBootSetCapacity
		if (retVal != 0) {
			printf("Error setting capacity with USB Mass Storage driver\n");
			sceKernelSleepThread();
		}
		retVal = 0;
		sceKernelDelayThread(5*10000);
		usbModules=1;
	}

	if (state & PSP_USB_ACTIVATED) {
		//retVal = sceUsb_driver_C572A9C8(0x1c8);
		unloadUsb();
		if(!firstBoot) 	doBlit("Usb Mass Storage Stopped");
	}
	else {
		retVal = sceUsb_driver_586DB82C(0x1c8); //sceUsbActivate
		if(!firstBoot) doBlit("Usb Mass Storage Started");
	}
	return 0;
}

void unloadUsb() {

	sceUsb_driver_C572A9C8(0x1c8);
	sceUsb_driver_C2464FA0(PSP_USBSTOR_DRIVERNAME, 0, 0); //sceUsbStop
  	sceUsb_driver_C2464FA0(PSP_USBBUS_DRIVERNAME, 0, 0);
	usbModules=0;
}

void unloadUsbhost() {

	sceUsb_driver_C572A9C8(HOSTFSDRIVER_PID);
	sceUsb_driver_C2464FA0(HOSTFSDRIVER_NAME, 0, 0); //sceUsbStop
  	sceUsb_driver_C2464FA0(PSP_USBBUS_DRIVERNAME, 0, 0);
	unloadStopModule("USBHostFS");
}

void setCpuSpeed(void)
{
	switch(cpuSpeed) {

		case 111:
			sctrlHENSetSpeed(111,55);
			cpuSpeed=222;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}			
			break;		
	
		case 222:
			sctrlHENSetSpeed(222,111);
			cpuSpeed=266;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}			
			break;
					
		case 266:
			sctrlHENSetSpeed(266,133);
			cpuSpeed=333;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	
		case 333:
			sctrlHENSetSpeed(333,166);
			cpuSpeed=66;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	
		case 66:
			sctrlHENSetSpeed(66,33);
			cpuSpeed=111;
			sceKernelDelayThread(10000);
			if(!firstBoot) {
				sprintf(strBuf0,"Cpu/Bus Speed => %03d/%03d",scePower_driver_FDB5BFE9(),scePower_driver_1688935C());
				doBlit(strBuf0);
			}
			break;
	}
}

int hookWait = 0;
int hookWait2 = 0;

void execEboot(char *target)
{
	cleanExit = 0;
			
	sceKernelDelayThread(1000);
			
	kill_display=1;
			
	sceKernelDelayThread(1000);

	struct SceKernelLoadExecVSHParam param;
			
	memset(&param, 0, sizeof(param));
			
	param.key = "game";
	param.size = sizeof(param);
	param.args = strlen(target)+1;
	param.argp = target;
	
	nkThreadResume(sceKernelGetThreadId());
	
	sctrlKernelLoadExecVSHMs2(target, &param);	
	
	sceKernelExitDeleteThread(0);
}


int vshHook()
{
	
	if(hookWait>0) hookWait--;
	
	if(!hookWait) 
	{	
		if(enable_replace_video_icon_with)
		{		
			if(sceKernelFindModuleByName("msvideo_plugin_module"))  // video
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_video_icon_with);
			}
		}

		if(enable_replace_locationFree_icon_with)
		{			
			if(sceKernelFindModuleByName("lftv_plugin_module")) // Location Free
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_locationFree_icon_with);
			}
		}

		if(enable_replace_remotePlay_icon_with)
		{			
			if(sceKernelFindModuleByName("premo_plugin_module")) // Lecture à distance
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_remotePlay_icon_with);
			}
		}

		if(enable_replace_rss_icon_with)
		{	
			if(sceKernelFindModuleByName("rss_main_plugin_module")) // Rss
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_rss_icon_with);
			}
		}
		
		if(enable_replace_gameSharing_icon_with)
		{			
			if(sceKernelFindModuleByName("sceVshGSPlugin_Module")) // Partage de jeu
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_gameSharing_icon_with);
			}
		}
		
		if(enable_replace_update_icon_with)
		{
			if(sceKernelFindModuleByName("update_plugin_module")) // Update
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_update_icon_with);
			}
		}

		if(enable_replace_camera_icon_with)
		{
			if(sceKernelFindModuleByName("camera_plugin_module")) // Camera
			{
				nkThreadSuspend(sceKernelGetThreadId());
				execEboot(config.replace_camera_icon_with);
			}
		}		
		hookWait = 100;
	}
	return 0;	
}

void cleanBeforeExit() {

	if(hookWait2>0) hookWait2--;
	
	if(!hookWait2)
	{
		SceUID thids[50];
		int thid_count = 0;
		int i;
		SceKernelThreadInfo thinfo;

		sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread,thids,50,&thid_count);
		for(i=0;i<thid_count;i++)
			{
			memset(&thinfo,0,sizeof(SceKernelThreadInfo));
			thinfo.size = sizeof(SceKernelThreadInfo);
            
			sceKernelReferThreadStatus(thids[i],&thinfo);

			if(strcmp(&thinfo.name[0],"SceKernelLoadExecThread")==0)
			{
				menuDone = 1;
				if(usbModules) unloadUsb();
				sceKernelTerminateDeleteThread(main_thid);
				sctrlHENSetSpeed(222,111);
				sceKernelSelfStopUnloadModule(1, 0, NULL); 
			}
		}
		hookWait2 = 200;
		
	}
}

int helpMenu() 
{	
	menuDone=0;
	
	sprintf(strBuf0, "%s + %s = Shutdown PSP", config.comboButton, config.poweroffButton);
	sprintf(strBuf1, "%s + %s = Reboot PSP", config.comboButton, config.resetButton);
	sprintf(strBuf2, "%s + %s = Change Cpu Speed", config.comboButton, config.cpuspeedButton);
	sprintf(strBuf3, "%s + %s = Set Max Brightness", config.comboButton, config.maxBrightnessButton);
	sprintf(strBuf4, "%s + %s = Start usb iso redirection", config.comboButton, config.usbhostUmdModeButton);
	sprintf(strBuf5, "%s + %s = Start/Stop Usb Mass", config.comboButton, config.startStopUsbmassButton);
	sprintf(strBuf6, "%s + %s = Start Ftpd server", config.comboButton, config.startFtpdButton);
	sprintf(strBuf7, "%s + %s = Take Screenshot", config.comboButton, config.takeScreenshotButton);
	//sprintf(strBuf8, "%s + %s = Start video capture (fat psp)", config.comboButton, config.captureButton);
	sprintf(strBuf9, "%s + %s = Show this help", config.comboButton, config.showHelpButton);	
	
	nkThreadSuspend(sceKernelGetThreadId());
	
	while(!menuDone)
	{
		cleanBeforeExit();
		
		showHelp=1;
		
		sceDisplay_driver_B685BA36();
		
		sceCtrl_driver_C4AAD55F(&pad, 1);
		if (pad.Buttons != pad_old)
		{	
			if(pad.Buttons & PSP_CTRL_CIRCLE) 
			{
				nkThreadResume(sceKernelGetThreadId());
				showHelp=0;
				menuDone=1;
			}
		}
	}
	pad_old = pad.Buttons;
	sceKernelDelayThread(1000);
	
	return 0;
}

int getIso(int mode)
{
	int ctrlWait = 0;
	int retry = 0;
	
	//if(mode==0||mode==1) 
	if(mode==0) 
	{
		if(usbModules) unloadUsb();
		sceKernelDelayThread(100000);

		loadStartModule("ms0:/seplugins/cfe/usbhostfs.prx", 0, NULL);	
		int retVal = 0;
		retVal = sceUsb_driver_AE5DE6AF(PSP_USBBUS_DRIVERNAME, 0, 0); //SceUsbStart
		if (retVal != 0) {
			printf("Error starting USB Bus driver\n");
			return 0;
		}
		retVal = sceUsb_driver_AE5DE6AF(HOSTFSDRIVER_NAME, 0, 0);
		if (retVal != 0) {
			printf("Error starting USB Host driver\n");
			return 0;
		}
		retVal = sceUsb_driver_586DB82C(HOSTFSDRIVER_PID); //SceUsbActivate
	
		sceKernelDelayThread(30*100000);
		usbhostLoaded=1;
		
		//if(mode==0) {
			int fd33 = sceIoOpen("fatms0:/seplugins/cfe/usbhost_iso", PSP_O_CREAT | PSP_O_RDWR, 0777);
			//if(fd33 < 0) printf("Could not write usbhost_iso.log");
			sceIoWrite(fd33, "o", 1);
			sceIoClose(fd33);
		/*}
		else {
			int fd33 = sceIoOpen("fatms0:/seplugins/cfe/usbhost_game", PSP_O_CREAT | PSP_O_RDWR, 0777);
			//if(fd33 < 0) printf("Could not write usbhost_iso.log");
			sceIoWrite(fd33, "o", 1);
			sceIoClose(fd33);
		}*/	
	} 
	else {

		loadNetHost();
		
		sceKernelDelayThread(100*100000);

		if(mode==1) {
			int fd33 = sceIoOpen("fatms0:/seplugins/cfe/nethost_iso_ip", PSP_O_CREAT | PSP_O_RDWR, 0777);
			//if(fd33 < 0) printf("Could not write usbhost_iso.log");
			sceIoWrite(fd33, config.pc_ip_address, 16);
			sceIoClose(fd33);
		}
		else {
			int fd33 = sceIoOpen("fatms0:/seplugins/cfe/nethost_game_ip", PSP_O_CREAT | PSP_O_RDWR, 0777);
			//if(fd33 < 0) printf("Could not write usbhost_iso.log");
			sceIoWrite(fd33, config.pc_ip_address, 16);
			sceIoClose(fd33);
		}
	}	
	
	SceIoDirent dir;
	
	int isoDir, isoDone = 0, isoCount = 0, isoMax = 0;

	num = 0;

	if(mode==0) {
	
		isoDir = sceIoDopen("host0:/ISO");
	}
	/*else if(mode==1) {

		isoDir = sceIoDopen("host0:/PSP/GAME");
	}*/
	else if(mode==1) {
		isoDir = sceIoDopen("nethost0:/ISO");
	}
	else if(mode==2) {
		isoDir = sceIoDopen("nethost0:/PSP/GAME");
	}
	
	getRemoteList:
	if (isoDir >= 0)
	{
		while(sceIoDread(isoDir, &dir) > 0)
		{
			if(mode==0) 
			{
				if (!FIO_S_ISDIR(dir.d_stat.st_mode))
				{	
					strcpy(fullpath[isoCount], "host0:/ISO/");
					strcat(fullpath[isoCount], dir.d_name);				
					isoCount++;
					isoMax = isoCount;
					//printf("Path => %s Count => %i\n",fullpath[isoCount], isoCount);
				}
			}

			/*else if(mode==1) 
			{
				if (FIO_S_ISDIR(dir.d_stat.st_mode))
				{	
					strcpy(fullpath[isoCount], "host0:/PSP/GAME/");
					strcat(fullpath[isoCount], dir.d_name);
					strcat(fullpath[isoCount], "/eboot.pbp");
					isoCount++;
					isoMax = isoCount;
				}
			}*/	
			
			else if(mode==1) 
			{
				if (!FIO_S_ISDIR(dir.d_stat.st_mode))
				{
					strcpy(fullpath[isoCount], "nethost0:/ISO/");
					strcat(fullpath[isoCount], dir.d_name);				
					isoCount++;
					isoMax = isoCount;
					//printf("Path => %s Count => %i\n",fullpath[isoCount], isoCount);
				}
			}

			else if(mode==2) 
			{	
				if (FIO_S_ISDIR(dir.d_stat.st_mode))
				{
					if(strcmp(dir.d_name, ".")==0||strcmp(dir.d_name, "..")==0) 
					{
						printf("No");
					} 
					else
					{
						strcpy(fullpath[isoCount], "nethost0:/PSP/GAME/");
						strcat(fullpath[isoCount], dir.d_name);
						strcat(fullpath[isoCount], "/eboot.pbp");
						
						int fd = sceIoOpen(fullpath[isoCount], PSP_O_RDONLY, 0777);
						if(fd < 0) {
							printf("Could not write usbhost_iso.log");
							sceIoClose(fd);
						}
						else
						{
							isoCount++;
							isoMax = isoCount;
							sceIoClose(fd);
						}
					}
				}
			}
				
		} sceIoClose(isoDir);	
			
	} 
	else {
		if(mode==1||mode==2)
		{
			if(retry<2)
			{
				doBlit("Could not get remote list, retrying please wait");
				sceKernelDelayThread(100*100000);
				retry++;
				goto getRemoteList;
			}
			else
			{
				doBlit("Could not get remote list");
				goto end;
			}
		}
		else {
			doBlit("Could not get remote list");
			unloadUsbhost();
			goto end;
		}
	}
	
	while(!isoDone)
	{	
		
		showUsbhostMenu=1;
		
		sceCtrl_driver_C4AAD55F(&padIso, 1);
		
		if(ctrlWait>0) ctrlWait--;
		
		if(!ctrlWait) 
		{
			if(padIso.Buttons & PSP_CTRL_RTRIGGER)
			{
				num++;
				if(num==isoMax) num=0;
				ctrlWait=10;
			}
			
			if(padIso.Buttons & PSP_CTRL_LTRIGGER)
			{
				if(num==0) num=isoMax;
				num--;
				ctrlWait=10;
			}			
				
			if(padIso.Buttons & PSP_CTRL_HOME)
			{
				isoDone=1;
			}
			
			if(padIso.Buttons & PSP_CTRL_CIRCLE)
			{
				unloadUsbhost();
				showUsbhostMenu=0;
				break;
			}
		}
	
		sceDisplay_driver_B685BA36();
	}

	if(isoDone) {
	
		if(usbModules) unloadUsb();
		
		int fd = sceIoOpen("fatms0:/seplugins/cfe/game_path", PSP_O_CREAT | PSP_O_RDWR, 0777);
		if(fd < 0) printf("Could not write game_path");
		sceIoWrite(fd, fullpath[num], 128);
		sceIoClose(fd);
		
		nkThreadSuspend(sceKernelGetThreadId());
		execEboot("fatms0:/seplugins/cfe/usbiso_bootloader.elf");
	}
	
	end:
		return 0;
}

void streamMenu() {

	menuDone=0;
	int _mode = 0;
	int ctrlWait = 0;
	int proceed = 0;
	
	//nkThreadSuspend(sceKernelGetThreadId());
	
	showStreamMenu=1;
	
	while(!menuDone)
	{
		
		cleanBeforeExit();
		
		sceDisplay_driver_B685BA36();
		
		sceCtrl_driver_C4AAD55F(&pad, 1);
		
		if(ctrlWait>0) ctrlWait--;
		
		if(!ctrlWait) 
		{

			if (pad.Buttons != pad_old)
			{	
		
				if(pad.Buttons & PSP_CTRL_UP) 
				{
					if(showStreamMenu > 1)
					{
						showStreamMenu--;
						_mode--;
						ctrlWait=10;
					}
				}

				if(pad.Buttons & PSP_CTRL_DOWN) 
				{
					if(showStreamMenu < 3)
					{
						showStreamMenu++;
						_mode++;
						ctrlWait=10;
					}
				}
				
				if(pad.Buttons & PSP_CTRL_HOME) 
				{
					proceed=1;
					showStreamMenu=0;
					menuDone=1;
					
				}
				
				if(pad.Buttons & PSP_CTRL_CIRCLE) 
				{
					//nkThreadResume(sceKernelGetThreadId());
					showStreamMenu=0;
					menuDone=1;
				}
			}
		}
	}
	pad_old = pad.Buttons;
	sceKernelDelayThread(1000);
	
	if(proceed) getIso(_mode); // (0 = usbhost ISO) - (1 = usbhost GAME) - (2 = nethost ISO) - (3 = nethost GAME)
}

void setBrightness(int x)
{
	sceDisplay_driver_776ADFDB(x,0);
}

void checkUnloadBrowser() {

	SceUID thids[50];
	int thid_count = 0;
	int i;
	SceKernelThreadInfo thinfo;

	sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread,thids,50,&thid_count);
	for(i=0;i<thid_count;i++)
        {
		memset(&thinfo,0,sizeof(SceKernelThreadInfo));
		thinfo.size = sizeof(SceKernelThreadInfo);

		sceKernelReferThreadStatus(thids[i],&thinfo);

		if(strcmp(&thinfo.name[0],"SceHtmlViewer")==0)
		{
			webBrowserLoaded=1;

			//sceKernelTerminateDeleteThread(thids[i]);
		}
		/*if(strcmp(&thinfo.name[0],"SceNetCallout")==0)
		{
			sceKernelTerminateDeleteThread(thids[i]);
		}
		if(strcmp(&thinfo.name[0],"SceNetNetintr")==0)
		{
			sceKernelTerminateDeleteThread(thids[i]);
		}
		if(strcmp(&thinfo.name[0],"SceNetApctl")==0)
		{
			sceKernelTerminateDeleteThread(thids[i]);
		}
		if(strcmp(&thinfo.name[0],"SceHtmlViewerNetfront")==0)
		{
			sceKernelTerminateDeleteThread(thids[i]);
		}

		if(strcmp(&thinfo.name[0],"sceHtmlViewerHttp")==0)
		{

			sceKernelTerminateDeleteThread(thids[i]);

			unloadStopModule("sceHttpStorage_Service");
			unloadStopModule("sceSsl_Module");
			unloadStopModule("sceCert_Loader");
			unloadStopModule("sceDNAS_Library");
			unloadStopModule("sceDNASCore_lib");
			unloadStopModule("sceMcctrl");
			unloadStopModule("SceHttp_Library");
			unloadStopModule("SceParseURI_Library");
			unloadStopModule("SceParseHTTPheader_Library");
			//unloadStopModule("sceNetResolver_Library");
			//unloadStopModule("sceNetApctl_Library");
			//unloadStopModule("sceNetInet_Library");
			//unloadStopModule("sceNet_Library");
			//unloadStopModule("sceNetIfhandle_Service");
			unloadStopModule("sceHVAuth_Library");
			unloadStopModule("sceFont_Library_HV");
			unloadStopModule("sceHVSlim_Library");
			//unloadStopModule("sceHVUI_Module");
			unloadStopModule("sceHVWWW_Library");
			unloadStopModule("sceHVFlash_Module");
			unloadStopModule("sceHVNetfront_Module");
			//unloadStopModule("htmlviewer_plugin_module");
			
		}*/
	}
}

/*
int print_modinfo(SceUID uid)
{
	SceKernelModuleInfo info;
	int ret;
	char szString2[256] = "";

	int fd2 = sceIoOpen("ms0:/modlist.txt", PSP_O_WRONLY | PSP_O_APPEND, 0777); 

	memset(&info, 0, sizeof(info));
	info.size = sizeof(info);

	ret = sceKernelQueryModuleInfo(uid, &info);
	if(ret >= 0)
	{
		//printf("UID: 0x%08X Attr: %04X - Name: %s\n", uid, info.attribute, info.name);

		sceIoLseek(fd2, 0, SEEK_END);

		sprintf( szString2, &info.name);

		sceIoWrite(fd2, szString2, strlen(szString2) );

		sceIoLseek(fd2, 0, SEEK_END);

		sceIoWrite(fd2, "--", 2);	

	}
	sceIoClose(fd2);

	return ret;
}


int modlist()
{
	SceUID ids[100];
	int ret;
	int count;
	int i;

	memset(ids, 0, 100 * sizeof(SceUID));
	ret = sceKernelGetModuleIdList(ids, 100 * sizeof(SceUID), &count);
	if(ret >= 0)
	{
		for(i = 0; i < count; i++)
		{
			print_modinfo(ids[i]);
		}
	}

	return 0;
}
*/

/*int remapNethost()
{
	SceModule *mod;
	mod = sceKernelFindModuleByName("sceIOFileManager");
	if(mod == NULL)	printf("Hum ... sceIOFileManager module not found\n");
	u32 * addr;
	addr = (u32 *)(mod->gp_value+0x2b30);
	//printf("3.71 hack address : %x\n",addr);
	memset(addr, 0, 76);
	
	sceIoUnassign("ms0:");
	sceIoAssign("ms0:", "nethost0:", NULL, IOASSIGN_RDWR, NULL, 0);

	return 0;
}*/

int threadMain(SceSize args, void *argp)
{
	firstBoot = 1;
	state = 0;
	cleanExit = 1;
	
	read_config("fatms0:/seplugins/cfe/cfe.config", &config);
	sceKernelDelayThread(10000);
	
	while(!translateButtons()) {
		printf("waiting\n");
	}
	
	sceKernelDelayThread(20*100000);
	
	state = sceUsb_driver_C21645A4();
	if(config.enableUsbMass) loadUsb();
	
	cpuSpeed=config.defaultCpuSpeedVsh;
	setCpuSpeed();
	
	setBrightness(config.defaultBrightnessVsh);
	
	firstBoot=0;

	while(1) {
	
		state = sceUsb_driver_C21645A4();

		if(cleanExit) cleanBeforeExit();
		
		vshHook();
		
		if(stopSleepMode) scePower_driver_9C40E184(0);

		sceCtrl_driver_C4AAD55F(&pad, 1);
		
		if (pad.Buttons != pad_old)
		{		
			if(poweroffEnable) 
			{
				if((pad.Buttons & (poweroffButton_i | comboButton_i)) == (poweroffButton_i | comboButton_i))				
				{
					scePower_driver_9B1A9C5F();
				}
			}

			if(resetEnable) 
			{	
				if((pad.Buttons & (resetButton_i | comboButton_i)) == (resetButton_i | comboButton_i))
				{
					scePower_driver_E65F00BD();
				}	
			}
			
			if(cpuspeedEnable) {
				if((pad.Buttons & (cpuspeedButton_i | comboButton_i)) == (cpuspeedButton_i | comboButton_i))			
				{
					setCpuSpeed();
				}
			}

			if(maxBrightnessEnable) {	
				if((pad.Buttons & (maxBrightnessButton_i | comboButton_i)) == (maxBrightnessButton_i | comboButton_i))
				{
					setBrightness(99);
					doBlit("Brightness set to maximum value");
				}
			}

			if(usbhostUmdModeEnable) {
				if((pad.Buttons & (usbhostUmdModeButton_i | comboButton_i)) == (usbhostUmdModeButton_i | comboButton_i))
				{
					//doBlit("Loading Streaming Menu");
					
					streamMenu();
				}
			}
			
			if(takeScreenshotEnable) 
			{
				if((pad.Buttons & (takeScreenshotButton_i | comboButton_i)) == (takeScreenshotButton_i | comboButton_i))			
				{
					int plop = sceIoDopen(config.captureFolder);
	
					if (plop >= 0)
					{
						printf("Directory already exist\n");					
					} 
					else {
						sceIoMkdir(config.captureFolder, 0777);
					}
						
					screenshot();
					sprintf(strBuf0,"Screenshot saved to %s", file);
					doBlit(strBuf0);
				}	
			}
			
			if(showHelpEnable)
			{
				if((pad.Buttons & (showHelpButton_i | comboButton_i)) == (showHelpButton_i | comboButton_i))
				{
					helpMenu();
				}
			}
			
			if(startStopUsbmassEnable) {
				if((pad.Buttons & (startStopUsbmassButton_i | comboButton_i)) == (startStopUsbmassButton_i | comboButton_i))
				{
					loadUsb();				
				}
			}
			
			if(startFtpdEnable) {
				if((pad.Buttons & (startFtpdButton_i | comboButton_i)) == (startFtpdButton_i | comboButton_i))
				{
					checkUnloadBrowser();
					sceKernelDelayThread(5*10000);
					if(!webBrowserLoaded) {
						sctrlHENSetSpeed(333,166);
						loadStartModule("ms0:/seplugins/cfe/cfe_ftpd.prx", 0, NULL);
						stopSleepMode=1;
					}
				}
				if(pad.Buttons & PSP_CTRL_CIRCLE) stopSleepMode=0;
			}

			/*if(config.usePspSlim)
			{
				if(captureEnable) 
				{
					if((pad.Buttons & (captureButton_i | comboButton_i)) == (captureButton_i | comboButton_i))
					{
						doBlit("Enabling remotejoy video capture");
						loadStartModule("ms0:/seplugins/cfe/usbhostfs.prx", 0, NULL);
						
						sceKernelDelayThread(5*100000);
							
						loadStartModule("ms0:/seplugins/cfe/remotejoy_371.prx", 0, NULL);	
				
						doBlit("Done");	
					}
				}
			}*/		
			
			if((pad.Buttons & (PSP_CTRL_NOTE | PSP_CTRL_VOLUP)) == (PSP_CTRL_NOTE | PSP_CTRL_VOLUP))
			{
				loadNetHost();
				sceKernelDelayThread(80*100000);
				//remapNethost();
			}
		}
		pad_old = pad.Buttons;
		sceKernelDelayThread(1000);
	}
	return 0;
}

int module_start(SceSize args, void *argp)
{
	
	display_thid = sceKernelCreateThread("cfe_vsh_display", display_thread, 8, 0x400, 0, NULL);
	if(display_thid >= 0) sceKernelStartThread(display_thid, args, argp);
	
	nkLoad();
	
	main_thid = sceKernelCreateThread("cfe_vsh_main", threadMain, 6, 0x4000, 0, NULL);
	if(main_thid >= 0) sceKernelStartThread(main_thid, args, argp);

	return 0;

	sceKernelExitDeleteThread(0);
}

int module_stop(SceSize args, void *argp)
{
	return 0;
}
