BizHawk/libmupen64plus/mupen64plus-input-bkm/nragev20/PakIO.cpp

416 lines
11 KiB
C++

/*
N-Rage`s Dinput8 Plugin
(C) 2002, 2006 Norbert Wladyka
Author`s Email: norbert.wladyka@chello.at
Website: http://go.to/nrage
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "commonIncludes.h"
#include <windows.h>
#include <Commctrl.h>
#include <tchar.h>
#include <stdio.h>
#include "../plugin.hpp"
//#include "NRagePluginV2.h"
//#include "DirectInput.h"
//#include "Interface.h"
//#include "FileAccess.h"
#include "PakIO.h"
#include "GBCart.h"
// ProtoTypes
BYTE AddressCRC( LPCBYTE Address );
BYTE DataCRC( LPCBYTE Data, const int iLength );
VOID CALLBACK WritebackProc( HWND hWnd, UINT msg, UINT_PTR idEvent, DWORD dwTime );
bool InitTransferPak( const int iControl )
// Prepares the Pak
{
if( !controller[iControl].control->Present )
return false;
bool bReturn = false;
controller[iControl].pPakData = malloc( sizeof(TRANSFERPAK));
LPTRANSFERPAK tPak = (LPTRANSFERPAK)controller[iControl].pPakData;
tPak->bPakType = PAK_TRANSFER;
tPak->gbCart.hRomFile = NULL;
tPak->gbCart.hRamFile = NULL;
tPak->gbCart.RomData = NULL;
tPak->gbCart.RamData = NULL;
/*
* Once the Interface is implemented g_pcControllers[iControl].szTransferRom will hold filename of the GB-Rom
* and g_pcControllers[iControl].szTransferSave holds Filename of the SRAM Save
*
* Here, both files should be opened and the handles stored in tPak ( modify the struct for Your own purposes, only bPakType must stay at first )
*/
//CreateFile( g_pcControllers[iControl].szTransferSave, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL );
tPak->iCurrentAccessMode = 0;
tPak->iCurrentBankNo = 0;
tPak->iEnableState = false;
tPak->iAccessModeChanged = 0x44;
tPak->bPakInserted = LoadCart( &tPak->gbCart, "gb_rom.gb", "gb_sav.sav", _T("") );
/*
if (tPak->bPakInserted) {
//DebugWriteA( "*** Init Transfer Pak - Success***\n" );
} else {
//DebugWriteA( "*** Init Transfer Pak - FAILURE***\n" );
}
*/
bReturn = true;
/*
// if there were any unrecoverable errors and we have allocated pPakData, free it and set paktype to NONE
if( !bReturn && g_pcControllers[iControl].pPakData )
CloseControllerPak( iControl );
*/
return bReturn;
}
BYTE ReadTransferPak( const int iControl, LPBYTE Command )
{
BYTE bReturn = RD_ERROR;
LPBYTE Data = &Command[2];
if( !controller[iControl].pPakData )
return RD_ERROR;
WORD dwAddress = (Command[0] << 8) + (Command[1] & 0xE0);
LPTRANSFERPAK tPak = (LPTRANSFERPAK)controller[iControl].pPakData; // TODO: null pointer check on tPak
// set bReturn = RD_OK when implementing Transferpak
bReturn = RD_OK;
//DebugWriteA( "TPak Read:\n" );
//DebugWriteA( " Address: %04X\n", dwAddress );
switch (dwAddress >> 12)
{
case 0x8: // if ((dwAddress >= 0x8000) && (dwAddress <= 0x8FFF))
//DebugWriteA( "Query Enable State: %u\n", tPak->iEnableState );
if (tPak->iEnableState == false)
ZeroMemory(Data, 32);
else
FillMemory(Data, 32, 0x84);
break;
case 0xB: // if ((dwAddress >= 0xB000) && (dwAddress <= 0xBFFF))
if (tPak->iEnableState == true) {
//DebugWriteA( "Query Cart. State:" );
if (tPak->bPakInserted) {
if (tPak->iCurrentAccessMode == 1) {
FillMemory(Data, 32, 0x89);
//DebugWriteA( " Inserted, Access Mode 1\n" );
} else {
FillMemory(Data, 32, 0x80);
//DebugWriteA( " Inserted, Access Mode 0\n" );
}
Data[0] = Data[0] | (BYTE)tPak->iAccessModeChanged;
} else {
FillMemory(Data, 32, 0x40); // Cart not inserted.
//DebugWriteA( " Not Inserted\n" );
}
tPak->iAccessModeChanged = 0;
}
break;
case 0xC:
case 0xD:
case 0xE:
case 0xF: // if ((dwAddress >= 0xC000))
if (tPak->iEnableState == true) {
//DebugWriteA( "Cart Read: Bank:%i\n", tPak->iCurrentBankNo );
//DebugWriteA( " Address:%04X\n", ((dwAddress & 0xFFE0) - 0xC000) + ((tPak->iCurrentBankNo & 3) * 0x4000) );
tPak->gbCart.ptrfnReadCart(&tPak->gbCart, ((dwAddress & 0xFFE0) - 0xC000) + ((tPak->iCurrentBankNo & 3) * 0x4000), Data);
}
break;
//default:
//DebugWriteA("WARNING: Unusual Pak Read\n" );
//DebugWriteA(" Address: %04X\n", dwAddress);
} // end switch (dwAddress >> 12)
//Data[32] = DataCRC( Data, 32 );
bReturn = RD_OK;
return bReturn;
}
// Called when the N64 tries to write to the controller pak, e.g. a mempak
BYTE WriteTransferPak( const int iControl, LPBYTE Command )
{
BYTE bReturn = RD_ERROR;
BYTE *Data = &Command[2];
if( !controller[iControl].pPakData )
return RD_ERROR;
WORD dwAddress = (Command[0] << 8) + (Command[1] & 0xE0);
LPTRANSFERPAK tPak = (LPTRANSFERPAK)controller[iControl].pPakData;
// set bReturn = RD_OK when implementing Transferpak
//DebugWriteA( "TPak Write:\n" );
//DebugWriteA( " Address: %04X\n", dwAddress );
switch (dwAddress >> 12)
{
case 0x8: // if ((dwAddress >= 0x8000) && (dwAddress <= 0x8FFF))
if (Data[0] == 0xFE) {
//DebugWriteA("Cart Disable\n" );
tPak->iEnableState = false;
}
else if (Data[0] == 0x84) {
//DebugWriteA("Cart Enable\n" );
tPak->iEnableState = true;
}
else {
//DebugWriteA("WARNING: Unusual Cart Enable/Disable\n" );
//DebugWriteA(" Address: " );
//DebugWriteWordA(dwAddress);
//DebugWriteA("\n" );
//DebugWriteA(" Data: " );
//DebugWriteByteA(Data[0]);
//DebugWriteA("\n" );
}
break;
case 0xA: // if ((dwAddress >= 0xA000) && (dwAddress <= 0xAFFF))
if (tPak->iEnableState == true) {
tPak->iCurrentBankNo = Data[0];
//DebugWriteA("Set TPak Bank No:%02X\n", Data[0] );
}
break;
case 0xB: // if ((dwAddress >= 0xB000) && (dwAddress <= 0xBFFF))
if (tPak->iEnableState == true) {
tPak->iCurrentAccessMode = Data[0] & 1;
tPak->iAccessModeChanged = 4;
//DebugWriteA("Set TPak Access Mode: %04X\n", tPak->iCurrentAccessMode);
if ((Data[0] != 1) && (Data[0] != 0)) {
//DebugWriteA("WARNING: Unusual Access Mode Change\n" );
//DebugWriteA(" Address: " );
//DebugWriteWordA(dwAddress);
//DebugWriteA("\n" );
//DebugWriteA(" Data: " );
//DebugWriteByteA(Data[0]);
//DebugWriteA("\n" );
}
}
break;
case 0xC:
case 0xD:
case 0xE:
case 0xF: // if (dwAddress >= 0xC000)
tPak->gbCart.ptrfnWriteCart(&tPak->gbCart, ((dwAddress & 0xFFE0) - 0xC000) + ((tPak->iCurrentBankNo & 3) * 0x4000), Data);
/*
if (tPak->gbCart.hRamFile != NULL )
SetTimer( g_strEmuInfo.hMainWindow, PAK_TRANSFER, 2000, (TIMERPROC) WritebackProc ); // if we go 2 seconds without a write, call the Writeback proc (which will flush the cache)
*/
break;
//default:
//DebugWriteA("WARNING: Unusual Pak Write\n" );
//DebugWriteA(" Address: %04X\n", dwAddress);
} // end switch (dwAddress >> 12)
//Data[32] = DataCRC( Data, 32 );
bReturn = RD_OK;
return bReturn;
}
void SaveControllerPak( const int iControl )
{
/*
if( !g_pcControllers[iControl].pPakData )
return;
switch( *(BYTE*)g_pcControllers[iControl].pPakData )
{
case PAK_MEM:
{
MEMPAK *mPak = (MEMPAK*)g_pcControllers[iControl].pPakData;
if( !mPak->fReadonly )
FlushViewOfFile( mPak->aMemPakData, PAK_MEM_SIZE ); // we've already written the stuff, just flush the cache
}
break;
case PAK_RUMBLE:
break;
case PAK_TRANSFER:
{
LPTRANSFERPAK tPak = (LPTRANSFERPAK)g_pcControllers[iControl].pPakData;
// here the changes( if any ) in the SRAM should be saved
if (tPak->gbCart.hRamFile != NULL)
{
SaveCart(&tPak->gbCart, g_pcControllers[iControl].szTransferSave, _T(""));
//DebugWriteA( "*** Save Transfer Pak ***\n" );
}
}
break;
case PAK_VOICE:
break;
case PAK_ADAPTOID:
break;
//case PAK_NONE:
// break;
}
*/
}
// if there is pPakData for the controller, does any closing of handles before freeing the pPakData struct and setting it to NULL
// also sets fPakInitialized to false
void CloseControllerPak( const int iControl )
{
/*
if( !g_pcControllers[iControl].pPakData )
return;
g_pcControllers[iControl].fPakInitialized = 0;
switch( *(BYTE*)g_pcControllers[iControl].pPakData )
{
case PAK_MEM:
{
MEMPAK *mPak = (MEMPAK*)g_pcControllers[iControl].pPakData;
if( mPak->fReadonly )
{
P_free( mPak->aMemPakData );
mPak->aMemPakData = NULL;
}
else
{
FlushViewOfFile( mPak->aMemPakData, PAK_MEM_SIZE );
// if it's a dexsave, our original mapped view is not aMemPakData
UnmapViewOfFile( mPak->fDexSave ? mPak->aMemPakData - PAK_MEM_DEXOFFSET : mPak->aMemPakData );
if ( mPak->hMemPakHandle != NULL )
CloseHandle( mPak->hMemPakHandle );
}
}
break;
case PAK_RUMBLE:
ReleaseEffect( g_apdiEffect[iControl] );
g_apdiEffect[iControl] = NULL;
break;
case PAK_TRANSFER:
{
LPTRANSFERPAK tPak = (LPTRANSFERPAK)g_pcControllers[iControl].pPakData;
UnloadCart(&tPak->gbCart);
//DebugWriteA( "*** Close Transfer Pak ***\n" );
// close files and free any additionally ressources
}
break;
case PAK_VOICE:
break;
case PAK_ADAPTOID:
break;
//case PAK_NONE:
// break;
}
freePakData( &g_pcControllers[iControl] );
*/
return;
}
BYTE AddressCRC( LPCBYTE Address )
{
bool HighBit;
WORD Data = MAKEWORD( Address[1], Address[0] );
register BYTE Remainder = ( Data >> 11 ) & 0x1F;
BYTE bBit = 5;
while( bBit < 16 )
{
HighBit = (Remainder & 0x10) != 0;
Remainder = (Remainder << 1) & 0x1E;
Remainder += ( bBit < 11 && Data & (0x8000 >> bBit )) ? 1 : 0;
Remainder ^= (HighBit) ? 0x15 : 0;
bBit++;
}
return Remainder;
}
BYTE DataCRC( LPCBYTE Data, const int iLength )
{
register BYTE Remainder = Data[0];
int iByte = 1;
BYTE bBit = 0;
while( iByte <= iLength )
{
bool HighBit = ((Remainder & 0x80) != 0);
Remainder = Remainder << 1;
Remainder += ( iByte < iLength && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
Remainder ^= (HighBit) ? 0x85 : 0;
bBit++;
iByte += bBit/8;
bBit %= 8;
}
return Remainder;
}
VOID CALLBACK WritebackProc( HWND hWnd, UINT msg, UINT_PTR idEvent, DWORD dwTime )
{
/*
KillTimer(hWnd, idEvent); // timer suicide
switch (idEvent)
{
case PAK_MEM:
//DebugWriteA("Mempak: WritebackProc flushed file writes\n");
for( int i = 0; i < 4; i++ )
{
MEMPAK *mPak = (MEMPAK*)g_pcControllers[i].pPakData;
if ( mPak && mPak->bPakType == PAK_MEM && !mPak->fReadonly && mPak->hMemPakHandle != NULL )
FlushViewOfFile( mPak->aMemPakData, PAK_MEM_SIZE );
}
return;
case PAK_TRANSFER:
//DebugWriteA("TPak: WritebackProc flushed file writes\n");
for( int i = 0; i < 4; i++ )
{
LPTRANSFERPAK tPak = (LPTRANSFERPAK)g_pcControllers[i].pPakData;
if (tPak && tPak->bPakType == PAK_TRANSFER && tPak->bPakInserted && tPak->gbCart.hRamFile != NULL )
FlushViewOfFile( tPak->gbCart.RamData, (tPak->gbCart.RomData[0x149] == 1 ) ? 0x0800 : tPak->gbCart.iNumRamBanks * 0x2000);
}
return;
}
*/
}