Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-input-bkm/plugin.c
2 views
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* Mupen64plus-input-bkm - plugin.c *
3
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4
* Edited 2014 null_ptr *
5
* Copyright (C) 2008-2011 Richard Goedeken *
6
* Copyright (C) 2008 Tillin9 *
7
* Copyright (C) 2002 Blight *
8
* *
9
* This program is free software; you can redistribute it and/or modify *
10
* it under the terms of the GNU General Public License as published by *
11
* the Free Software Foundation; either version 2 of the License, or *
12
* (at your option) any later version. *
13
* *
14
* This program is distributed in the hope that it will be useful, *
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17
* GNU General Public License for more details. *
18
* *
19
* You should have received a copy of the GNU General Public License *
20
* along with this program; if not, write to the *
21
* Free Software Foundation, Inc., *
22
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
23
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
29
#define M64P_PLUGIN_PROTOTYPES 1
30
#include "m64p_types.h"
31
#include "m64p_plugin.h"
32
#include "m64p_common.h"
33
#include "m64p_config.h"
34
35
#include "plugin.h"
36
#include "config.h"
37
#include "version.h"
38
#include "osal_dynamiclib.h"
39
40
#include <errno.h>
41
42
/* global data definitions */
43
SController controller[4]; // 4 controllers
44
45
/* static data definitions */
46
static void (*l_DebugCallback)(void *, int, const char *) = NULL;
47
static void *l_DebugCallContext = NULL;
48
static int l_PluginInit = 0;
49
50
/* Callbacks for data flow out of mupen */
51
static int (*l_inputCallback)(int i) = NULL;
52
static int (*l_setrumbleCallback)(int i, int on) = NULL;
53
54
static int romopen = 0; // is a rom opened
55
56
/* Global functions */
57
void DebugMessage(int level, const char *message, ...)
58
{
59
char msgbuf[1024];
60
va_list args;
61
62
if (l_DebugCallback == NULL)
63
return;
64
65
va_start(args, message);
66
vsprintf(msgbuf, message, args);
67
68
(*l_DebugCallback)(l_DebugCallContext, level, msgbuf);
69
70
va_end(args);
71
}
72
73
#pragma region (De-)Initialization
74
75
/* Mupen64Plus plugin functions */
76
EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
77
void (*DebugCallback)(void *, int, const char *))
78
{
79
ptr_CoreGetAPIVersions CoreAPIVersionFunc;
80
81
int ConfigAPIVersion, DebugAPIVersion, VidextAPIVersion;
82
83
if (l_PluginInit)
84
return M64ERR_ALREADY_INIT;
85
86
/* first thing is to set the callback function for debug info */
87
l_DebugCallback = DebugCallback;
88
l_DebugCallContext = Context;
89
90
/* attach and call the CoreGetAPIVersions function, check Config API version for compatibility */
91
CoreAPIVersionFunc = (ptr_CoreGetAPIVersions) osal_dynlib_getproc(CoreLibHandle, "CoreGetAPIVersions");
92
if (CoreAPIVersionFunc == NULL)
93
{
94
DebugMessage(M64MSG_ERROR, "Core emulator broken; no CoreAPIVersionFunc() function found.");
95
return M64ERR_INCOMPATIBLE;
96
}
97
98
(*CoreAPIVersionFunc)(&ConfigAPIVersion, &DebugAPIVersion, &VidextAPIVersion, NULL);
99
if ((ConfigAPIVersion & 0xffff0000) != (CONFIG_API_VERSION & 0xffff0000))
100
{
101
DebugMessage(M64MSG_ERROR, "Emulator core Config API (v%i.%i.%i) incompatible with plugin (v%i.%i.%i)",
102
VERSION_PRINTF_SPLIT(ConfigAPIVersion), VERSION_PRINTF_SPLIT(CONFIG_API_VERSION));
103
return M64ERR_INCOMPATIBLE;
104
}
105
106
/* reset controllers */
107
memset(controller, 0, sizeof(controller));
108
109
l_PluginInit = 1;
110
return M64ERR_SUCCESS;
111
}
112
113
EXPORT m64p_error CALL PluginShutdown(void)
114
{
115
if (!l_PluginInit)
116
return M64ERR_NOT_INIT;
117
118
/* reset some local variables */
119
l_DebugCallback = NULL;
120
l_DebugCallContext = NULL;
121
122
l_PluginInit = 0;
123
memset(controller, 0, sizeof(controller));
124
return M64ERR_SUCCESS;
125
}
126
127
/******************************************************************
128
Function: InitiateControllers
129
Purpose: This function initialises how each of the controllers
130
should be handled.
131
input: - The handle to the main window.
132
- A controller structure that needs to be filled for
133
the emulator to know how to handle each controller.
134
output: none
135
*******************************************************************/
136
EXPORT void CALL InitiateControllers(CONTROL_INFO ControlInfo)
137
{
138
int i;
139
memset( controller, 0, sizeof(controller) );
140
141
for( i = 0; i < 4; i++ )
142
{
143
controller[i].control = ControlInfo.Controls + i;
144
controller[i].control->Plugin = PLUGIN_MEMPAK;
145
controller[i].control->Present = 1;
146
controller[i].control->RawData = 0;
147
}
148
149
DebugMessage(M64MSG_INFO, "%s version %i.%i.%i initialized.", PLUGIN_NAME, VERSION_PRINTF_SPLIT(PLUGIN_VERSION));
150
}
151
152
/******************************************************************
153
Function: RomClosed
154
Purpose: This function is called when a rom is closed.
155
input: none
156
output: none
157
*******************************************************************/
158
EXPORT void CALL RomClosed(void)
159
{
160
romopen = 0;
161
}
162
163
/******************************************************************
164
Function: RomOpen
165
Purpose: This function is called when a rom is open. (from the
166
emulation thread)
167
input: none
168
output: none
169
*******************************************************************/
170
EXPORT int CALL RomOpen(void)
171
{
172
romopen = 1;
173
return 1;
174
}
175
176
#pragma endregion
177
178
EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
179
{
180
/* set version info */
181
if (PluginType != NULL)
182
*PluginType = M64PLUGIN_INPUT;
183
184
if (PluginVersion != NULL)
185
*PluginVersion = PLUGIN_VERSION;
186
187
if (APIVersion != NULL)
188
*APIVersion = INPUT_PLUGIN_API_VERSION;
189
190
if (PluginNamePtr != NULL)
191
*PluginNamePtr = PLUGIN_NAME;
192
193
if (Capabilities != NULL)
194
{
195
*Capabilities = 0;
196
}
197
198
return M64ERR_SUCCESS;
199
}
200
201
#pragma region Raw read and write
202
203
/* ----------------------------------------------------------------------
204
-------------------------- Controller CRC ----------------------------
205
---------------------------------------------------------------------- */
206
static unsigned char DataCRC( unsigned char *Data, int iLenght )
207
{
208
unsigned char Remainder = Data[0];
209
210
int iByte = 1;
211
unsigned char bBit = 0;
212
213
while( iByte <= iLenght )
214
{
215
int HighBit = ((Remainder & 0x80) != 0);
216
Remainder = Remainder << 1;
217
218
Remainder += ( iByte < iLenght && Data[iByte] & (0x80 >> bBit )) ? 1 : 0;
219
220
Remainder ^= (HighBit) ? 0x85 : 0;
221
222
bBit++;
223
iByte += bBit/8;
224
bBit %= 8;
225
}
226
227
return Remainder;
228
}
229
230
/******************************************************************
231
Function: ControllerCommand
232
Purpose: To process the raw data that has just been sent to a
233
specific controller.
234
input: - Controller Number (0 to 3) and -1 signalling end of
235
processing the pif ram.
236
- Pointer of data to be processed.
237
output: none
238
239
note: This function is only needed if the DLL is allowing raw
240
data, or the plugin is set to raw
241
242
the data that is being processed looks like this:
243
initilize controller: 01 03 00 FF FF FF
244
read controller: 01 04 01 FF FF FF FF
245
*******************************************************************/
246
EXPORT void CALL ControllerCommand(int Control, unsigned char *Command)
247
{
248
if( Control == -1)
249
return;
250
}
251
252
/* ----------------------------------------------------------------------
253
----------- Handles raw data read from a rumble pak -------------
254
----------- Data read at address C01B is 32x the status -------------
255
----------- Data read at address 8001 is 32x 0x80 -------------
256
---------------------------------------------------------------------- */
257
void DoRumblePakRead(int Control, unsigned char* Command)
258
{
259
if(Command[3] == 0x80 && Command[4] == 0x01)
260
memset(Command+5, 0x80, 32);
261
else if(Command[3] == 0xC0 && Command[4] == 0x1B)
262
memset(Command+5, controller[Control].rumbling, 32);
263
else
264
memset(Command+5, 0x00, 32);
265
}
266
267
/* ----------------------------------------------------------------------
268
----------- Writes data to rumble pak -------------
269
----------- If writes 0x01 to address 0xC01B rumble on -------------
270
----------- If writes 0x00 to address 0xC01B rumble off -------------
271
---------------------------------------------------------------------- */
272
void DoRumblePakWrite(int Control, unsigned char* Command)
273
{
274
if(Command[3] == 0xC0 && Command[4] == 0x1B)
275
{
276
controller[Control].rumbling = Command[5];
277
if(l_setrumbleCallback != NULL)
278
l_setrumbleCallback(Control, Command[5]);
279
}
280
}
281
282
/* ----------------------------------------------------------------------
283
----------- Does a raw read of a controller pak -------------
284
----------- Currently only handles rumble paks -------------
285
---------------------------------------------------------------------- */
286
void DoRawRead(int Control, unsigned char* Command)
287
{
288
switch(controller[Control].control->Plugin)
289
{
290
case PLUGIN_RUMBLE_PAK:
291
DoRumblePakRead(Control, Command);
292
break;
293
case PLUGIN_NONE:
294
case PLUGIN_RAW:
295
case PLUGIN_MEMPAK:
296
case PLUGIN_TRANSFER_PAK:
297
default:
298
break;
299
}
300
}
301
302
/* ----------------------------------------------------------------------
303
----------- Handles raw write to the controller pak -------------
304
----------- Currently only handles rumble paks -------------
305
---------------------------------------------------------------------- */
306
void DoRawWrite(int Control, unsigned char* Command)
307
{
308
switch(controller[Control].control->Plugin)
309
{
310
case PLUGIN_RUMBLE_PAK:
311
DoRumblePakWrite(Control, Command);
312
break;
313
case PLUGIN_NONE:
314
case PLUGIN_RAW:
315
case PLUGIN_MEMPAK:
316
case PLUGIN_TRANSFER_PAK:
317
default:
318
break;
319
}
320
}
321
322
/******************************************************************
323
Function: ReadController
324
Purpose: To process the raw data in the pif ram that is about to
325
be read.
326
input: - Controller Number (0 to 3) and -1 signalling end of
327
processing the pif ram.
328
- Pointer of data to be processed.
329
output: none
330
note: This function is only needed if the DLL is allowing raw
331
data.
332
*******************************************************************/
333
EXPORT void CALL ReadController(int Control, unsigned char *Command)
334
{
335
unsigned char * Data = Command + 5;
336
int value;
337
if(Control == -1)
338
return;
339
340
switch(Command[2])
341
{
342
case RD_RESETCONTROLLER:
343
case RD_GETSTATUS:
344
Command[3] = RD_GAMEPAD | RD_ABSOLUTE;
345
Command[4] = RD_NOEEPROM;
346
Command[5] = controller[Control].control->Plugin != PLUGIN_NONE;
347
break;
348
case RD_READKEYS:
349
value = l_inputCallback(Control);
350
*((int*)(Command+3)) = value;
351
break;
352
case RD_READPAK:
353
DoRawRead(Control, Command);
354
Data[32] = DataCRC(Data, 32);
355
break;
356
case RD_WRITEPAK:
357
DoRawWrite(Control, Command);
358
Data[32] = DataCRC(Data, 32);
359
break;
360
case RD_READEEPROM:
361
case RD_WRITEEPROM:
362
default:
363
break;
364
}
365
}
366
367
#pragma endregion
368
369
#pragma region Useless stubs
370
371
/* ----------------------------------------------------------------------
372
-------------------- This functions are not used --------------------
373
-------------------- Plugin api just expects them --------------------
374
-------------------- to exist --------------------
375
---------------------------------------------------------------------- */
376
377
/******************************************************************
378
Function: SDL_KeyDown
379
Purpose: To pass the SDL_KeyDown message from the emulator to the
380
plugin.
381
input: keymod and keysym of the SDL_KEYDOWN message.
382
output: none
383
*******************************************************************/
384
EXPORT void CALL SDL_KeyDown(int keymod, int keysym)
385
{
386
}
387
388
/******************************************************************
389
Function: SDL_KeyUp
390
Purpose: To pass the SDL_KeyUp message from the emulator to the
391
plugin.
392
input: keymod and keysym of the SDL_KEYUP message.
393
output: none
394
*******************************************************************/
395
EXPORT void CALL SDL_KeyUp(int keymod, int keysym)
396
{
397
}
398
399
#pragma endregion
400
401
/******************************************************************
402
Function: GetKeys
403
Purpose: To get the current state of the controllers buttons.
404
input: - Controller Number (0 to 3)
405
- A pointer to a BUTTONS structure to be filled with
406
the controller state.
407
output: none
408
*******************************************************************/
409
EXPORT void CALL GetKeys( int Control, BUTTONS *Keys )
410
{
411
Keys->Value = (*l_inputCallback)(Control);
412
}
413
414
/* ----------------------------------------------------------------------
415
----------- Sets callback to retrieve button and axis data -----------
416
---------------------------------------------------------------------- */
417
EXPORT void CALL SetInputCallback(int (*inputCallback)(int i))
418
{
419
l_inputCallback = inputCallback;
420
}
421
422
/* ----------------------------------------------------------------------
423
----------- Sets a callback to set rumble on and off -------------
424
---------------------------------------------------------------------- */
425
EXPORT void CALL SetRumbleCallback(void (*rumbleCallback)(int Control, int on))
426
{
427
}
428
429
/* ----------------------------------------------------------------------
430
----------- Sets the type of the controller pak -------------
431
----------- Possible values for type: -------------
432
----------- 1 - No pak inserted -------------
433
----------- 2 - Memory card -------------
434
----------- 3 - Rumble pak (no default implementation) -------------
435
----------- 4 - Transfer pak (no default implementation) -------------
436
----------- 5 - Raw data -------------
437
---------------------------------------------------------------------- */
438
EXPORT void CALL SetControllerPakType(int idx, int type)
439
{
440
controller[idx].control->Plugin = type;
441
controller[idx].control->RawData = (type != PLUGIN_MEMPAK);
442
}
443
444
/* ----------------------------------------------------------------------
445
----------- Sets if a controller is connected -------------
446
---------------------------------------------------------------------- */
447
EXPORT void CALL SetControllerConnected(int idx, int connected)
448
{
449
controller[idx].control->Present = connected;
450
}
451