/*****************************************************************************/

/*
 *      remote.c -- REALmagic Celeste Application
 *
 *      Copyright (C) 1999-2000 Sigma Designs
 *
 *      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, or
 *      (at your option) any later version.
 *
 *      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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*****************************************************************************/

#include "remote.h"

#ifdef PRINCETON
extern unsigned char Image6_0[];
extern unsigned char Image6_1[];
#endif

extern DWORD g_Pass;
extern unsigned char yuv_data[];
#define SPL_WIDTH 720
#define SPL_HEIGHT 480

#undef RELEASE_FOR_QA 

#define SCREEN_WIDTH	640
#define SCREEN_HEIGHT	480

ThINFO rem, kbd;
int rtID, ktID, omID, osdtID, ttID, aptID;

#ifdef PRINCETON

ThINFO rs232;
int rstID, swID;

#define RS_REPLY(f,s,t)             \
if(pInfo->bAns) {                   \
	OSWriteToPort(rs232.portID, STX); \
	OSWriteToPort(rs232.portID, f);   \
	OSWriteToPort(rs232.portID, s);   \
	OSWriteToPort(rs232.portID, t);   \
	OSWriteToPort(rs232.portID, ETX); \
	pInfo->bAns--;                    \
}

#define RS_REPLY_ERR(f,s,t)           \
if(pInfo->bAns) {                     \
	OSWriteToPort(rs232.portID, STX);   \
	OSWriteToPort(rs232.portID, 'E');   \
	OSWriteToPort(rs232.portID, 'R');   \
	OSWriteToPort(rs232.portID, f);     \
	OSWriteToPort(rs232.portID, s);     \
	OSWriteToPort(rs232.portID, t);     \
	OSWriteToPort(rs232.portID, ETX);   \
	pInfo->bAns--;                      \
}

#else

#define RS_REPLY(f,s,t)
#define RS_REPLY_ERR(f,s,t)

#endif



#define DIGITS_INPUT(x)                                                  \
if(pInfo->blk || pInfo->bSearch) {                                       \
	msg = x;                                                               \
	if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);             \
}                                                                        \
else {                                                                   \
	if ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) \
		pInfo->bSearch = 3;                                                  \
	else if(pInfo->bDiscType == FMPC_DVD_VIDEO)                            \
		if(FMPGet(FMPI_BUTTONS_AVAILABLE) >= (DWORD)(x - ZERO))                       \
			pInfo->bSearch = 2;                                                \
		else                                                                 \
			pInfo->bSearch = 1;                                                \
	msg = SHOW_SEARCH;                                                     \
	if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);             \
}

DWORD g_OutputMode = 0;

HDTV_PARAMS Hdtv_Params[] = {
// HSync VSync VidH  VidV  TotH PreH ActH PostH TotV PreV ActV PostV PixF Interlaced
{ 31500,  6000, 2160,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 37800,  7200, 1080,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 50400,  9600, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 63000, 12000,  720,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 45000,  6000,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 54000,  7200,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 72000,  9600,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 63000,  6000,  720,  960,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 75600,  7200,  720,  960,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0}
/*
{ 31500,  6000, 2160,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 37800,  7200, 2160,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 50400,  9600, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 63000, 12000, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 45000,  6000, 2160,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 54000,  7200, 1440,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 72000,  9600,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 63000,  6000, 1440,  960,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},
{ 75600,  7200,  720,  960,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0}
*/
};

HDTV_PARAMS Hdtv_Params_Init = { 31500,  6000,  720,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0 };

HDTV_PARAMS Hdtv_Params1[] = {
// HSync VSync VidH  VidV  TotH PreH ActH PostH TotV PreV ActV PostV PixF Interlaced
{ 31469, 5994,  640,  480,  800,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 0
{ 31500, 6000,  640,  480,  800,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 1
{ 45000, 6000,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 7
{ 31469, 5994, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//15

//{ 31500, 6000,  720,  480,  880,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 3
//{ 37800, 7200,  720,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 4
//{ 44955, 5994,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 6
//{ 45000, 6000,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 7

//{ 45000, 6000, 1280,  720, 1650,  70, 40, 260 , 750, 5,  5, 20, 0, 0},	//11
//{ 45000, 6000, 1280,  720, 1800,  70, 40, 350 , 750, 5,  5, 20, 0, 0},	//12
//{ 33750, 6000, 1920, 1080, 2200,  44, 44, 192, 1125, 4, 10, 30, 0, 0},	//19
};

/*
HDTV_PARAMS Hdtv_Params[] = {
// HSync VSync VidH  VidV  TotH PreH ActH PostH TotV PreV ActV PostV PixF Interlaced
{ 31469, 5994,  640,  480,  800,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 0
{ 31500, 6000,  640,  480,  800,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 1
{ 31469, 5994,  720,  480,  880,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 2
{ 31500, 6000,  720,  480,  880,  59, 16,  85 , 525, 6,  9, 30, 0, 0},	// 3
{ 37800, 7200,  720,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 4
{ 50400, 9600,  720,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 5
{ 44955, 5994,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 6
{ 45000, 6000,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 7
{ 54000, 7200,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 8
{ 72000, 9600,  720,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	// 9
{ 44955, 5994, 1280,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//10
{ 45000, 6000, 1280,  720, 1650,  70, 40, 260 , 750, 5,  5, 20, 0, 0},	//11
{ 45000, 6000, 1280,  720, 1800,  70, 40, 350 , 750, 5,  5, 20, 0, 0},	//12
{ 54000, 7200, 1280,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//13
{ 72000, 9600, 1280,  720,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//14
{ 31469, 5994, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//15
{ 31500, 6000, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//16
{ 37800, 7200, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//17
{ 50400, 9600, 1440,  480,    0,   0,  0,   0 ,   0, 0,  0,  0, 0, 0},	//18
{ 33750, 6000, 1920, 1080, 2200,  44, 44,  192,1125, 4, 10, 30, 0, 0},	//19
{ 33750, 6000, 1920, 1080, 2400, 144, 44,  292,1125, 4, 10, 30, 0, 0},	//20
{ 33750, 6000, 2160, 1080, 2440,  44, 44,  192,1125, 4, 10, 30, 0, 0},	//21
// special modes for Iggy
{ 60000, 7200, 1024,  768, 1280,   0,  0,   0 , 834, 0,  0,  0, 0, 0},	// 22 -> 76.8M
{ 60000, 7200,  720,  768,  900,   0,  0,   0 , 834, 0,  0,  0, 0, 0} 	// 23 -> 54M
};
*/

//----------------------------------------------------------------------------//
// Event_Notifications - This function receives events from the graph manager //
//----------------------------------------------------------------------------//
DWORD Event_Notifications (DWORD dwContext, DWORD dwMsg, DWORD dwValue)
{
	INFO *a;
	a = (INFO*)dwContext;

	switch (dwMsg)
	{
	case FMPM_ERROR:	
	case FMPM_STARVATION:
	case FMPM_EOS:
	case FMPM_REGION_MISMATCH:
		a->maddie = 1;
		if(a->msgQueue) {
			char msg = EJECT1;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	case FMPM_DVDROM_NOT_READY:
		if(a->msgQueue) {
			char msg = EJECT1;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	case FMPM_DVD_ANGLE_CHANGE:
		DPRINT(("Event: DVD Angle Change\n"));
		break;
	case FMPM_DVD_ANGLES_BLOCK:
		DPRINT(("Event: DVD Angles Block Change\n"));
		break;
	case FMPM_DVD_AUDIO_STREAM_CHANGE:
		DPRINT(("Event: DVD Audio Stream Change\n"));
		break;
	case FMPM_DVD_BUTTONS_CHANGE:
		DPRINT(("Event: DVD Buttons Change\n"));
		break;
	case FMPM_DVD_BUTTON_CHANGE:
		DPRINT(("Event: DVD Button Change\n"));
		break;
	case FMPM_DVD_PROGRAM_START:
		DPRINT(("Event: DVD Program Start\n"));
		break;
	case FMPM_DVD_CURRENT_TIME:
		if(a->playing != PLAYING || a->bABRepeat == 2) { //For the timer
//		{
			char msg;
/*
			printf("Event: DVD Current Time %2x:%2x:%2x:%x\r\n",
						 ((unsigned char *)(&dwValue))[0],
						 ((unsigned char *)(&dwValue))[1],
						 ((unsigned char *)(&dwValue))[2],
						 ((unsigned char *)(&dwValue))[3]);
*/
//			OSEnterCriticalSection(&(a->cS));
			if((dwValue & 0xffffff) ^ (a->dwTime & 0xffffff)) {
				a->dwTime = dwValue;
				if(a->osdFlag && a->osdMsgQ) {
					msg = EV_NOTE;
					OSPostMessage(a->osdMsgQ, &msg, 1);
				}
			}
			else {
				a->dwTime = dwValue;
			}
//			OSLeaveCriticalSection(&(a->cS));
		}
		break;
	case FMPM_DVD_DOMAIN_CHANGE:
		DPRINT(("Event: DVD Domain Change\n"));
		if(a->msgQueue) {
			char msg;
			if(dwValue == STOP_STATE) {
/*
				if(a->osdFlag) {
					a->osdFlag = 0;
					msg = SHOW_TIME;
					if(a->osdMsgQ) OSPostMessage(a->osdMsgQ, &msg, 1);
				}
*/
				msg = STOP_1;
				OSPostMessage(a->msgQueue, &msg, 1);
			}
			msg = TIME_ADJUST;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	case FMPM_DVD_NO_FP_PGC:
		DPRINT(("Event: DVD No FP PGC\n"));
		break;
	case FMPM_DVD_PARENTAL_LEVEL_CHANGE:
		DPRINT(("Event: DVD Parental Level Change\n"));
		break;
	case FMPM_DVD_PARENTAL_ERROR:
		DPRINT(("Event: DVD Parental Level Violation\n"));
		a->maddie = 2;
		if(a->msgQueue) {
			char msg = EJECT1;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	case FMPM_DVD_PARENTAL_CHECK:
	{
		BYTE msg;
		DPRINT(("Event: DVD Check Password for parental control level change\n"));
		if(g_Pass == 0xffffffff ||
		   FMPGetProfileWord(RMREG_PASSW_STATE) == RM_PASSWORD_OFF)
			return 0;
		if(a->osdMsgQ) {
			msg = SHOW_CHECK_PASSWORD;
			OSPostMessage(a->osdMsgQ, &msg, 1);
		}
		else
			return 0;
		a->blk = 1;
		do {
			a->symbol = GetSymbol(a->msgQueue, a);
			ReadLibrary(a);
		} while(!(a->test));
		msg = a->test >> 1;
		a->test = 0;
		return (DWORD)msg;
	}
	case FMPM_DVD_PLAYBACK_STOPPED:
		DPRINT(("Event: DVD Playback Stopped\n"));
		break;
	case FMPM_DVD_STILL_OFF:
		DPRINT(("Event: DVD Still Off\n"));
		break;
	case FMPM_DVD_STILL_ON:
		DPRINT(("Event: DVD Still On\n"));
		break;
	case FMPM_DVD_SUBPICTURE_STREAM_CHANGE:
		DPRINT(("Event: DVD Subpic Stream Change\n"));
		break;
	case FMPM_DVD_TITLE_CHANGE:
	{
		char msg;
		if(a->bDiscType == FMPC_CDDA) {
			DPRINT(("Event: CDDA track Change\n"));
		}
		else if(a->bDiscType == FMPC_VCD || a->bDiscType == FMPC_SVCD) {
			DPRINT(("Event: VCD track Change\n"));
		}
		else {
			DPRINT(("Event: DVD Title Change\n"));
		}
		if(a->msgQueue) {
			msg = TIME_ADJUST;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	}
	case FMPM_DVD_CHAPTER_CHANGE:
	{
		char msg;
		if(a->msgQueue) {
			msg = TIME_ADJUST;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		DPRINT(("Event: DVD Chapter Change\n"));
		if(a->playing == TRICK_MODE && dwValue == 0xffffffff) {
			DPRINT(("Event: DVD End of the trick mode\n"));
			a->playing = PLAYING;
			a->bFast = 0;
			if(a->osdMsgQ) {
				msg = SCR_OFF;
				OSPostMessage(a->osdMsgQ, &msg, 1);
			}
		}
		break;
	}
	case FMPM_TRICK_MODE_CHANGE:
	{
		char msg;
		if(a->msgQueue) {
			msg = TIME_ADJUST;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		DPRINT(("Event: Trick Mode Change\n"));
		if(a->playing == TRICK_MODE && dwValue == 0) {
			DPRINT(("Event: End of the trick mode\n"));
			a->playing = PLAYING;
			a->bFast = 0;
			if(a->osdMsgQ) {
				msg = SCR_OFF;
				OSPostMessage(a->osdMsgQ, &msg, 1);
			}
		}
		break;
	}
	case FMPM_DVD_VALID_UOPS_CHANGE:
		DPRINT(("Event: DVD VALID UOPS Change\n"));
		break;
	case FMPM_CDDA_PSD_END:
		DPRINT(("Event: CDDA End of the playback\n"));
		if(a->msgQueue) {
			BYTE msg = STOP_1;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	case FMPM_SVCD_PSD_END:
		DPRINT(("Event: SVCD End of the playback\n"));
		if(a->msgQueue) {
			BYTE msg = STOP_1;
			a->playing = VCD_WAITING;
			OSPostMessage(a->msgQueue, &msg, 1);
		}
		break;
	default:
		break;
	}
	return 0;
}
									
//-------------------------------------------------------------------------//
// ReadDigit - This function identifies input digits and returns the digit //
//-------------------------------------------------------------------------//
int ReadDigit(int entry) {
	int value = entry - ZERO;
	if (value < 0 || value > 9) return -1;
	return value;
}

//-------------------------------------------------------------------------------------//
// ReadLibrary - This function is a Library of behaviours attached to the symbols read //
//-------------------------------------------------------------------------------------//
HRESULT ReadLibrary(INFO *pInfo) {

	char msg;
//timer
	int pl_tmp = pInfo->playing;
	
	switch(pInfo->symbol) {    // identify symbol
	case TIME_ADJUST:
		if(pInfo->bDiscType == FMPC_DVD_VIDEO ||
		   pInfo->bDiscType == FMPC_CDDA) {
			DWORD timeInfo[2];
			OSSleep_s(1);
			DVDQueryAttribute(DVDI_TIME, (DWORD)(timeInfo));
			timeInfo[0] = (timeInfo[0] << 16) | (timeInfo[0] >> 16);
			timeInfo[1] = (timeInfo[1] << 16) | (timeInfo[1] >> 16);
			timeInfo[0] = ((timeInfo[0] << 8) & 0xff00ff00) | ((timeInfo[0] >> 8) & 0xff00ff);
			timeInfo[1] = ((timeInfo[1] << 8) & 0xff00ff00) | ((timeInfo[1] >> 8) & 0xff00ff);
			pInfo->totalTime = timeInfo[0];
			pInfo->dwTime = timeInfo[1];
		}
		else if(pInfo->bDiscType == FMPC_VCD ||
		        pInfo->bDiscType == FMPC_SVCD) {
			BYTE h, m, s;
			DWORD secs = FMPGet(FMPI_TOTAL_TRACK_TIME);
			h = secs / 3600;
			m = (secs % 3600) / 60;
			s = (secs % 60);
			pInfo->totalTime = (((h / 10) << 4) | (h % 10) |
			                    ((DWORD)(m / 10) << 12) | ((DWORD)(m % 10) << 8) |
			                    ((DWORD)(s / 10) << 20) | ((DWORD)(s % 10) << 16)) & 0xffffff;
			secs = FMPGet(FMPI_CURRENT_TIME);
			h = secs / 3600;
			m = (secs % 3600) / 60;
			s = (secs % 60);
			pInfo->dwTime = (((h / 10) << 4) | (h % 10) |
			                 ((DWORD)(m / 10) << 12) | ((DWORD)(m % 10) << 8) |
			                 ((DWORD)(s / 10) << 20) | ((DWORD)(s % 10) << 16)) & 0xffffff;
		}
		if(pInfo->osdFlag && pInfo->osdMsgQ) {
			msg = SCR_OFF;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case ZERO:		// 0
//		FMPSetDestination (0, 0, 100, 100);
		if(pInfo->blk || pInfo->bSearch) {
			msg = ZERO;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case ONE:		// 1: VCDNumericSelection()
	case TWO:		// 2
	case THREE:	// 3
	case FOUR:	// 4
	case FIVE:	// 5
	case SIX:		// 6
	case SEVEN:	// 7
	case EIGHT:	// 8
	case NINE:	// 9
		DIGITS_INPUT(pInfo->symbol);
		break;
	case VGA_TV:		// VGA/TV
		if(pInfo->bMode || pInfo->bSearch) {
			msg = VGA_TV;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bABRepeat) {
			msg = SHOW_AB_REPEAT;
			if(pInfo->bABRepeat == 1) {
       	ClearRepeatAB(); //Cancels ABRepeat
				RS_REPLY('M','R','P');
				pInfo->bABRepeat = 0;
			}
			else {
 				RepeatAB(); //Stops ABRepeat
				RS_REPLY('M','R','P');
				pInfo->bABRepeat = 0;
			}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bRepeat) {
			msg = SHOW_REPEAT;
			if(pInfo->bRepeat == 1) {
				RepeatTitle(); //Stops Repeat Title
				RS_REPLY('M','R','P');
				pInfo->bRepeat = 0;
			}
			else {
				RepeatChapter(); //Stops Repeat Chapter
				RS_REPLY('M','R','P');
				pInfo->bRepeat = 0;
			}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case ENT:     //ENT		
		if(pInfo->blk) {
			msg = SHOW_HIDDEN;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		if(pInfo->bSearch) {
			msg = ENT;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case L_R:		// L-R
		if(pInfo->bDiscType == FMPC_DVD_VIDEO) {
/*
			if(pInfo->playing == PAUSED) {
				if(FMPStep(1)) {
					RS_REPLY('2','7','8');
					msg = SHOW_ERROR;
				}
				else {
					RS_REPLY('O','T','F');
					msg = SHOW_STEPRW;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				RS_REPLY_ERR('2','7','8');
			}
			else {
*/
				LONG sp = (LONG)FMPGet(FMPI_CURRENT_SPEED);
				if(sp > 0) {
					sp = 0;
					ForwardScan(sp, pInfo->bFast);
				}
				sp = (sp + 2) & 3;
				DPRINT(("DVD SLOW BACKWARD: %dx\n", sp));
				if(BackwardScan(sp, 0) != DVDE_UNAUTHORIZED) {
					if(!sp)
						pInfo->playing = PLAYING;
					else
						pInfo->playing = TRICK_MODE;
					pInfo->bFast = 0;
					RS_REPLY('O','M','R');
					msg = SHOW_SLOWRW;
				}
				else {
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
/*
			}
*/
		}
		break;

#define BUTTON_PRESSED(symb, act)                            \
if(pInfo->blk || pInfo->bMode) {                             \
	RS_REPLY('O','D','V');                                     \
	msg = symb;                                                \
	if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1); \
}                                                            \
else if(pInfo->bDiscType == FMPC_DVD_VIDEO) {                \
	act##ButtonSelect();                                       \
	RS_REPLY('O','D','V');                                     \
}                                                            \
break;

	case UP:		// UP
		BUTTON_PRESSED(UP, Upper)
	case LEFT:		// Left
		BUTTON_PRESSED(LEFT, Left)
	case DOWN:		// Down
		BUTTON_PRESSED(DOWN, Lower)
	case RIGHT:		// Right
		BUTTON_PRESSED(RIGHT, Right)
	case SEL:		// Sel
		if(pInfo->blk) {
			msg = SEL;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			ButtonActivate();
			pInfo->playing = PLAYING;
			msg = SCR_OFF;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case BREAK:
//		FMPEnableOverlay (0);
		if(pInfo->osdFlag) {
			pInfo->osdFlag = 0;
			if(pInfo->osdMsgQ) {
				msg = SHOW_TIME;
				OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
		}
		FMPStop();
		FMPClose();
		pInfo->playing = CLOSED;
		RS_REPLY('O','C','L');
		break;
	case COMPUTER:		// Computer: Setup Menu
		if(pInfo->playing == CLOSED) {
			pInfo->blk = 1;
			msg = SHOW_MENU;
			if(pInfo->osdMsgQ)
				OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bSearch < 2 /*&&
		        (pInfo->bDiscType == FMPC_CDDA || pInfo->bDiscType == FMPC_DVD_VIDEO)*/) {
			pInfo->bSearch = 1;
			pInfo->symbol = '_';
			msg = SHOW_SEARCH;
			if(pInfo->osdMsgQ)
				OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case SHOW_SEARCH:
		if(pInfo->bSearch == 3 && pInfo->dwSearch) {
			if(NumericSelections((BYTE)pInfo->dwSearch) != S_OK) {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
			else {
				RS_REPLY('S','R','P');
			}
		}
		else if(pInfo->bSearch == 2) {
			if(pInfo->dwSearch <= FMPGet(FMPI_BUTTONS_AVAILABLE) && pInfo->dwSearch) {
				ButtonSelectAndActivate((BYTE)pInfo->dwSearch);
				RS_REPLY('O','D','V');
				DPRINT(("Button %d selected\n", pInfo->dwSearch));
				pInfo->playing = PLAYING;
				msg = SCR_OFF;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
			else {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
		}
		else {
			DWORD res;
			if(pInfo->dwSearch) {
				DPRINT(("Search for "));
//timer
				pInfo->playing = UNDETERMINED;
//
				if(!(pInfo->dwSearch >> 24)) { //play title
					DPRINT(("title %d\n", pInfo->dwSearch));
					res = TitlePlay(pInfo->dwSearch & 0xffffff);
					if(res == S_OK) {
						RS_REPLY('S','R','P');
						pInfo->playing = PLAYING;
					}
					else {
						RS_REPLY_ERR('2','7','8');
						msg = SHOW_ERROR;
						if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
//timer
						pInfo->playing = pl_tmp;
//
					}
				}
				else if((pInfo->dwSearch >> 24) == 1) { //play chapter (current title)
					DPRINT(("chapter %d\n", pInfo->dwSearch));
					res = ChapterSearch((BYTE)(pInfo->dwSearch & 0xff));
					if(res != DVDE_UNAUTHORIZED && res != DVDE_PTTNUMBER) {
						RS_REPLY('S','R','P');
						pInfo->playing = PLAYING;
					}
					else {
						RS_REPLY_ERR('2','7','8');
						msg = SHOW_ERROR;
						if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
//timer
						pInfo->playing = pl_tmp;
//
					}
				}
				else if((pInfo->dwSearch >> 24) == 2) {
					TCHAR cdda_time[12];
					_stprintf((TCHAR*)cdda_time, TEXT("%02x:%02x:%02x:00"),
					        pInfo->dwSearch & 0xff,
									(pInfo->dwSearch >> 8) & 0xff,
					        (pInfo->dwSearch >> 16) & 0xff);
//timer
					pInfo->playing = pl_tmp;
//
					DPRINT(("time %s\n", cdda_time));
					if(pInfo->bDiscType == FMPC_CDDA)
						res = TimeSearch(cdda_time);
					else
						res = TimeSearch((TCHAR *)(pInfo->dwSearch & 0xffffff));
					if(res != DVDE_UNAUTHORIZED && res != DVDE_ARG) {
						RS_REPLY('S','R','P');
						OSSleep_t(10); //Need to wait for the correct time
						if(pInfo->msgQueue) {
							msg = TIME_ADJUST;
							OSPostMessage(pInfo->msgQueue, &msg, 1);
						}
					}
					else {
						RS_REPLY_ERR('2','7','8');
						msg = SHOW_ERROR;
						if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					}
				}
			}
		}
		pInfo->bSearch = 0;
		break;
	case MENU:		// Menu: ReturnPGSearch
		if((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
			ReturnPGSearch();
			pInfo->playing = PLAYING;
			msg = SCR_OFF;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_DVD_VIDEO) {
			if(MenuCall(DVD_ROOT_ID) == DVDE_UNAUTHORIZED) { //DVD_ROOT_ID = 3
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
			else {
				RS_REPLY('O','D','V');
				pInfo->playing = PLAYING;
				msg = SCR_OFF;
				OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
		}
		break;
	case TITLE:		// Title
		if((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
			DefaultPGSearch();
			pInfo->playing = PLAYING;
			msg = SCR_OFF;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_DVD_VIDEO) {
			if(MenuCall(DVD_TITLE_ID) == DVDE_UNAUTHORIZED) { //DVD_TITLE_ID = 4
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
			else {
				RS_REPLY('O','D','V');
				pInfo->playing = PLAYING;
				msg = SCR_OFF;
				OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			}
		}
		break;
	case PLAYER:		// Player : Shows title, chapter and time
		if(pInfo->playing != CLOSED) {
			pInfo->osdFlag = !pInfo->osdFlag;
			msg = SHOW_TIME;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case OSD:		// OSD
		if(pInfo->blk) {
			msg = SHOW_PREV;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case LANGUAGE:		// Language
		if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			if(!pInfo->bAudioStream) {
				pInfo->bAudioStream = (BYTE)FMPGet(FMPI_CURRENT_AUDIO_STREAM) + 1;
				if (pInfo->bAudioStream >= FMPGet(FMPI_AUDIO_STREAMS_AVAILABLE))
					pInfo->bAudioStream = 0;
			}
			else {
				pInfo->bAudioStream--;
				if (pInfo->bAudioStream >= FMPGet(FMPI_AUDIO_STREAMS_AVAILABLE)) {
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
					pInfo->bAudioStream = 0;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					break;
				}
			}
			DPRINT(("DVD LANGUAGE %d\n", pInfo->bAudioStream));
			if(AudioStreamChange (pInfo->bAudioStream) != DVDE_UNAUTHORIZED) {
				RS_REPLY('A','S','T');
				msg = SHOW_LANGUAGE;
			}
			else {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
			}
			pInfo->bAudioStream = 0;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		if ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
			AudioStreamChange(0);		
			DPRINT(("VCD LANGUAGE\n"));
		}
		break;
	case ANGLE:		// Angle
		if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			if(!pInfo->bAngleNumber) {
				pInfo->bAngleNumber = (BYTE)FMPGet(FMPI_CURRENT_ANGLE) + 1;
				if (pInfo->bAngleNumber > FMPGet(FMPI_ANGLES_AVAILABLE))
					pInfo->bAngleNumber = 1;
			}
			DPRINT(("DVD ANGLE %d\n", pInfo->bAngleNumber));
			if(!AngleChange(pInfo->bAngleNumber)) {
				RS_REPLY('V','A','G');
				msg = SHOW_ANGLE;
			}
			else {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
			}
			pInfo->bAngleNumber = 0;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case SUBTITLE:		// Sub-title
		if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			DWORD currSP = FMPGet(FMPI_CURRENT_SUBPICT_STREAM);
			if(pInfo->bSPStream == 0xff) {
				if ((currSP + 1) >= FMPGet(FMPI_SUBPICTURE_STREAM_AVAILABLE))
					if(FMPGet(FMPI_SUBPICTURE_ON))
						pInfo->bSPStream = 0;
					else {
						currSP = 0;
						pInfo->bSPStream = 99;
					}
				else if(FMPGet(FMPI_SUBPICTURE_ON))
					pInfo->bSPStream = (BYTE)currSP + 1;
				else
					pInfo->bSPStream = 99;
			}
			else if(pInfo->bSPStream != 99 && pInfo->bSPStream > 1)
				pInfo->bSPStream--;
			else if(pInfo->bSPStream == 1) {
				currSP = 0;
				pInfo->bSPStream = 99;
			}
			if(!pInfo->bSPStream) {
				DPRINT(("DVD SUB-TITLE off\n"));
				if(SubPictureStreamChange((BYTE)currSP, 0) != DVDE_UNAUTHORIZED) {
					RS_REPLY('X','S','T');
					msg = SHOW_SUBTITLE;
				}
				else {
					msg = SHOW_ERROR;
					RS_REPLY_ERR('2','7','8');
				}
			}
			else {
				if(pInfo->bSPStream == 99)
					pInfo->bSPStream = (BYTE)currSP;
				if (pInfo->bSPStream >= FMPGet(FMPI_SUBPICTURE_STREAM_AVAILABLE)) {
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
					pInfo->bSPStream = 0xff;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					break;
				}
				DPRINT(("DVD SUB-TITLE %d\n", pInfo->bSPStream));
				if(SubPictureStreamChange(pInfo->bSPStream, 1) != DVDE_UNAUTHORIZED) {
					RS_REPLY('X','S','T');
					msg = SHOW_SUBTITLE;
				}
				else {
					msg = SHOW_ERROR;
					RS_REPLY_ERR('2','7','8');
				}
			}
			pInfo->bSPStream = 0xff;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}		
		break;
	case PLAY_PAUSE:		// Play/Pause: if playing: FMPPause(), if not playing, FMPPlay()
	{
		WORD reg_tmp = (WORD)FMPGet(FMPI_CURRENT_DOMAIN);
		if((FMPGet(FMPI_CURRENT_DOMAIN) & 0x10000) &&
		   reg_tmp != VMGM_DOM && reg_tmp != VTSM_DOM) {
//timer
			pInfo->playing = UNDETERMINED;
//
			if(StillOff() == DVDE_UNAUTHORIZED) {
				msg = SHOW_ERROR;
				pInfo->playing = pl_tmp;
			}
			else {
				msg = SHOW_PLAY;
				pInfo->playing = PLAYING;
			}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if ((pInfo->playing == STOPPED) || (pInfo->playing == PAUSED) ||
		         (pInfo->playing == TRICK_MODE_PAUSED)) {
			msg = SHOW_PLAY;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			FMPPlay();
			if(pInfo->playing == TRICK_MODE_PAUSED)
				pInfo->playing = TRICK_MODE;
			else
				pInfo->playing = PLAYING;
			RS_REPLY('O','P','L');
		}	
		else if (pInfo->playing == STOP_FOR_RESUME) {
			if ((pInfo->bDiscType == FMPC_DVD_VIDEO) ||
			    (pInfo->bDiscType == FMPC_VCD) ||
			    (pInfo->bDiscType == FMPC_SVCD)) {
				msg = SHOW_PLAY;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
//				Resume();
				FMPPlay(); //!!!
			}
			RS_REPLY('O','P','L');
			pInfo->playing = PLAYING;
		}
		else if (pInfo->playing == CLOSED) {
			if(FMPTrayOperation(FMPT_TRAYCHECK) == FMPT_TRAYOPEN) {
				msg = SHOW_CLOSE;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				FMPTrayOperation(FMPT_TRAYCLOSE);
				RS_REPLY('O','E','J');
			}
			StartPlaying(pInfo);
			RS_REPLY('O','S','A');
			if(pInfo->bDiscType == FMPC_CDDA) {
				FMPSet(FMPI_LEFT_VOLUME, 60);
				FMPSet(FMPI_RIGHT_VOLUME, 60);
				pInfo->totalTime = 0xffffffff;
				pInfo->dwTime = 0;
				msg = SHOW_TIME;
				pInfo->osdFlag = 1;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				msg = TIME_ADJUST;
				if(pInfo->msgQueue) OSPostMessage(pInfo->msgQueue, &msg, 1);
			}
			else if(pInfo->bDiscType == FMPC_VCD ||
			        pInfo->bDiscType == FMPC_SVCD) {
				FMPSet(FMPI_LEFT_VOLUME, 80);
				FMPSet(FMPI_RIGHT_VOLUME, 80);
			}
		}
		else {
			msg = SHOW_PAUSE;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			FMPPause();
			if(pInfo->playing == TRICK_MODE)
				pInfo->playing = TRICK_MODE_PAUSED;
			else
				pInfo->playing = PAUSED;
			RS_REPLY('O','P','A');
		}
		break;
	}
	case STOP_1:		// Stop: FMPStop()
		if(pInfo->playing != CLOSED) {
			if(pInfo->playing == VCD_WAITING &&
			   (pInfo->bDiscType == FMPC_VCD || pInfo->bDiscType == FMPC_SVCD)) {
				DWORD tmp0, tmp1;
				WORD tmp2;
				if(pInfo->osdFlag) {
					pInfo->osdFlag = 0;
					if(pInfo->osdMsgQ) {
						msg = SHOW_TIME;
						OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					}
				}
				tmp0 = FMPGet(FMPI_SVCD_CURRENT_VOLUME);
				tmp1 = FMPGet(FMPI_SVCD_VOLUMES_AVAILABLE);
				FMPStop();
				FMPClose();
				pInfo->playing = CLOSED;
//Before showing splash screen we return to 720x480 resolution
				if(pInfo->IHdtv_c)
					IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
				if(pInfo->pIOsd) IOsd_ShowSplash(pInfo->pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
				if(tmp0 < tmp1) {
					FMPTrayOperation(FMPT_TRAYOPEN);
					if(pInfo->osdMsgQ) {
						msg = SHOW_SVCD_WAITING;
						OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					}
				}
			}
			else if(pInfo->playing == STOP_FOR_RESUME || pInfo->playing == STOPPED) {
				WORD tmp;
				VIDEO_MODE vm;
				if(pInfo->osdFlag) {
					pInfo->osdFlag = 0;
					if(pInfo->osdMsgQ) {
						msg = SHOW_TIME;
						OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					}
				}
				msg = SHOW_STOP2;
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				if(pInfo->bDiscType == FMPC_DVD_VIDEO)
					DVDQueryAttribute(DVDI_VIDEO_MODE, (DWORD)(&vm));
				else
					vm.bAspectRatio = ASPECT_RATIO_4_3;
				FMPStop();
				FMPClose();
				pInfo->playing = CLOSED;

				if(vm.bAspectRatio != ASPECT_RATIO_4_3 && pInfo->pIHdtv)
					IHdtv_SetAspectRatio(pInfo->pIHdtv,4,3,5);

//Before showing splash screen we return to 720x480 resolution
				if(pInfo->IHdtv_c)
					IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
				if(pInfo->pIOsd) IOsd_ShowSplash(pInfo->pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
				RS_REPLY('O','S','P');
			}
			else {
				if ((pInfo->bDiscType == FMPC_DVD_VIDEO) ||
						(pInfo->bDiscType == FMPC_VCD) ||
						(pInfo->bDiscType == FMPC_SVCD)) {
//					StopForResume();
					if(pInfo->playing == TRICK_MODE ||           //!!!
					   pInfo->playing == TRICK_MODE_PAUSED) {    //!!!
						if(((LONG)FMPGet(FMPI_CURRENT_SPEED)) > 0) //!!!
							if(pInfo->bDiscType == FMPC_DVD_VIDEO)   //!!!
								ForwardScan(0, pInfo->bFast);          //!!!
							else                                     //!!!
								FastForward(0);                        //!!!
						else                                       //!!!
							if(pInfo->bDiscType == FMPC_DVD_VIDEO)   //!!!
								BackwardScan(0, pInfo->bFast);         //!!!
							else                                     //!!!
								Rewind(0);                             //!!!
						pInfo->bFast = 0;                          //!!!
					}                                            //!!!
					FMPPause();                                  //!!!
					pInfo->playing = STOP_FOR_RESUME;
					if(pInfo->bABRepeat) {
						ClearRepeatAB(); //!!!
						pInfo->bABRepeat = 0;
						msg = SHOW_AB_REPEAT;
						if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
						OSSleep_t(30);
					}
					else if(pInfo->bRepeat) {
						if(pInfo->bRepeat == 1) //!!!
							RepeatTitle();        //!!!
						else                    //!!!
							RepeatChapter();      //!!!
						pInfo->bRepeat = 0;
						msg = SHOW_REPEAT;
						if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
						OSSleep_s(1);
					}
					msg = SHOW_STOP;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				}
				else if(pInfo->bDiscType == FMPC_CDDA) {
					WORD tmp;
					msg = SHOW_STOP2;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					FMPStop();
					FMPClose();
					pInfo->playing = CLOSED;
//Before showing splash screen we return to 720x480 resolution
					if(pInfo->IHdtv_c)
						IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
					if(pInfo->pIOsd) IOsd_ShowSplash(pInfo->pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
					pInfo->osdFlag = 0;
				}
				RS_REPLY('O','S','P');
			}
		}
		else {
			msg = SHOW_STOP2;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		break;
	case STEP_PLAY:		// Step play
		{
/*
			int key, digit;
			int power = 0, i;
			int time[4];
			ULONG time_return;

			if ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
				DPRINT(("Time Search: "));
				OSPurgeMQ(pInfo->msgQueue);
				key = GetSymbol(pInfo->msgQueue, NULL); // get first digit
				while (power <= 4) {                  // while not cancelled or finished
					if ((key == VGA_TV) && (power > 0)) {  // if rewind pressed .. delete last digit entered
						power--;
						DPRINT(("\n"));
						for (i = 0; i < power; i++) DPRINT(("%d", time[i]));
					}
					else
						if ((key == ENT) && (power < 4)) break;					
						else
							if ((key == ENT) && (power == 4)) {
								time_return = 1000 * time[0] + 100 * time[1] + 10 * time[2] + time[3];
								//TimeSearch (time_return);	// do a time search
								break;
							}
							else
								if (power < 4) {
									digit = ReadDigit(key);		// get the digit
									if (digit != -1 && (((power != 0) && (power != 2)) || digit < 6)) {
											// if digit correct
										DPRINT(("%d", digit));
										time[power] = digit;
										power++;
									}
									if (digit == -1) {
										pInfo->maddie = TRUE;
										pInfo->symbol = key;
										break;
									}
								}	
					if ((power <= 4) && (key != ENT))	{    // if not four digits are entered
						OSPurgeMQ(pInfo->msgQueue);
						key = GetSymbol(pInfo->msgQueue, NULL);
					}
				}
			}
			else
*/
			if(pInfo->bDiscType == FMPC_DVD_VIDEO) {
				if(pInfo->playing == PAUSED) {
				DPRINT(("Step forward\n"));
					if(FMPStep(1)) {
						RS_REPLY('2','7','8');
						msg = SHOW_ERROR;
					}
					else {
						RS_REPLY('O','T','F');
						msg = SHOW_STEPFF;
					}
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				}
				else {
					LONG sp = (LONG)FMPGet(FMPI_CURRENT_SPEED);
					if(sp < 0) {
						sp = 0;
						BackwardScan (sp, pInfo->bFast);
					}
					sp = (sp + 2) % 10;
					DPRINT(("DVD SLOW FORWARD: %dx\n", sp));
					if(ForwardScan (sp, 0) != DVDE_UNAUTHORIZED) {
						if(!sp)
							pInfo->playing = PLAYING;
						else
							pInfo->playing = TRICK_MODE;
						pInfo->bFast = 0;
						RS_REPLY('O','M','F');
						msg = SHOW_SLOWFF;
					}
					else {
						RS_REPLY_ERR('2','7','8');
						msg = SHOW_ERROR;
					}
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				}
			}
		}
		break;
	case EJECT:		// Eject
		if (FMPTrayOperation(FMPT_TRAYCHECK) == FMPT_TRAYCLOSE) {
			WORD tmp;
			if(pInfo->playing != CLOSED) {
				VIDEO_MODE vm;
				if(pInfo->osdFlag) {
					pInfo->osdFlag = 0;
					if(pInfo->osdMsgQ) {
						msg = SHOW_TIME;
						OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					}
				}
				if(pInfo->bDiscType == FMPC_DVD_VIDEO)
					DVDQueryAttribute(DVDI_VIDEO_MODE, (DWORD)(&vm));
				else
					vm.bAspectRatio = ASPECT_RATIO_4_3;
				FMPStop();
				FMPClose();
				pInfo->playing = CLOSED;
				if(vm.bAspectRatio != ASPECT_RATIO_4_3 && pInfo->pIHdtv)
					IHdtv_SetAspectRatio(pInfo->pIHdtv,4,3,5);
//Before showing splash screen we return to 720x480 resolution
				if(pInfo->IHdtv_c)
					IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
				if(pInfo->pIOsd) IOsd_ShowSplash(pInfo->pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
			}
			msg = SHOW_OPEN;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			FMPTrayOperation(FMPT_TRAYOPEN);
			RS_REPLY('O','E','J');
		}
		else {
			msg = SHOW_CLOSE;
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
			FMPTrayOperation(FMPT_TRAYCLOSE);
			RS_REPLY('O','E','J');
		}
		break;
	case EJECT1:		// Eject
	{
		WORD tmp;
		if(pInfo->playing != CLOSED) {
			VIDEO_MODE vm;
			if(pInfo->osdFlag) {
				pInfo->osdFlag = 0;
				if(pInfo->osdMsgQ) {
					msg = SHOW_TIME;
					OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				}
			}
			if(pInfo->bDiscType == FMPC_DVD_VIDEO)
				DVDQueryAttribute(DVDI_VIDEO_MODE, (DWORD)(&vm));
			else
				vm.bAspectRatio = ASPECT_RATIO_4_3;
			FMPStop();
			FMPClose();
			pInfo->playing = CLOSED;
			if(vm.bAspectRatio != ASPECT_RATIO_4_3 && pInfo->pIHdtv)
				IHdtv_SetAspectRatio(pInfo->pIHdtv,4,3,5);
//Before showing splash screen we return to 720x480 resolution
				if(pInfo->IHdtv_c)
					IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
			if(pInfo->pIOsd) IOsd_ShowSplash(pInfo->pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
		}
		if(pInfo->maddie)
			msg = SHOW_ERROR;
		else
			msg = SHOW_OPEN;
		if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		break;
	}
	case REW:		// Rewind
		if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			LONG sp = (LONG)FMPGet(FMPI_CURRENT_SPEED);
			if(sp > 0) {
				sp = 0;
				ForwardScan ((WORD)sp, pInfo->bFast);
			}
			sp = -sp;
			sp = (sp + 2) % 10;
			DPRINT(("DVD REVERSE: %dx\n", sp));
			if(BackwardScan ((WORD)sp, 1) != DVDE_UNAUTHORIZED) {
				if(!sp) {
					pInfo->bFast = 0;
					pInfo->playing = PLAYING;
				}
				else {
					pInfo->playing = TRICK_MODE;
					pInfo->bFast = 1;
				}
				RS_REPLY('O','C','R');
				msg = SHOW_REVERSE;
			}
			else {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
			}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
			LONG speed;
			DPRINT(("VCD REWIND\n"));
			msg = SHOW_REVERSE;
			speed = (LONG)FMPGet(FMPI_CURRENT_SPEED);
			if(speed > 0) {
				FastForward(0);
				speed = 0;
			}
			speed--;
			speed = -speed;
			if(speed == 4)
				speed = 0;
			Rewind((BYTE)speed);
			if(speed) {
				pInfo->playing = TRICK_MODE;
				pInfo->bFast = 1;
			}
			else {
				pInfo->playing = PLAYING;
				pInfo->bFast = 0;
			}
			RS_REPLY('O','C','R');
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_CDDA) {
//???????
		}
		break;
	case FF:		// Fast Forward
		if (pInfo->bDiscType == FMPC_DVD_VIDEO) {
			LONG sp = (LONG)FMPGet(FMPI_CURRENT_SPEED);
			if(sp < 0) {
				sp = 0;
				BackwardScan ((WORD)sp, pInfo->bFast);
			}
			sp = (sp + 2) % 10;
			DPRINT(("DVD FAST FORWARD: %dx\n", sp));
			if(ForwardScan ((WORD)sp, 1) != DVDE_UNAUTHORIZED) {
				if(!sp) {
					pInfo->bFast = 0;
					pInfo->playing = PLAYING;
				}
				else {
					pInfo->playing = TRICK_MODE;
					pInfo->bFast = 1;
				}
				RS_REPLY('O','C','F');
				msg = SHOW_NEXT;
			}
			else {
				RS_REPLY_ERR('2','7','8');
				msg = SHOW_ERROR;
			}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)) {
			LONG speed;
			DPRINT(("VCD FAST FORWARD\n"));
			msg = SHOW_NEXT;
			speed = (LONG)FMPGet(FMPI_CURRENT_SPEED);
			if(speed < 0) {
				Rewind(0);
				speed = 0;
			}
			speed++;
			if(speed == 4)
				speed = 0;
			FastForward((BYTE)speed);
			if(speed) {
				pInfo->playing = TRICK_MODE;
				pInfo->bFast = 1;
			}
			else {
				pInfo->playing = PLAYING;
				pInfo->bFast = 0;
			}
			RS_REPLY('O','C','F');
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_CDDA) {
//???????
		}
		break;
	case LAST_TRACK:		// Last track: PrevPGSearch()
//timer
		pInfo->playing = UNDETERMINED;
//
		switch(pInfo->bDiscType) {
			case FMPC_DVD_VIDEO :
				if(pInfo->bABRepeat) {
					ClearRepeatAB(); //!!!
					pInfo->bABRepeat = 0;
					msg = SHOW_AB_REPEAT;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					OSSleep_t(30);
				}
				if(PrevPGSearch() != DVDE_UNAUTHORIZED) {
					pInfo->playing = PLAYING;
					msg = SHOW_BACK;
					RS_REPLY('O','D','V');
				}
				else {
					pInfo->playing = pl_tmp;
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
			case FMPC_VCD :
			case FMPC_SVCD :
				pInfo->playing = PLAYING;
				if(pInfo->bABRepeat) {
					ClearRepeatAB(); //!!!
					pInfo->bABRepeat = 0;
					msg = SHOW_AB_REPEAT;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					OSSleep_t(30);
				}
				if(PrevPGSearch() == S_OK) {
					msg = SHOW_BACK;
					RS_REPLY('O','P','B');
				}
				else {
					pInfo->playing = pl_tmp;
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
			case FMPC_CDDA :
				pInfo->playing = PLAYING;
				if(CDDAPrevTrack() == S_OK) {
					msg = SHOW_BACK;
				}
				else {
					pInfo->playing = pl_tmp;
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
		}
		break;
	case NEXT_TRACK:		// Next track: NextPGSearch()
//timer
		pInfo->playing = UNDETERMINED;
//
		switch (pInfo->bDiscType) {
			case FMPC_DVD_VIDEO :
				if(pInfo->bABRepeat) {
					ClearRepeatAB(); //!!!
					pInfo->bABRepeat = 0;
					msg = SHOW_AB_REPEAT;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					OSSleep_t(30);
				}
				if(NextPGSearch() != DVDE_UNAUTHORIZED)	{
					pInfo->playing = PLAYING;
					RS_REPLY('O','D','V');
					msg = SHOW_SKIP;
				}
				else {
					pInfo->playing = pl_tmp;
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
			case FMPC_VCD :
			case FMPC_SVCD :
				pInfo->playing = PLAYING;
				if(pInfo->bABRepeat) {
					ClearRepeatAB(); //!!!
					pInfo->bABRepeat = 0;
					msg = SHOW_AB_REPEAT;
					if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
					OSSleep_t(30);
				}
				if(NextPGSearch() == S_OK) {
					RS_REPLY('O','P','B');
					msg = SHOW_SKIP;
				}
				else {
					pInfo->playing = pl_tmp;
					RS_REPLY_ERR('2','7','8');
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
			case FMPC_CDDA :
				pInfo->playing = PLAYING;
				if(CDDANextTrack() == S_OK) {
					msg = SHOW_SKIP;
				}
				else {
					pInfo->playing = pl_tmp;
					msg = SHOW_ERROR;
				}
				if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				break;
		}
		break;
	case VOL_MORE:		// Repear title/chapter
		if((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD) ||
		   (pInfo->bDiscType == FMPC_DVD_VIDEO)) {
			msg = SHOW_REPEAT;
			if(!(pInfo->bRepeat) &&
			   ((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD)))
				pInfo->bRepeat++;
			if(pInfo->bRepeat == 0)
				if(RepeatTitle() == DVDE_UNAUTHORIZED) {
					msg = SHOW_ERROR;
					RS_REPLY_ERR('2','7','8');
				}
				else {
					RS_REPLY('M','R','P');
					pInfo->bRepeat = 1;
					pInfo->bABRepeat = 0;
				}
			else if(pInfo->bRepeat == 2 || pInfo->bRepeat == 1)
				if(RepeatChapter() == DVDE_UNAUTHORIZED) { //Also stops RepeatTitle or RepeatChapter
					msg = SHOW_ERROR;
					RS_REPLY_ERR('2','7','8');
				}
				else {
					RS_REPLY('M','R','P');
					pInfo->bRepeat = 4 - (pInfo->bRepeat << 1);
					pInfo->bABRepeat = 0;
				}
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_CDDA) {
			DWORD l, r;			
			l = FMPGet(FMPI_LEFT_VOLUME);
			r = FMPGet(FMPI_RIGHT_VOLUME);
			FMPSet (FMPI_LEFT_VOLUME, l + 10);
			FMPSet (FMPI_RIGHT_VOLUME, r + 10);
			l = FMPGet (FMPI_LEFT_VOLUME);
			r = FMPGet (FMPI_RIGHT_VOLUME);
			DPRINT(("VOL+ (%d, %d)\n", r, l));
		}
		break;
	case VOL_LESS:		// Vol-
		if((pInfo->bDiscType == FMPC_VCD) || (pInfo->bDiscType == FMPC_SVCD) ||
		   (pInfo->bDiscType == FMPC_DVD_VIDEO)) {
			msg = SHOW_AB_REPEAT;
//timer
			if(pl_tmp == PLAYING && (pInfo->bABRepeat == 1))
				pInfo->playing = UNDETERMINED;
//
			if(RepeatAB() != DVDE_UNAUTHORIZED) {
				pInfo->bABRepeat = (pInfo->bABRepeat + 1) % 3;
				pInfo->bRepeat = 0;
			}
			else
				msg = SHOW_ERROR;
//timer
			pInfo->playing = pl_tmp;
//
			if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		else if(pInfo->bDiscType == FMPC_CDDA) {
			DWORD l, r;			
			l = FMPGet(FMPI_LEFT_VOLUME);
			r = FMPGet(FMPI_RIGHT_VOLUME);
			FMPSet (FMPI_LEFT_VOLUME, l - 10);
			FMPSet (FMPI_RIGHT_VOLUME, r - 10);
			l = FMPGet (FMPI_LEFT_VOLUME);
			r = FMPGet (FMPI_RIGHT_VOLUME);
			DPRINT(("VOL- (%d, %d)\n", r, l));
		}
		break;
	case MUTE:		// Mode
		pInfo->bMode = !pInfo->bMode;
		msg = SHOW_RES;
		if(pInfo->osdMsgQ) OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		break;
	case SOFT_POWER:
		if(pInfo->playing != CLOSED) {
			FMPStop();
			FMPClose();
			pInfo->playing = CLOSED;
		}
		break;
	default:
		return ERROR;
	}
	return S_OK;
}


void StartPlaying(INFO* pInfo) {

	FMP_OPENSTRUCT FMPOpenStruct;
	DWORD tmp;

	if (pInfo->playing == CLOSED) {
		if(pInfo->osdMsgQ && pInfo->pIOsd) {
			BYTE msg = SHOW_LOADING;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}
		
		DPRINT(("Begin of FMPOpen\n"));
		FMPOpenStruct.dwStructSize  = sizeof (FMP_OPENSTRUCT);
		FMPOpenStruct.bDriverNumber	= DRIVE_NUMBER;
		FMPOpenStruct.dwSize        = 32 * 1024;
		FMPOpenStruct.dwCount       = 10;
		FMPOpenStruct.pCallback     = Event_Notifications;
		FMPOpenStruct.dwContext     = (DWORD)pInfo;
		FMPOpenStruct.sFileName     = NULL;
		FMPOpenStruct.dwFlags       = FMPF_DVD;
		FMPOpenStruct.bDiscContent  = FMPC_UNKNOWN;
		FMPOpenStruct.bFileSystem   = 0x00;

		pInfo->maddie = 0;
		pInfo->test = 0;

		g_Pass = FMPGetProfileWord(RMREG_PASSW_LOW_WORD) |
		         (FMPGetProfileWord(RMREG_PASSW_HIGH_WORD) << 16);

		tmp = FMPOpenDiscPlayback(&FMPOpenStruct);

		if(pInfo->osdMsgQ && pInfo->pIOsd) {
			BYTE msg = SCR_OFF;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}

		if(tmp != 0) {
			pInfo->playing = CLOSED;
			return;
		}

		// apply command line settings if present
		{
			DWORD oldsetting,newsetting;
			oldsetting=FMPGet(FMPI_VIDEOOUT);
			newsetting=oldsetting;
			
			if (command_line_switch_YUV) {
				newsetting=oldsetting&(~FMPV_VIDEOOUT_COMPONENT_MASK);
				newsetting|=FMPV_VIDEOOUT_COMPONENT_YUV;
			}
			if (command_line_switch_NTSC) {
				newsetting=oldsetting&(~FMPV_VIDEOOUT_STANDARDTV_MASK);
				newsetting|=FMPV_VIDEOOUT_NTSC;
			}
			if (command_line_switch_PAL) {
				newsetting=oldsetting&(~FMPV_VIDEOOUT_STANDARDTV_MASK);
				newsetting|=FMPV_VIDEOOUT_PAL;
			}
			
			if (newsetting!=oldsetting) FMPSet(FMPI_VIDEOOUT,newsetting);
		}
		
		// go full screen on TV now.
		FMPEnableOverlay (0);
		FMPEnableFullScreen	(1);

		pInfo->playing = STOPPED;
		pInfo->totalTime = 0;
		pInfo->dwTime = 0;
		DPRINT(("End of FMPOpen\n"));

		if(pInfo->pIHdtv) {
			if((g_OutputMode & FMPV_VIDEOOUT_MODE_MASK) == FMPV_VIDEOOUT_HDTV) {
				tmp = (WORD)FMPGetProfileWord(RMREG_HDTV_RES) & 0xff;
				pInfo->IHdtv_c = tmp + 1;
				IHdtv_SetMode(pInfo->pIHdtv, &(Hdtv_Params[pInfo->IHdtv_c - 1]), g_OutputMode);
			}
			else if((g_OutputMode & FMPV_VIDEOOUT_MODE_MASK) == FMPV_VIDEOOUT_TV) {
				pInfo->IHdtv_c = 0;
			}
		}

		if(pInfo->osdMsgQ && pInfo->pIOsd) {
			BYTE msg = SHOW_PLAY;
			OSPostMessage(pInfo->osdMsgQ, &msg, 1);
		}

		FMPPlay();
		pInfo->bABRepeat = 0;
		pInfo->bRepeat = 0;
		pInfo->bAudioStream = 0;
		pInfo->bAngleNumber = 0;
		pInfo->bSPStream = 0xff;
		pInfo->bDiscType = FMPOpenStruct.bDiscContent;
		pInfo->playing = PLAYING;
		DPRINT(("End of FMPPlay\n"));
	}
}

//-------------------------------------------------------------------------------//
//	GetSymbol - Reads the symbol                                                 //
//-------------------------------------------------------------------------------//
int GetSymbol(MESSAGE_QUEUE_OBJECT msgQueue, INFO *pInfo) {

	char buf[1];
	if (OSGetMessage(msgQueue, buf, 1) == ERROR) return -1;
	if(pInfo) {
		if(pInfo->blk && (buf[0] != OSD) &&
		   (buf[0] != UP) && (buf[0] != SEL) && (buf[0] != ENT) &&
		   (buf[0] != LEFT) && (buf[0] != RIGHT) &&
		   (buf[0] != DOWN) && (buf[0] != COMPUTER) &&
		   (buf[0] < ZERO || buf[0] > NINE))
			return 0;
		if(pInfo->bMode && (buf[0] != VGA_TV) && (buf[0] != MUTE) &&
		   (buf[0] != UP) && (buf[0] != LEFT) && (buf[0] != RIGHT) &&
		   (buf[0] != DOWN))
			return 0;
		if(pInfo->bSearch && (buf[0] != VGA_TV) && (buf[0] != SHOW_SEARCH) &&
		   (buf[0] != ENT) && (buf[0] != COMPUTER) &&
		   (buf[0] < ZERO || buf[0] > NINE))
			return 0;
	}
	return (int)(buf[0]);
}


//---------------------------------------------------------------------------------//
//	remReadPort - Reads the port until a valid sequence is detected - then returns //
//  the symbol read                                                                //
//---------------------------------------------------------------------------------//
BYTE remReadPort(PORTHANDLE hPort) {
	int test;
	BYTE symbol, symbol_2;

	do {
		test = 0;
		symbol = OSReadPort(hPort);	// read one character
		if  (symbol == 131) {
			symbol = OSReadPort(hPort);
			symbol_2 = OSReadPort(hPort);
			if (symbol == symbol_2)
				test = 1;
		}	
	}
	while (test == 0);

	switch(symbol) {
#ifdef PRINCETON
		case 0xa2/*0x97*/: symbol = LANGUAGE; break;   // Vol+
		case 0x97/*0xa2*/: symbol = VOL_MORE; break;   // Language
#else
		case 0x97: symbol = LANGUAGE; break;   // Language
		case 0xa2: symbol = VOL_MORE; break;   // Vol+
#endif
		case 0x0d: symbol = 55; break;         // 7
		case 0x11: symbol = 56; break;         // 8
		case 0x15: symbol = VGA_TV; break;     // VGA/TV
		case 0x19: symbol = 48; break;         // 0
		case 0x21: symbol = ENT; break;        // ENT
		case 0x25: symbol = L_R; break;        // L-R
		case 0x8d: symbol = COMPUTER; break;   // Computer
		case 0x8e: symbol = PLAYER; break;     // Player
		case 0x8f: symbol = UP; break;         // Up
		case 0x91: symbol = LEFT; break;       // Left
		case 0x92: symbol = SEL; break;        // Sel
		case 0x93: symbol = DOWN; break;       // Down
		case 0x94: symbol = MENU; break;       // Menu
		case 0x95: symbol = TITLE; break;      // Title
		case 0x96: symbol = OSD; break;        // OSD
		case 0x98: symbol = ANGLE; break;      // Angle
		case 0x99: symbol = SUBTITLE; break;   // Sub-title
		case 0x9a: symbol = PLAY_PAUSE; break; // Play/Pause
		case 0x9b: symbol = STOP_1; break;     // Stop
		case 0x9c: symbol = STEP_PLAY; break;  // Step play
		case 0x9d: symbol = EJECT; break;      // Eject
		case 0x9e: symbol = REW; break;        // Rewind
		case 0x9f: symbol = FF; break;         // Fast Forward
		case 0xa0: symbol = LAST_TRACK; break; // Last track
		case 0xa1: symbol = NEXT_TRACK; break; // Next track
		case 0xa3: symbol = 49; break;         // 1
		case 0xa4: symbol = 50; break;         // 2
		case 0xa5:
		case 0x41: symbol = 54; break;         // 6
		case 0xa6: symbol = VOL_LESS; break;   // Vol-
		case 0xa7: symbol = 52; break;         // 4
		case 0xa8: symbol = 53; break;         // 5
		case 0xa9: symbol = 57; break;         // 9
		case 0xab: symbol = MUTE; break;       // Mute		
		case 0xac: symbol = 51; break;         // 3
		case 0xbe: symbol = RIGHT; break;      // Right
		default:  symbol = -1; break;
	}
	OSPurge (hPort);
	return symbol;
}

//---------------------------------------------------------------------------------//
//	kbdReadPort - Reads the port until a valid sequence is detected - then returns //
//  the symbol read                                                                //
//---------------------------------------------------------------------------------//
BYTE kbdReadPort(PORTHANDLE hPort) {
	BYTE symbol;
	if ((symbol = OSReadPort(hPort)) == 27) {
		if ((symbol = OSReadPort(hPort)) == 91) {
			symbol = OSReadPort(hPort);
			if ((symbol > 64) && (symbol < 69)) symbol -= 37;
			return symbol;
		}
		if (symbol == 79) {
			symbol = OSReadPort(hPort);
			switch (symbol) {
				case 8  : return UP;       //Up arrow
				case 2  : return DOWN;     //Down arrow
				case 6  : return RIGHT;    //Right arrow
				case 4  : return LEFT;     //Left arrow
				case 5  : return SEL;      //SEL
				case 109: return VOL_MORE; //'+'
				case 108: return VOL_LESS; //'-'
				default : return symbol;
			}
		}
	}
	else
		if (symbol == 123) symbol++;
	return symbol;
}

#ifdef PRINCETON
//---------------------------------------------------------------------------------//
//	rsReadPort - Reads the port until a valid sequence is detected - then returns //
//  the symbol read                                                                //
//---------------------------------------------------------------------------------//
void rsReadPort(ThINFO *ms) {
	BYTE ans;
	BYTE str[65], *p, *p1;
	INFO *pInfo = (INFO *)(ms->info);
	int i;

	do {
		memset(str, 0, 65);
		i = -1;
		do {
			i++;
			if((str[i] = OSReadPort(ms->portID)) == 0x08) {
				str[i] = 0;
				i--;
				if(i > -1)
					i--;
			}
		} while(str[i] != ETX && i < 63);

		if(ans = checkSint(str)) {
			OSWriteToPort(ms->portID, NACK);
			OSWriteToPort(ms->portID, ans + ZERO);
			continue;
		}
		else
			OSWriteToPort(ms->portID, ACK);

		p1 = p = str + 1;
		OSThreadSuspend(rtID);
		OSThreadSuspend(ktID);
		OSPurgeMQ(pInfo->msgQueue);
		while(*p != ETX && p1) {
			p1 = sendRSCommand(p, pInfo);
			if(!p1) {
				OSWriteToPort(ms->portID, STX);
				OSWriteToPort(ms->portID, 'E');
				OSWriteToPort(ms->portID, 'R');
				OSWriteToPort(ms->portID, ZERO);
				OSWriteToPort(ms->portID, ZERO);
				OSWriteToPort(ms->portID, p[-1] + ZERO);
				OSWriteToPort(ms->portID, ETX);
			}
			else
				p = p1;
			OSSleep_s(2);
		};
		OSSleep_s(8);
		OSThreadResume(rtID);
		OSThreadResume(ktID);

	} while(1);
}
#endif

//-------------------------------------------------------------------------------//
//	Polling Threads															 //
//-------------------------------------------------------------------------------//
void portReadingThread(ThINFO *ms) {
	BYTE buf;
	OSCelSetThreadPriority(THREAD_SELF_ID, PORT_READING_THREAD_PRIORITY);
	while(1) {
		buf = (BYTE)(ms->func(ms->portID));
		OSPostMessage(ms->msg_q_id, &buf, 1);
	}
}

//---------------------------------------------//
//	Timer Thread                               //
//---------------------------------------------//
void timerThread(INFO *pInfo)
{
	DWORD stopTime = 0;
	WORD reg_tmp;

	while(1) {
		OSSleep_t(2);
		if(pInfo->playing != PLAYING || pInfo->bABRepeat == 2 ||
		   (reg_tmp = (WORD)FMPGet(FMPI_CURRENT_DOMAIN)) == VMGM_DOM ||
				reg_tmp == VTSM_DOM) {
			stopTime = 0;
			continue;
		}
		if(!stopTime) {
			stopTime = OSGetTickCount_() + OSGetClockRate();
		}
		if(OSGetTickCount_() < stopTime)
			OSSleep_t(stopTime - OSGetTickCount_());
		stopTime = OSGetTickCount_() + OSGetClockRate();
		{
			char msg;
			DWORD tmp = (pInfo->dwTime << 8);
			DWORD inv_tot = (pInfo->totalTime << 8), inv_tmp;
			PBYTE pTmp = (PBYTE)(&tmp) + 1;

			inv_tot = (inv_tot >> 24) | ((inv_tot >> 8) & 0xff00) | ((inv_tot << 8) & 0xff0000);

			if((pTmp[2] & 0xf) > 0x8) {
				pTmp[2] &= 0xf0;
				if(pTmp[2] > 0x40) {
					pTmp[2] = 0;
					if((pTmp[1] & 0xf) > 0x8) {
						pTmp[1] &= 0xf0;
						if(pTmp[1] > 0x40) {
							pTmp[1] = 0;
							if((pTmp[0] & 0xf) > 0x8) {
								pTmp[0] &= 0xf0;
								if(pTmp[0] > 0x80) {
									pTmp[0] = 0;
								}
								else
									pTmp[0] += 0x10;
							}
							else
								pTmp[0]++;
						}
						else
							pTmp[1] += 0x10;
					}
					else
						pTmp[1]++;
				}
				else
					pTmp[2] += 0x10;
			}
			else
				pTmp[2]++;

			inv_tmp = ((DWORD)pTmp[0] << 16) | ((DWORD)pTmp[1] << 8) | (DWORD)pTmp[2];
			if(inv_tot >= inv_tmp) {
				pInfo->dwTime = (tmp >> 8) | (pInfo->dwTime & 0xff000000);
				if(pInfo->osdFlag && pInfo->osdMsgQ) {
					msg = EV_NOTE;
					OSPostMessage(pInfo->osdMsgQ, &msg, 1);
				}
			}
		}
	}
}

void autoPlayThread(INFO *pInfo)
{
	DWORD diskIn;
	char msg;

	OSSleep_s(1);
	if(pInfo->playing == CLOSED)
		diskIn = FMPIsDiscLoaded();
	else
		diskIn = 1;
	while(1) {
		if(pInfo->playing == CLOSED) {
			if(!diskIn && FMPIsDiscLoaded()) {
				diskIn = 1;
				msg = PLAY_PAUSE;
					if(pInfo->msgQueue)
						OSPostMessage(pInfo->msgQueue, &msg, 1);
			}
			else
				diskIn = FMPIsDiscLoaded();
		}
		OSSleep_s(1);
	}
}



#define PRINT_INFO                                      \
{                                                       \
	TCHAR V[17], D[13];                                   \
	FMPAbout(V, D, NULL);                                 \
	_tprintf(TEXT("%s\n\r%s\n\rVersion: %s\n\rBuild on: %s\n\r"), \
	       RM_PRODUCTNAME, RM_LEGALCOPYRIGHT, V, D);      \
}

//-----------------------------------------------------------------------------//
//	MAIN FUNCTION - IDENTICAL IN QNX AND CE, EXCEPT FOR "int WINAPI WinMain..."//
//-----------------------------------------------------------------------------//
void OSMain() {						
	INFO Info;
	MESSAGE_QUEUE_OBJECT symb_msg_q;
	WORD tmp;
	BOOL wait_for_sp_pressed = FALSE;

	DPRINT(("remote application start\n"));

#ifdef _STPC_
	ConfigSwitches();
#endif

	rem.func = remReadPort;
	kbd.func = kbdReadPort;

	DPRINT(("open com ports\n"));
	rem.portID = OSOpenPort(REM_PORT);      // Opens and initialize COM port
#ifndef _BARBADOS_
	kbd.portID = OSOpenPort(KBD_PORT); // Opens and initialize keyboard
#else
	// do not access keyboard with Linux (blocks console)
	kbd.portID = ERROR;
#endif _BARBADOS_
#ifdef PRINCETON
	rs232.portID = OSOpenPort(RS232_PORT); // Opens and initialize COM port
#endif
	if ((rem.portID == ERROR) && (kbd.portID == ERROR)
#ifdef PRINCETON
	    && (rs232.portID == ERROR)
#endif
	                                                  ) {
		DPRINT(("Cannot open ports\n"));
		return;
	}

	// Create message queue
	if (!(symb_msg_q = (MESSAGE_QUEUE_OBJECT)OSCreateMessageQueue())) {
		DPRINT(("cannot create message queue\n"));
		OSClosePort(rem.portID);
		OSClosePort(kbd.portID);
#ifdef PRINCETON
		OSClosePort(rs232.portID);
#endif
		return;
	}
	Info.msgQueue = rem.msg_q_id = kbd.msg_q_id = symb_msg_q;

	// Spawn tasks
	if (rem.portID != ERROR)
		rtID = OSInitPolling("remote_read_port", (FUNCPTR)portReadingThread, (DWORD)(&rem));
	if (kbd.portID != ERROR)
		ktID = OSInitPolling("kbd_read_port", (FUNCPTR)portReadingThread, (DWORD)(&kbd));
#ifdef PRINCETON
	if (rs232.portID != ERROR) {
		rs232.info = (DWORD)(&Info);
		rstID = OSInitPolling("rs232_read_port", (FUNCPTR)rsReadPort, (DWORD)(&rs232));
	}
	swID = OSInitPolling("read_front_panel", (FUNCPTR)ReadFrontPanel, (DWORD)(&Info));
#elif defined(_STPC_)
	ReadFrontPanel(NULL);
#endif
	if ((rtID == ERROR) && (ktID == ERROR)
#ifdef PRINCETON
	    && (rstID == ERROR) && (swID == ERROR)
#endif
	                                      ) {
		DPRINT(("Cannot spawn tasks\n"));
		OSDestroyMessageQueue(symb_msg_q);
		OSClosePort(rem.portID);
		OSClosePort(kbd.portID);
#ifdef PRINCETON
		OSClosePort(rs232.portID);
#endif
		return;
	}

	OSCelSetThreadPriority(THREAD_SELF_ID, MAIN_THREAD_PRIORITY);

	PRINT_INFO

SP_Entry:
// Initialize driver
	MPEGDriverEntry(DRIVE_NUMBER);

#ifdef _INCLUDE_IGS_
	igs_start ();
	igs_fullscreen_step1 (720, 480);
	igs_fullscreen_step2 (720, 480);
#endif

	g_OutputMode = (WORD)FMPGetProfileWord(RMREG_OUTPUTMODE);

	if(FMPQueryInterface(IID_IHDTV, (void **)(&(Info.pIHdtv)))) {
		DPRINT(("Cannot set HDTV\n"));
		Info.pIHdtv = NULL;
	}
	else {
		IHdtv_SetAspectRatio(Info.pIHdtv,4,3,5);
		if((g_OutputMode & FMPV_VIDEOOUT_MODE_MASK) == FMPV_VIDEOOUT_HDTV) {
			tmp = (WORD)FMPGetProfileWord(RMREG_HDTV_RES) & 0xff;
			Info.IHdtv_c = tmp + 1;
//Before showing splash screen we return to 720x480 resolution
			IHdtv_SetMode(Info.pIHdtv, &(Hdtv_Params_Init), g_OutputMode);
		}
		else if((g_OutputMode & FMPV_VIDEOOUT_MODE_MASK) == FMPV_VIDEOOUT_TV) {
			IHdtv_Off(Info.pIHdtv, g_OutputMode);
			Info.IHdtv_c = 0;
		}
	}

	if(FMPQueryInterface(IID_IOSD, (void **)(&(Info.pIOsd)))) {
		DPRINT(("Cannot set OSD\n"));
		Info.pIOsd = NULL;
	}
	else {
		IOsd_ShowSplash(Info.pIOsd,yuv_data,SPL_WIDTH,SPL_HEIGHT);
	}

	DPRINT(("mpeg driver initialized\n"));

// initialize the info structure
	Info.symbol		= 0;
	Info.bDiscType = FMPC_UNKNOWN;
	Info.playing	= CLOSED;
	Info.test	= 0;
	Info.maddie		= 0;
// should get this info from navigator
	Info.bFullScreen = 1;

// Position and Size of the window
	Info.dwX	= 320;
	Info.dwY	= 0;
	Info.dwcX	= 320;
	Info.dwcY	= 240;
	Info.bStep	= 10;
	Info.bPosAction = POS_NO_ACTION;
	Info.pIRma = NULL;
//	Info.IHdtv_AR = 0;
	Info.dwTime = 0;
	Info.totalTime = 0;
	Info.osdFlag = 0;
	Info.blk = 0;
	Info.bMode = 0;
	Info.bSearch = 0;

#ifdef PRINCETON
	Info.bAns = 0;

	LCDOn();
	DrawImage(Image6_0, Image6_1);
#endif

	if(QFAILED(OSDModCreateInstance(0, &CLSID_CRMA, &IID_IRMA, (void**)(&(Info.pIRma))))) {
		DPRINT(("Cannot get instance of RMA interface\n"));
		Info.pIRma = NULL;
	}

// Create message queue
	if(Info.osdMsgQ = (MESSAGE_QUEUE_OBJECT)OSCreateMessageQueue()) {
		omID = OSInitPolling("osd_manager", (FUNCPTR)osdManager, (DWORD)(&Info));
		OSCelSetThreadPriority(omID, OSD_MANAGER_THREAD_PRIORITY);
	}
	if(omID == ERROR && Info.osdMsgQ) {
		OSDestroyMessageQueue(Info.osdMsgQ);
		Info.osdMsgQ = NULL;
	}

//timer
	ttID = OSInitPolling("timer_thread", (FUNCPTR)timerThread, (DWORD)(&Info));
	OSCelSetThreadPriority(ttID, TIMER_THREAD_PRIORITY);

//autoplay
	tmp = (WORD)FMPGetProfileWord(RMREG_AUTOPLAY);
	if(tmp == RM_AUTOPLAY_ON)
		aptID = OSInitPolling("autoplay_thread", (FUNCPTR)autoPlayThread, (DWORD)(&Info));
	else
		aptID = ERROR;

	DPRINT(("purge com ports\n"));
	OSPurge(rem.portID);		// empties COM port before first reading
	OSPurge(kbd.portID);		// empties COM port before first reading
#ifdef PRINCETON
	OSPurge(rs232.portID);		// empties COM port before first reading
#endif

	while (1) {
		Info.symbol = GetSymbol(symb_msg_q, &Info); // Reads until a good sequence is found
		ReadLibrary(&Info);	           // Identifies sequence with a known key
		if (Info.symbol == BREAK)
			break;
		else if(Info.symbol == SOFT_POWER) {
			wait_for_sp_pressed = TRUE;
			break;
		}
	}
	
#ifdef PRINCETON
	LCDOff();
#endif

	OSThreadDelete(aptID);
	OSThreadDelete(ttID); //timer
	OSThreadDelete(omID);
	OSThreadDelete(osdtID);
	if(Info.osdMsgQ) OSDestroyMessageQueue(Info.osdMsgQ);
	if(Info.pIRma) IRma_Delete((IObject *)Info.pIRma, TRUE);
	MPEGDriverUnload();

	if(wait_for_sp_pressed) {
		wait_for_sp_pressed = FALSE;
		do {
			Info.symbol = GetSymbol(symb_msg_q, &Info);
		} while(Info.symbol != SOFT_POWER && Info.symbol != BREAK);
		if(Info.symbol == SOFT_POWER)
			goto SP_Entry;
	}

	OSThreadDelete(rtID);
	OSThreadDelete(ktID);
#ifdef PRINCETON
	OSThreadDelete(swID);
	OSThreadDelete(rstID);
	OSClosePort(rs232.portID);
#endif
	OSDestroyMessageQueue(symb_msg_q);
	OSClosePort(rem.portID);
	OSClosePort(kbd.portID);

	OSCelMemCheck();

#ifdef _INCLUDE_IGS_
	igs_end ();
#endif

	return;
}





/*

#ifdef PRINCETON

void testLCD() {						
	INFO Info;
	MESSAGE_QUEUE_OBJECT symb_msg_q;
	int i = 1;
	BYTE tmp0 = 1, tmp1 = 1, com = 0;
	BYTE reg[8];
	IUserI2C *pIUserI2C;

	memset(&Info, 0, sizeof(INFO));
	memset(reg, 0, 8);

	MPEGDriverEntry(DRIVE_NUMBER);
	printf("driver initialized\n");

	if(FMPQueryInterface(IID_ILCD, (void **)(&(pIUserI2C)))) {
		printf("Cannot set LCD interface\n");
		MPEGDriverUnload();
		return;
	}
	else {
		IUserI2C_SetI2CAddress(pIUserI2C,0x58,0x59,1);
		printf("Address set\n");
	}

	LCDOn();
	DrawImage(Image6_0, Image6_1);
	ConfigSwitches();

	rem.func = remReadPort;

	printf("open rem port\n");
	rem.portID = OSOpenPort(REM_PORT);      // Opens and initialize COM port
	if (rem.portID == ERROR) {
		printf("Cannot open ports\n");
		MPEGDriverUnload();
		return;
	}

	if(!(symb_msg_q = (MESSAGE_QUEUE_OBJECT)OSCreateMessageQueue())) {
		printf("cannot create message queue\n");
		OSClosePort(rem.portID);
		MPEGDriverUnload();
		return;
	}
	Info.msgQueue = rem.msg_q_id = symb_msg_q;

	printf("purge rem port\n");
	OSPurge(rem.portID);		// empties COM port before first reading

	if (rem.portID != ERROR)
		rtID = OSInitPolling("remote_read_port", (FUNCPTR)portReadingThread, (DWORD)(&rem));
	if (rtID == ERROR) {
		printf("Cannot spawn tasks\n");
		OSDestroyMessageQueue(symb_msg_q);
		OSClosePort(rem.portID);
		MPEGDriverUnload();
		return;
	}

	while (1) {
		switch(Info.symbol = GetSymbol(symb_msg_q, &Info)) {
			case LEFT:
				tmp0 = (tmp0 < 10) ? (tmp0 + 54) : (tmp0 - 10);
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("current value = %d; next value = %d; ", com, tmp0);
				IUserI2C_Write(pIUserI2C,0xa0,&tmp0,1);
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("new value = %d\n", com);
				break;
			case RIGHT:
				tmp0 = (tmp0 + 10) & 0x3f;
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("current value = %d; next value = %d; ", com, tmp0);
				IUserI2C_Write(pIUserI2C,0xa0,&tmp0,1);
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("new value = %d\n", com);
				break;
			case DOWN:
				tmp1 = (tmp1 < 10) ? (tmp1 + 54) : (tmp1 - 10);
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("current value = %d; next value = %d; ", com, tmp1);
				IUserI2C_Write(pIUserI2C,0xa1,&tmp1,1);
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("new value = %d\n", com);
				break;
			case UP:
				tmp1 = (tmp1 + 10) & 0x3f;
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("current value = %d; next value = %d; ", com, tmp1);
				IUserI2C_Write(pIUserI2C,0xa1,&tmp1,1);
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("new value = %d\n", com);
				break;
//for backlight
			case ONE:
			case TWO:
			case THREE:
			case FOUR:
			{
				BYTE pos = Info.symbol - ZERO - 1;
				reg[pos] = (reg[pos] + 1) & 0x3f;
				IUserI2C_Read(pIUserI2C,(0xb0 | (pos << 2)),&com,1);
				printf("current value = %d; next value = %d; ", com, reg[pos]);
				IUserI2C_Write(pIUserI2C,(0xc0 | (pos << 2)),(reg + pos),1);
				OSSleep_t(1);
				IUserI2C_Read(pIUserI2C,(0xb0 | (pos << 2)),&com,1);
				printf("new value = %d\n", com);
				break;
			}
//for contrast
			case FIVE:
			case SIX:
			case SEVEN:
			case EIGHT:
			{
				BYTE pos = Info.symbol - ZERO - 5;
				reg[pos + 4] = (reg[pos + 4] + 1) & 0x3f;
				IUserI2C_Read(pIUserI2C,(0xb1 | (pos << 2)),&com,1);
				printf("current value = %d; next value = %d; ", com, reg[pos + 4]);
				IUserI2C_Write(pIUserI2C,(0xc1 | (pos << 2)),(reg + pos + 4),1);
				OSSleep_t(1);
				IUserI2C_Read(pIUserI2C,(0xb1 | (pos << 2)),&com,1);
				printf("new value = %d\n", com);
				break;
			}
			case FF:
			{
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("current value = %d; ", com);
				II2C_IncLCD(pIUserI2C,0x20);
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("new value = %d\n", com);
				break;
			}
			case REW:
			{
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("current value = %d; ", com);
				II2C_DecLCD(pIUserI2C,0x20);
				IUserI2C_Read(pIUserI2C,0x90,&com,1);
				printf("new value = %d\n", com);
				break;
			}
			case NEXT_TRACK:
			{
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("current value = %d; ", com);
				II2C_IncLCD(pIUserI2C,0x21);
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("new value = %d\n", com);
				break;
			}
			case LAST_TRACK:
			{
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("current value = %d; ", com);
				II2C_DecLCD(pIUserI2C,0x21);
				IUserI2C_Read(pIUserI2C,0x91,&com,1);
				printf("new value = %d\n", com);
				break;
			}
			default:
				break;
		}
		OSPurgeMQ(Info.msgQueue);			// If a known key was found, empties message queue
		if (Info.symbol == COMPUTER)
			break;
	}
	
	LCDOff();

	OSThreadDelete(rtID);
	OSDestroyMessageQueue(symb_msg_q);
	OSClosePort(rem.portID);
	MPEGDriverUnload();
	return;
}
#endif
*/

#ifdef DEBUG

/*
int portRead() {
	char a[3];
	int pd, sd;

	memset(a, '\n', 3);
	pd = OSOpenPort("/tyCo/0"); // Opens and initialize COM port
	if (pd == ERROR) {
		printf("Cannot open the port");
		return -1;
	}
	a[1] = OSReadPort(pd);	// read one character
	sd = open("/pcConsole/0", O_WRONLY, 0644);
	if(sd != ERROR) {
		write(sd, a, 3);
		OSClosePort(sd);
	}
	OSClosePort(pd);
	return a[1];
}
void remCodes(int n) {

	int portID, i;
	unsigned char buf[3];
	portID = OSOpenPort("/tyCo/1");
	OSPurge(portID);

	for(i = 0; i < n; i++) {
		memset(buf, 0, 3);
		read(portID, buf, 1);
		read(portID, buf + 1, 1);
		read(portID, buf + 2, 1);
		printf("0x%2x 0x%2x 0x%2x\n", buf[0], buf[1], buf[2]);
	}
	close(portID);
}

extern unsigned char next_osd[];
extern unsigned char reverse_osd[];

PBYTE crPic(IRma *pIRma, unsigned char *v) {

	ULONG size;
	RMAYUVENTRY *pPalette;
	RMAPOINT pos1;
	RMARECT rect;
	PBYTE p1 = v, bmp;

	IRma_CreateDC(pIRma, COLORDEPTH_EIGHT_BPP, 112, 34, 0x01);
	IRma_GetPaletteFromBitmap(pIRma, (HRMABITMAP)next_osd,
	                          (PBYTE *)(&pPalette), (LONG *)(&size));
	IRma_SetPalette(pIRma, NULL, pPalette, 0, 256);

	pos1.x = 30;
	pos1.y = 0;
	rect.right = ((DWORD)p1[4] << 8) | (DWORD)p1[5];
	rect.left = rect.right - 82;
	rect.top = 0;
	rect.bottom = ((DWORD)p1[6] << 8) | (DWORD)p1[7];
	IRma_LockRmaOSD(pIRma, (HRMABITMAP)p1, (PBYTE *)(&p1), &size);
	RmaBitBlt(NULL, pIRma, (HRMABITMAP)p1, NULL, pos1, rect, RMASRCCOPY, 0);
	IRma_UnLockRmaOSD(pIRma, (HRMABITMAP)p1, (PBYTE *)(&p1), &size);

// Clean up

	IRma_LockRmaOSD(pIRma, NULL, (PBYTE *)(&p1), &size);

	if(!(bmp = (PBYTE)OSmalloc(size))) {
		printf("Not enough memory\n");
		IRma_DestroyDC(pIRma);
		return NULL;
	}
	memcpy((void *)bmp, (void *)p1, size);
	IRma_DestroyDC(pIRma);
	return bmp;
}

void bmpGen(char *pic_name) {

	IRma *pIRma;
	BYTE *p, *p1, name[20];
	DWORD width, height, i, j, r;
	FILE *fd;

	MPEGDriverEntry(DRIVE_NUMBER);
	memset(name, 0, 20);
	sprintf(name, "%s.h", pic_name);
	if(QFAILED(OSDModCreateInstance(0, &CLSID_CRMA, &IID_IRMA, (void**)(&pIRma)))) {
		printf("Cannot get instance of RMA interface\n");
		MPEGDriverUnload();
		return;
	}
	if((fd = fopen(name, "w")) == NULL) {
		printf("Cannot open file %s\n", name);
		if(pIRma) IRma_Delete((IObject *)pIRma, TRUE);
		MPEGDriverUnload();
		return;
	}

	if(pic_name[0] == 'n')
		p = crPic(pIRma, next_osd);
	if(pic_name[0] == 'r')
		p = crPic(pIRma, reverse_osd);
	if(p == NULL) {
		if(fclose(fd))
			printf("Error during closing file %s\n", name);
		if(pIRma) IRma_Delete((IObject *)pIRma, TRUE);
		MPEGDriverUnload();
		return;
	}
	width = ((DWORD)p[4] << 8) | (DWORD)p[5];
	height = ((DWORD)p[6] << 8) | (DWORD)p[7];
	r = width % 8;

	fprintf(fd, "unsigned char %s_osd[] = {\n0x%02x,\n", pic_name, p[0]);
	fprintf(fd, "0x%02x, 0x%02x, 0x%02x,\n", p[1], p[2], p[3]);
*/
//	fprintf(fd, "/* width  %3d */\n0x%02x, 0x%02x,\n", width, p[4], p[5]);
//	fprintf(fd, "/* heigth %3d */\n0x%02x, 0x%02x,\n", height, p[6], p[7]);
//	p1 = p + 8;
//	for(i = 0; i < 256; i++) {
//		fprintf(fd, "/*[0x%02x]*/ 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
//		                  i,       p1[0],  p1[1],  p1[2],  p1[3]);
//		p1 += 4;
//	}
//	for(i = 0; i < height; i ++) {
//		fprintf(fd, "/*row %d*/\n", i);
/*
		for(j = 0; j < width; j += 8) {
			fprintf(fd, "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
			              p1[0],  p1[1],  p1[2],  p1[3],  p1[4],  p1[5],  p1[6],  p1[7]);
			p1 += 8;
		}
		for(j = 0; j < r; j++)
			fprintf(fd, "0x%02x, ", p1[j]);
		fprintf(fd, "\n");
		p1 += r;
	}
	fprintf (fd, "};\n");

	if(fclose(fd))
		printf("Error during closing file %s\n", name);
	if(pIRma) IRma_Delete((IObject *)pIRma, TRUE);
	OSfree(p);
	MPEGDriverUnload();
	return;
}
*/
#endif
