Path: blob/master/libmupen64plus/mupen64plus-input-bkm/plugin.c
2 views
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *1* Mupen64plus-input-bkm - plugin.c *2* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *3* Edited 2014 null_ptr *4* Copyright (C) 2008-2011 Richard Goedeken *5* Copyright (C) 2008 Tillin9 *6* Copyright (C) 2002 Blight *7* *8* This program is free software; you can redistribute it and/or modify *9* it under the terms of the GNU General Public License as published by *10* the Free Software Foundation; either version 2 of the License, or *11* (at your option) any later version. *12* *13* This program is distributed in the hope that it will be useful, *14* but WITHOUT ANY WARRANTY; without even the implied warranty of *15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *16* GNU General Public License for more details. *17* *18* You should have received a copy of the GNU General Public License *19* along with this program; if not, write to the *20* Free Software Foundation, Inc., *21* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *22* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */2324#include <stdio.h>25#include <stdlib.h>26#include <string.h>2728#define M64P_PLUGIN_PROTOTYPES 129#include "m64p_types.h"30#include "m64p_plugin.h"31#include "m64p_common.h"32#include "m64p_config.h"3334#include "plugin.h"35#include "config.h"36#include "version.h"37#include "osal_dynamiclib.h"3839#include <errno.h>4041/* global data definitions */42SController controller[4]; // 4 controllers4344/* static data definitions */45static void (*l_DebugCallback)(void *, int, const char *) = NULL;46static void *l_DebugCallContext = NULL;47static int l_PluginInit = 0;4849/* Callbacks for data flow out of mupen */50static int (*l_inputCallback)(int i) = NULL;51static int (*l_setrumbleCallback)(int i, int on) = NULL;5253static int romopen = 0; // is a rom opened5455/* Global functions */56void DebugMessage(int level, const char *message, ...)57{58char msgbuf[1024];59va_list args;6061if (l_DebugCallback == NULL)62return;6364va_start(args, message);65vsprintf(msgbuf, message, args);6667(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);6869va_end(args);70}7172#pragma region (De-)Initialization7374/* Mupen64Plus plugin functions */75EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,76void (*DebugCallback)(void *, int, const char *))77{78ptr_CoreGetAPIVersions CoreAPIVersionFunc;7980int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;8182if (l_PluginInit)83return M64ERR_ALREADY_INIT;8485/* first thing is to set the callback function for debug info */86l_DebugCallback = DebugCallback;87l_DebugCallContext = Context;8889/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */90CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");91if (CoreAPIVersionFunc == NULL)92{93DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");94return M64ERR_INCOMPATIBLE;95}9697(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);98if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))99{100DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",101VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));102return M64ERR_INCOMPATIBLE;103}104105/* reset controllers */106memset(controller, 0, sizeof(controller));107108l_PluginInit = 1;109return M64ERR_SUCCESS;110}111112EXPORT m64p_error CALL PluginShutdown(void)113{114if (!l_PluginInit)115return M64ERR_NOT_INIT;116117/* reset some local variables */118l_DebugCallback = NULL;119l_DebugCallContext = NULL;120121l_PluginInit = 0;122memset(controller, 0, sizeof(controller));123return M64ERR_SUCCESS;124}125126/******************************************************************127Function: InitiateControllers128Purpose: This function initialises how each of the controllers129should be handled.130input: - The handle to the main window.131- A controller structure that needs to be filled for132the emulator to know how to handle each controller.133output: none134*******************************************************************/135EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)136{137int i;138memset( controller, 0, sizeof(controller) );139140for( i = 0; i < 4; i++ )141{142controller[i].control = ControlInfo.Controls + i;143controller[i].control->Plugin = PLUGIN_MEMPAK;144controller[i].control->Present = 1;145controller[i].control->RawData = 0;146}147148DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));149}150151/******************************************************************152Function: RomClosed153Purpose: This function is called when a rom is closed.154input: none155output: none156*******************************************************************/157EXPORT void CALL RomClosed(void)158{159romopen = 0;160}161162/******************************************************************163Function: RomOpen164Purpose: This function is called when a rom is open. (from the165emulation thread)166input: none167output: none168*******************************************************************/169EXPORT int CALL RomOpen(void)170{171romopen = 1;172return 1;173}174175#pragma endregion176177EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)178{179/* set version info */180if (PluginType != NULL)181*PluginType = M64PLUGIN_INPUT;182183if (PluginVersion != NULL)184*PluginVersion = PLUGIN_VERSION;185186if (APIVersion != NULL)187*APIVersion = INPUT_PLUGIN_API_VERSION;188189if (PluginNamePtr != NULL)190*PluginNamePtr = PLUGIN_NAME;191192if (Capabilities != NULL)193{194*Capabilities = 0;195}196197return M64ERR_SUCCESS;198}199200#pragma region Raw read and write201202/* ----------------------------------------------------------------------203-------------------------- Controller CRC ----------------------------204---------------------------------------------------------------------- */205static unsigned char DataCRC( unsigned char *Data, int iLenght )206{207unsigned char Remainder = Data[0];208209int iByte = 1;210unsigned char bBit = 0;211212while( iByte <= iLenght )213{214int HighBit = ((Remainder & 0x80) != 0);215Remainder = Remainder << 1;216217Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;218219Remainder ^= (HighBit) ? 0x85 : 0;220221bBit++;222iByte += bBit/8;223bBit %= 8;224}225226return Remainder;227}228229/******************************************************************230Function: ControllerCommand231Purpose: To process the raw data that has just been sent to a232specific controller.233input: - Controller Number (0 to 3) and -1 signalling end of234processing the pif ram.235- Pointer of data to be processed.236output: none237238note: This function is only needed if the DLL is allowing raw239data, or the plugin is set to raw240241the data that is being processed looks like this:242initilize controller: 01 03 00 FF FF FF243read controller: 01 04 01 FF FF FF FF244*******************************************************************/245EXPORT void CALL ControllerCommand(int Control, unsigned char *Command)246{247if( Control == -1)248return;249}250251/* ----------------------------------------------------------------------252----------- Handles raw data read from a rumble pak -------------253----------- Data read at address C01B is 32x the status -------------254----------- Data read at address 8001 is 32x 0x80 -------------255---------------------------------------------------------------------- */256void DoRumblePakRead(int Control, unsigned char* Command)257{258if(Command[3] == 0x80 && Command[4] == 0x01)259memset(Command+5, 0x80, 32);260else if(Command[3] == 0xC0 && Command[4] == 0x1B)261memset(Command+5, controller[Control].rumbling, 32);262else263memset(Command+5, 0x00, 32);264}265266/* ----------------------------------------------------------------------267----------- Writes data to rumble pak -------------268----------- If writes 0x01 to address 0xC01B rumble on -------------269----------- If writes 0x00 to address 0xC01B rumble off -------------270---------------------------------------------------------------------- */271void DoRumblePakWrite(int Control, unsigned char* Command)272{273if(Command[3] == 0xC0 && Command[4] == 0x1B)274{275controller[Control].rumbling = Command[5];276if(l_setrumbleCallback != NULL)277l_setrumbleCallback(Control, Command[5]);278}279}280281/* ----------------------------------------------------------------------282----------- Does a raw read of a controller pak -------------283----------- Currently only handles rumble paks -------------284---------------------------------------------------------------------- */285void DoRawRead(int Control, unsigned char* Command)286{287switch(controller[Control].control->Plugin)288{289case PLUGIN_RUMBLE_PAK:290DoRumblePakRead(Control, Command);291break;292case PLUGIN_NONE:293case PLUGIN_RAW:294case PLUGIN_MEMPAK:295case PLUGIN_TRANSFER_PAK:296default:297break;298}299}300301/* ----------------------------------------------------------------------302----------- Handles raw write to the controller pak -------------303----------- Currently only handles rumble paks -------------304---------------------------------------------------------------------- */305void DoRawWrite(int Control, unsigned char* Command)306{307switch(controller[Control].control->Plugin)308{309case PLUGIN_RUMBLE_PAK:310DoRumblePakWrite(Control, Command);311break;312case PLUGIN_NONE:313case PLUGIN_RAW:314case PLUGIN_MEMPAK:315case PLUGIN_TRANSFER_PAK:316default:317break;318}319}320321/******************************************************************322Function: ReadController323Purpose: To process the raw data in the pif ram that is about to324be read.325input: - Controller Number (0 to 3) and -1 signalling end of326processing the pif ram.327- Pointer of data to be processed.328output: none329note: This function is only needed if the DLL is allowing raw330data.331*******************************************************************/332EXPORT void CALL ReadController(int Control, unsigned char *Command)333{334unsigned char * Data = Command + 5;335int value;336if(Control == -1)337return;338339switch(Command[2])340{341case RD_RESETCONTROLLER:342case RD_GETSTATUS:343Command[3] = RD_GAMEPAD | RD_ABSOLUTE;344Command[4] = RD_NOEEPROM;345Command[5] = controller[Control].control->Plugin != PLUGIN_NONE;346break;347case RD_READKEYS:348value = l_inputCallback(Control);349*((int*)(Command+3)) = value;350break;351case RD_READPAK:352DoRawRead(Control, Command);353Data[32] = DataCRC(Data, 32);354break;355case RD_WRITEPAK:356DoRawWrite(Control, Command);357Data[32] = DataCRC(Data, 32);358break;359case RD_READEEPROM:360case RD_WRITEEPROM:361default:362break;363}364}365366#pragma endregion367368#pragma region Useless stubs369370/* ----------------------------------------------------------------------371-------------------- This functions are not used --------------------372-------------------- Plugin api just expects them --------------------373-------------------- to exist --------------------374---------------------------------------------------------------------- */375376/******************************************************************377Function: SDL_KeyDown378Purpose: To pass the SDL_KeyDown message from the emulator to the379plugin.380input: keymod and keysym of the SDL_KEYDOWN message.381output: none382*******************************************************************/383EXPORT void CALL SDL_KeyDown(int keymod, int keysym)384{385}386387/******************************************************************388Function: SDL_KeyUp389Purpose: To pass the SDL_KeyUp message from the emulator to the390plugin.391input: keymod and keysym of the SDL_KEYUP message.392output: none393*******************************************************************/394EXPORT void CALL SDL_KeyUp(int keymod, int keysym)395{396}397398#pragma endregion399400/******************************************************************401Function: GetKeys402Purpose: To get the current state of the controllers buttons.403input: - Controller Number (0 to 3)404- A pointer to a BUTTONS structure to be filled with405the controller state.406output: none407*******************************************************************/408EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )409{410Keys->Value = (*l_inputCallback)(Control);411}412413/* ----------------------------------------------------------------------414----------- Sets callback to retrieve button and axis data -----------415---------------------------------------------------------------------- */416EXPORT void CALL SetInputCallback(int (*inputCallback)(int i))417{418l_inputCallback = inputCallback;419}420421/* ----------------------------------------------------------------------422----------- Sets a callback to set rumble on and off -------------423---------------------------------------------------------------------- */424EXPORT void CALL SetRumbleCallback(void (*rumbleCallback)(int Control, int on))425{426}427428/* ----------------------------------------------------------------------429----------- Sets the type of the controller pak -------------430----------- Possible values for type: -------------431----------- 1 - No pak inserted -------------432----------- 2 - Memory card -------------433----------- 3 - Rumble pak (no default implementation) -------------434----------- 4 - Transfer pak (no default implementation) -------------435----------- 5 - Raw data -------------436---------------------------------------------------------------------- */437EXPORT void CALL SetControllerPakType(int idx, int type)438{439controller[idx].control->Plugin = type;440controller[idx].control->RawData = (type != PLUGIN_MEMPAK);441}442443/* ----------------------------------------------------------------------444----------- Sets if a controller is connected -------------445---------------------------------------------------------------------- */446EXPORT void CALL SetControllerConnected(int idx, int connected)447{448controller[idx].control->Present = connected;449}450451