451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus - plugin.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2002 Hacktarux * |
5 | * Copyright (C) 2009 Richard Goedeken * |
6 | * * |
7 | * This program is free software; you can redistribute it and/or modify * |
8 | * it under the terms of the GNU General Public License as published by * |
9 | * the Free Software Foundation; either version 2 of the License, or * |
10 | * (at your option) any later version. * |
11 | * * |
12 | * This program is distributed in the hope that it will be useful, * |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
15 | * GNU General Public License for more details. * |
16 | * * |
17 | * You should have received a copy of the GNU General Public License * |
18 | * along with this program; if not, write to the * |
19 | * Free Software Foundation, Inc., * |
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
22 | |
23 | #include <stdlib.h> |
24 | |
25 | #include "plugin.h" |
26 | |
27 | #include "api/callbacks.h" |
28 | #include "api/m64p_common.h" |
29 | #include "api/m64p_plugin.h" |
30 | #include "api/m64p_types.h" |
31 | |
32 | #include "main/rom.h" |
33 | #include "main/version.h" |
34 | #include "memory/memory.h" |
35 | |
36 | #include "osal/dynamiclib.h" |
37 | |
38 | #include "dummy_audio.h" |
39 | #include "dummy_video.h" |
40 | #include "dummy_input.h" |
41 | #include "dummy_rsp.h" |
42 | |
43 | CONTROL Controls[4]; |
44 | |
45 | /* global function pointers - initialized on core startup */ |
46 | gfx_plugin_functions gfx; |
47 | audio_plugin_functions audio; |
48 | input_plugin_functions input; |
49 | rsp_plugin_functions rsp; |
50 | |
51 | /* local data structures and functions */ |
52 | static const gfx_plugin_functions dummy_gfx = { |
53 | dummyvideo_PluginGetVersion, |
54 | dummyvideo_ChangeWindow, |
55 | dummyvideo_InitiateGFX, |
56 | dummyvideo_MoveScreen, |
57 | dummyvideo_ProcessDList, |
58 | dummyvideo_ProcessRDPList, |
59 | dummyvideo_RomClosed, |
60 | dummyvideo_RomOpen, |
61 | dummyvideo_ShowCFB, |
62 | dummyvideo_UpdateScreen, |
63 | dummyvideo_ViStatusChanged, |
64 | dummyvideo_ViWidthChanged, |
65 | dummyvideo_ReadScreen2, |
66 | dummyvideo_SetRenderingCallback, |
67 | dummyvideo_ResizeVideoOutput, |
68 | dummyvideo_FBRead, |
69 | dummyvideo_FBWrite, |
70 | dummyvideo_FBGetFrameBufferInfo |
71 | }; |
72 | |
73 | static const audio_plugin_functions dummy_audio = { |
74 | dummyaudio_PluginGetVersion, |
75 | dummyaudio_AiDacrateChanged, |
76 | dummyaudio_AiLenChanged, |
77 | dummyaudio_InitiateAudio, |
78 | dummyaudio_ProcessAList, |
79 | dummyaudio_RomClosed, |
80 | dummyaudio_RomOpen, |
81 | dummyaudio_SetSpeedFactor, |
82 | dummyaudio_VolumeUp, |
83 | dummyaudio_VolumeDown, |
84 | dummyaudio_VolumeGetLevel, |
85 | dummyaudio_VolumeSetLevel, |
86 | dummyaudio_VolumeMute, |
87 | dummyaudio_VolumeGetString |
88 | }; |
89 | |
90 | static const input_plugin_functions dummy_input = { |
91 | dummyinput_PluginGetVersion, |
92 | dummyinput_ControllerCommand, |
93 | dummyinput_GetKeys, |
94 | dummyinput_InitiateControllers, |
95 | dummyinput_ReadController, |
96 | dummyinput_RomClosed, |
97 | dummyinput_RomOpen, |
98 | dummyinput_SDL_KeyDown, |
99 | dummyinput_SDL_KeyUp |
100 | }; |
101 | |
102 | static const rsp_plugin_functions dummy_rsp = { |
103 | dummyrsp_PluginGetVersion, |
104 | dummyrsp_DoRspCycles, |
105 | dummyrsp_InitiateRSP, |
106 | dummyrsp_RomClosed |
107 | }; |
108 | |
109 | static GFX_INFO gfx_info; |
110 | static AUDIO_INFO audio_info; |
111 | static CONTROL_INFO control_info; |
112 | static RSP_INFO rsp_info; |
113 | |
114 | static int l_RspAttached = 0; |
115 | static int l_InputAttached = 0; |
116 | static int l_AudioAttached = 0; |
117 | static int l_GfxAttached = 0; |
118 | |
119 | static unsigned int dummy; |
120 | |
121 | /* local functions */ |
122 | static void EmptyFunc(void) |
123 | { |
124 | } |
125 | |
126 | // Handy macro to avoid code bloat when loading symbols |
127 | #define GET_FUNC(type, field, name) \ |
128 | ((field = (type)osal_dynlib_getproc(plugin_handle, name)) != NULL) |
129 | |
130 | // code to handle backwards-compatibility to video plugins with API_VERSION < 02.1.0. This API version introduced a boolean |
131 | // flag in the rendering callback, which told the core whether or not the current screen has been freshly redrawn since the |
132 | // last time the callback was called. |
133 | static void (*l_mainRenderCallback)(int) = NULL; |
134 | static ptr_SetRenderingCallback l_old1SetRenderingCallback = NULL; |
135 | |
136 | static void backcompat_videoRenderCallback(int unused) // this function will be called by the video plugin as the render callback |
137 | { |
138 | if (l_mainRenderCallback != NULL) |
139 | l_mainRenderCallback(1); // assume screen is always freshly redrawn (otherwise screenshots won't work w/ OSD enabled) |
140 | } |
141 | |
142 | static void backcompat_setRenderCallbackIntercept(void (*callback)(int)) |
143 | { |
144 | l_mainRenderCallback = callback; |
145 | } |
146 | |
147 | static void plugin_disconnect_gfx(void) |
148 | { |
149 | gfx = dummy_gfx; |
150 | l_GfxAttached = 0; |
151 | l_mainRenderCallback = NULL; |
152 | } |
153 | |
154 | static m64p_error plugin_connect_gfx(m64p_dynlib_handle plugin_handle) |
155 | { |
156 | /* attach the Video plugin function pointers */ |
157 | if (plugin_handle != NULL) |
158 | { |
159 | m64p_plugin_type PluginType; |
160 | int PluginVersion, APIVersion; |
161 | |
162 | if (l_GfxAttached) |
163 | return M64ERR_INVALID_STATE; |
164 | |
165 | /* set function pointers for required functions */ |
166 | if (!GET_FUNC(ptr_PluginGetVersion, gfx.getVersion, "PluginGetVersion") || |
167 | !GET_FUNC(ptr_ChangeWindow, gfx.changeWindow, "ChangeWindow") || |
168 | !GET_FUNC(ptr_InitiateGFX, gfx.initiateGFX, "InitiateGFX") || |
169 | !GET_FUNC(ptr_MoveScreen, gfx.moveScreen, "MoveScreen") || |
170 | !GET_FUNC(ptr_ProcessDList, gfx.processDList, "ProcessDList") || |
171 | !GET_FUNC(ptr_ProcessRDPList, gfx.processRDPList, "ProcessRDPList") || |
172 | !GET_FUNC(ptr_RomClosed, gfx.romClosed, "RomClosed") || |
173 | !GET_FUNC(ptr_RomOpen, gfx.romOpen, "RomOpen") || |
174 | !GET_FUNC(ptr_ShowCFB, gfx.showCFB, "ShowCFB") || |
175 | !GET_FUNC(ptr_UpdateScreen, gfx.updateScreen, "UpdateScreen") || |
176 | !GET_FUNC(ptr_ViStatusChanged, gfx.viStatusChanged, "ViStatusChanged") || |
177 | !GET_FUNC(ptr_ViWidthChanged, gfx.viWidthChanged, "ViWidthChanged") || |
178 | !GET_FUNC(ptr_ReadScreen2, gfx.readScreen, "ReadScreen2") || |
179 | !GET_FUNC(ptr_SetRenderingCallback, gfx.setRenderingCallback, "SetRenderingCallback") || |
180 | !GET_FUNC(ptr_FBRead, gfx.fBRead, "FBRead") || |
181 | !GET_FUNC(ptr_FBWrite, gfx.fBWrite, "FBWrite") || |
182 | !GET_FUNC(ptr_FBGetFrameBufferInfo, gfx.fBGetFrameBufferInfo, "FBGetFrameBufferInfo")) |
183 | { |
184 | DebugMessage(M64MSG_ERROR, "broken Video plugin; function(s) not found."); |
185 | plugin_disconnect_gfx(); |
186 | return M64ERR_INPUT_INVALID; |
187 | } |
188 | |
189 | /* set function pointers for optional functions */ |
190 | gfx.resizeVideoOutput = (ptr_ResizeVideoOutput) osal_dynlib_getproc(plugin_handle, "ResizeVideoOutput"); |
191 | |
192 | /* check the version info */ |
193 | (*gfx.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); |
194 | if (PluginType != M64PLUGIN_GFX || (APIVersion & 0xffff0000) != (GFX_API_VERSION & 0xffff0000)) |
195 | { |
196 | DebugMessage(M64MSG_ERROR, "incompatible Video plugin"); |
197 | plugin_disconnect_gfx(); |
198 | return M64ERR_INCOMPATIBLE; |
199 | } |
200 | |
201 | /* handle backwards-compatibility */ |
202 | if (APIVersion < 0x020100) |
203 | { |
204 | DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.1.0. Screenshots may contain On Screen Display text", VERSION_PRINTF_SPLIT(APIVersion)); |
205 | // tell the video plugin to make its rendering callback to me (it's old, and doesn't have the bScreenRedrawn flag) |
206 | gfx.setRenderingCallback(backcompat_videoRenderCallback); |
207 | l_old1SetRenderingCallback = gfx.setRenderingCallback; // save this just for future use |
208 | gfx.setRenderingCallback = (ptr_SetRenderingCallback) backcompat_setRenderCallbackIntercept; |
209 | } |
210 | if (APIVersion < 0x20200 || gfx.resizeVideoOutput == NULL) |
211 | { |
212 | DebugMessage(M64MSG_WARNING, "Fallback for Video plugin API (%02i.%02i.%02i) < 2.2.0. Resizable video will not work", VERSION_PRINTF_SPLIT(APIVersion)); |
213 | gfx.resizeVideoOutput = dummyvideo_ResizeVideoOutput; |
214 | } |
215 | |
216 | l_GfxAttached = 1; |
217 | } |
218 | else |
219 | plugin_disconnect_gfx(); |
220 | |
221 | return M64ERR_SUCCESS; |
222 | } |
223 | |
224 | static m64p_error plugin_start_gfx(void) |
225 | { |
226 | /* fill in the GFX_INFO data structure */ |
227 | gfx_info.HEADER = (unsigned char *) rom; |
228 | gfx_info.RDRAM = (unsigned char *) rdram; |
229 | gfx_info.DMEM = (unsigned char *) SP_DMEM; |
230 | gfx_info.IMEM = (unsigned char *) SP_IMEM; |
231 | gfx_info.MI_INTR_REG = &(MI_register.mi_intr_reg); |
232 | gfx_info.DPC_START_REG = &(dpc_register.dpc_start); |
233 | gfx_info.DPC_END_REG = &(dpc_register.dpc_end); |
234 | gfx_info.DPC_CURRENT_REG = &(dpc_register.dpc_current); |
235 | gfx_info.DPC_STATUS_REG = &(dpc_register.dpc_status); |
236 | gfx_info.DPC_CLOCK_REG = &(dpc_register.dpc_clock); |
237 | gfx_info.DPC_BUFBUSY_REG = &(dpc_register.dpc_bufbusy); |
238 | gfx_info.DPC_PIPEBUSY_REG = &(dpc_register.dpc_pipebusy); |
239 | gfx_info.DPC_TMEM_REG = &(dpc_register.dpc_tmem); |
240 | gfx_info.VI_STATUS_REG = &(vi_register.vi_status); |
241 | gfx_info.VI_ORIGIN_REG = &(vi_register.vi_origin); |
242 | gfx_info.VI_WIDTH_REG = &(vi_register.vi_width); |
243 | gfx_info.VI_INTR_REG = &(vi_register.vi_v_intr); |
244 | gfx_info.VI_V_CURRENT_LINE_REG = &(vi_register.vi_current); |
245 | gfx_info.VI_TIMING_REG = &(vi_register.vi_burst); |
246 | gfx_info.VI_V_SYNC_REG = &(vi_register.vi_v_sync); |
247 | gfx_info.VI_H_SYNC_REG = &(vi_register.vi_h_sync); |
248 | gfx_info.VI_LEAP_REG = &(vi_register.vi_leap); |
249 | gfx_info.VI_H_START_REG = &(vi_register.vi_h_start); |
250 | gfx_info.VI_V_START_REG = &(vi_register.vi_v_start); |
251 | gfx_info.VI_V_BURST_REG = &(vi_register.vi_v_burst); |
252 | gfx_info.VI_X_SCALE_REG = &(vi_register.vi_x_scale); |
253 | gfx_info.VI_Y_SCALE_REG = &(vi_register.vi_y_scale); |
254 | gfx_info.CheckInterrupts = EmptyFunc; |
255 | |
256 | /* call the audio plugin */ |
257 | if (!gfx.initiateGFX(gfx_info)) |
258 | return M64ERR_PLUGIN_FAIL; |
259 | |
260 | return M64ERR_SUCCESS; |
261 | } |
262 | |
263 | static void plugin_disconnect_audio(void) |
264 | { |
265 | audio = dummy_audio; |
266 | l_AudioAttached = 0; |
267 | } |
268 | |
269 | static m64p_error plugin_connect_audio(m64p_dynlib_handle plugin_handle) |
270 | { |
271 | /* attach the Audio plugin function pointers */ |
272 | if (plugin_handle != NULL) |
273 | { |
274 | m64p_plugin_type PluginType; |
275 | int PluginVersion, APIVersion; |
276 | |
277 | if (l_AudioAttached) |
278 | return M64ERR_INVALID_STATE; |
279 | |
280 | if (!GET_FUNC(ptr_PluginGetVersion, audio.getVersion, "PluginGetVersion") || |
281 | !GET_FUNC(ptr_AiDacrateChanged, audio.aiDacrateChanged, "AiDacrateChanged") || |
282 | !GET_FUNC(ptr_AiLenChanged, audio.aiLenChanged, "AiLenChanged") || |
283 | !GET_FUNC(ptr_InitiateAudio, audio.initiateAudio, "InitiateAudio") || |
284 | !GET_FUNC(ptr_ProcessAList, audio.processAList, "ProcessAList") || |
285 | !GET_FUNC(ptr_RomOpen, audio.romOpen, "RomOpen") || |
286 | !GET_FUNC(ptr_RomClosed, audio.romClosed, "RomClosed") || |
287 | !GET_FUNC(ptr_SetSpeedFactor, audio.setSpeedFactor, "SetSpeedFactor") || |
288 | !GET_FUNC(ptr_VolumeUp, audio.volumeUp, "VolumeUp") || |
289 | !GET_FUNC(ptr_VolumeDown, audio.volumeDown, "VolumeDown") || |
290 | !GET_FUNC(ptr_VolumeGetLevel, audio.volumeGetLevel, "VolumeGetLevel") || |
291 | !GET_FUNC(ptr_VolumeSetLevel, audio.volumeSetLevel, "VolumeSetLevel") || |
292 | !GET_FUNC(ptr_VolumeMute, audio.volumeMute, "VolumeMute") || |
293 | !GET_FUNC(ptr_VolumeGetString, audio.volumeGetString, "VolumeGetString")) |
294 | { |
295 | DebugMessage(M64MSG_ERROR, "broken Audio plugin; function(s) not found."); |
296 | plugin_disconnect_audio(); |
297 | return M64ERR_INPUT_INVALID; |
298 | } |
299 | |
300 | /* check the version info */ |
301 | (*audio.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); |
302 | if (PluginType != M64PLUGIN_AUDIO || (APIVersion & 0xffff0000) != (AUDIO_API_VERSION & 0xffff0000)) |
303 | { |
304 | DebugMessage(M64MSG_ERROR, "incompatible Audio plugin"); |
305 | plugin_disconnect_audio(); |
306 | return M64ERR_INCOMPATIBLE; |
307 | } |
308 | |
309 | l_AudioAttached = 1; |
310 | } |
311 | else |
312 | plugin_disconnect_audio(); |
313 | |
314 | return M64ERR_SUCCESS; |
315 | } |
316 | |
317 | static m64p_error plugin_start_audio(void) |
318 | { |
319 | /* fill in the AUDIO_INFO data structure */ |
320 | audio_info.RDRAM = (unsigned char *) rdram; |
321 | audio_info.DMEM = (unsigned char *) SP_DMEM; |
322 | audio_info.IMEM = (unsigned char *) SP_IMEM; |
323 | audio_info.MI_INTR_REG = &(MI_register.mi_intr_reg); |
324 | audio_info.AI_DRAM_ADDR_REG = &(ai_register.ai_dram_addr); |
325 | audio_info.AI_LEN_REG = &(ai_register.ai_len); |
326 | audio_info.AI_CONTROL_REG = &(ai_register.ai_control); |
327 | audio_info.AI_STATUS_REG = &dummy; |
328 | audio_info.AI_DACRATE_REG = &(ai_register.ai_dacrate); |
329 | audio_info.AI_BITRATE_REG = &(ai_register.ai_bitrate); |
330 | audio_info.CheckInterrupts = EmptyFunc; |
331 | |
332 | /* call the audio plugin */ |
333 | if (!audio.initiateAudio(audio_info)) |
334 | return M64ERR_PLUGIN_FAIL; |
335 | |
336 | return M64ERR_SUCCESS; |
337 | } |
338 | |
339 | static void plugin_disconnect_input(void) |
340 | { |
341 | input = dummy_input; |
342 | l_InputAttached = 0; |
343 | } |
344 | |
345 | static m64p_error plugin_connect_input(m64p_dynlib_handle plugin_handle) |
346 | { |
347 | /* attach the Input plugin function pointers */ |
348 | if (plugin_handle != NULL) |
349 | { |
350 | m64p_plugin_type PluginType; |
351 | int PluginVersion, APIVersion; |
352 | |
353 | if (l_InputAttached) |
354 | return M64ERR_INVALID_STATE; |
355 | |
356 | if (!GET_FUNC(ptr_PluginGetVersion, input.getVersion, "PluginGetVersion") || |
357 | !GET_FUNC(ptr_ControllerCommand, input.controllerCommand, "ControllerCommand") || |
358 | !GET_FUNC(ptr_GetKeys, input.getKeys, "GetKeys") || |
359 | !GET_FUNC(ptr_InitiateControllers, input.initiateControllers, "InitiateControllers") || |
360 | !GET_FUNC(ptr_ReadController, input.readController, "ReadController") || |
361 | !GET_FUNC(ptr_RomOpen, input.romOpen, "RomOpen") || |
362 | !GET_FUNC(ptr_RomClosed, input.romClosed, "RomClosed") || |
363 | !GET_FUNC(ptr_SDL_KeyDown, input.keyDown, "SDL_KeyDown") || |
364 | !GET_FUNC(ptr_SDL_KeyUp, input.keyUp, "SDL_KeyUp")) |
365 | { |
366 | DebugMessage(M64MSG_ERROR, "broken Input plugin; function(s) not found."); |
367 | plugin_disconnect_input(); |
368 | return M64ERR_INPUT_INVALID; |
369 | } |
370 | |
371 | /* check the version info */ |
372 | (*input.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); |
373 | if (PluginType != M64PLUGIN_INPUT || (APIVersion & 0xffff0000) != (INPUT_API_VERSION & 0xffff0000)) |
374 | { |
375 | DebugMessage(M64MSG_ERROR, "incompatible Input plugin"); |
376 | plugin_disconnect_input(); |
377 | return M64ERR_INCOMPATIBLE; |
378 | } |
379 | |
380 | l_InputAttached = 1; |
381 | } |
382 | else |
383 | plugin_disconnect_input(); |
384 | |
385 | return M64ERR_SUCCESS; |
386 | } |
387 | |
388 | static m64p_error plugin_start_input(void) |
389 | { |
390 | int i; |
391 | |
392 | /* fill in the CONTROL_INFO data structure */ |
393 | control_info.Controls = Controls; |
394 | for (i=0; i<4; i++) |
395 | { |
396 | Controls[i].Present = 0; |
397 | Controls[i].RawData = 0; |
398 | Controls[i].Plugin = PLUGIN_NONE; |
399 | } |
400 | |
401 | /* call the input plugin */ |
402 | input.initiateControllers(control_info); |
403 | |
404 | return M64ERR_SUCCESS; |
405 | } |
406 | |
407 | static void plugin_disconnect_rsp(void) |
408 | { |
409 | rsp = dummy_rsp; |
410 | l_RspAttached = 0; |
411 | } |
412 | |
413 | static m64p_error plugin_connect_rsp(m64p_dynlib_handle plugin_handle) |
414 | { |
415 | /* attach the RSP plugin function pointers */ |
416 | if (plugin_handle != NULL) |
417 | { |
418 | m64p_plugin_type PluginType; |
419 | int PluginVersion, APIVersion; |
420 | |
421 | if (l_RspAttached) |
422 | return M64ERR_INVALID_STATE; |
423 | |
424 | if (!GET_FUNC(ptr_PluginGetVersion, rsp.getVersion, "PluginGetVersion") || |
425 | !GET_FUNC(ptr_DoRspCycles, rsp.doRspCycles, "DoRspCycles") || |
426 | !GET_FUNC(ptr_InitiateRSP, rsp.initiateRSP, "InitiateRSP") || |
427 | !GET_FUNC(ptr_RomClosed, rsp.romClosed, "RomClosed")) |
428 | { |
429 | DebugMessage(M64MSG_ERROR, "broken RSP plugin; function(s) not found."); |
430 | plugin_disconnect_rsp(); |
431 | return M64ERR_INPUT_INVALID; |
432 | } |
433 | |
434 | /* check the version info */ |
435 | (*rsp.getVersion)(&PluginType, &PluginVersion, &APIVersion, NULL, NULL); |
436 | if (PluginType != M64PLUGIN_RSP || (APIVersion & 0xffff0000) != (RSP_API_VERSION & 0xffff0000)) |
437 | { |
438 | DebugMessage(M64MSG_ERROR, "incompatible RSP plugin"); |
439 | plugin_disconnect_rsp(); |
440 | return M64ERR_INCOMPATIBLE; |
441 | } |
442 | |
443 | l_RspAttached = 1; |
444 | } |
445 | else |
446 | plugin_disconnect_rsp(); |
447 | |
448 | return M64ERR_SUCCESS; |
449 | } |
450 | |
451 | static m64p_error plugin_start_rsp(void) |
452 | { |
453 | /* fill in the RSP_INFO data structure */ |
454 | rsp_info.RDRAM = (unsigned char *) rdram; |
455 | rsp_info.DMEM = (unsigned char *) SP_DMEM; |
456 | rsp_info.IMEM = (unsigned char *) SP_IMEM; |
457 | rsp_info.MI_INTR_REG = &MI_register.mi_intr_reg; |
458 | rsp_info.SP_MEM_ADDR_REG = &sp_register.sp_mem_addr_reg; |
459 | rsp_info.SP_DRAM_ADDR_REG = &sp_register.sp_dram_addr_reg; |
460 | rsp_info.SP_RD_LEN_REG = &sp_register.sp_rd_len_reg; |
461 | rsp_info.SP_WR_LEN_REG = &sp_register.sp_wr_len_reg; |
462 | rsp_info.SP_STATUS_REG = &sp_register.sp_status_reg; |
463 | rsp_info.SP_DMA_FULL_REG = &sp_register.sp_dma_full_reg; |
464 | rsp_info.SP_DMA_BUSY_REG = &sp_register.sp_dma_busy_reg; |
465 | rsp_info.SP_PC_REG = &rsp_register.rsp_pc; |
466 | rsp_info.SP_SEMAPHORE_REG = &sp_register.sp_semaphore_reg; |
467 | rsp_info.DPC_START_REG = &dpc_register.dpc_start; |
468 | rsp_info.DPC_END_REG = &dpc_register.dpc_end; |
469 | rsp_info.DPC_CURRENT_REG = &dpc_register.dpc_current; |
470 | rsp_info.DPC_STATUS_REG = &dpc_register.dpc_status; |
471 | rsp_info.DPC_CLOCK_REG = &dpc_register.dpc_clock; |
472 | rsp_info.DPC_BUFBUSY_REG = &dpc_register.dpc_bufbusy; |
473 | rsp_info.DPC_PIPEBUSY_REG = &dpc_register.dpc_pipebusy; |
474 | rsp_info.DPC_TMEM_REG = &dpc_register.dpc_tmem; |
475 | rsp_info.CheckInterrupts = EmptyFunc; |
476 | rsp_info.ProcessDlistList = gfx.processDList; |
477 | rsp_info.ProcessAlistList = audio.processAList; |
478 | rsp_info.ProcessRdpList = gfx.processRDPList; |
479 | rsp_info.ShowCFB = gfx.showCFB; |
480 | |
481 | /* call the RSP plugin */ |
482 | rsp.initiateRSP(rsp_info, NULL); |
483 | |
484 | return M64ERR_SUCCESS; |
485 | } |
486 | |
487 | /* global functions */ |
488 | m64p_error plugin_connect(m64p_plugin_type type, m64p_dynlib_handle plugin_handle) |
489 | { |
490 | switch(type) |
491 | { |
492 | case M64PLUGIN_GFX: |
493 | if (plugin_handle != NULL && (l_AudioAttached || l_InputAttached || l_RspAttached)) |
494 | DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); |
495 | return plugin_connect_gfx(plugin_handle); |
496 | case M64PLUGIN_AUDIO: |
497 | if (plugin_handle != NULL && (l_InputAttached || l_RspAttached)) |
498 | DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); |
499 | return plugin_connect_audio(plugin_handle); |
500 | case M64PLUGIN_INPUT: |
501 | if (plugin_handle != NULL && (l_RspAttached)) |
502 | DebugMessage(M64MSG_WARNING, "Front-end bug: plugins are attached in wrong order."); |
503 | return plugin_connect_input(plugin_handle); |
504 | case M64PLUGIN_RSP: |
505 | return plugin_connect_rsp(plugin_handle); |
506 | default: |
507 | return M64ERR_INPUT_INVALID; |
508 | } |
509 | |
510 | return M64ERR_INTERNAL; |
511 | } |
512 | |
513 | m64p_error plugin_start(m64p_plugin_type type) |
514 | { |
515 | switch(type) |
516 | { |
517 | case M64PLUGIN_RSP: |
518 | return plugin_start_rsp(); |
519 | case M64PLUGIN_GFX: |
520 | return plugin_start_gfx(); |
521 | case M64PLUGIN_AUDIO: |
522 | return plugin_start_audio(); |
523 | case M64PLUGIN_INPUT: |
524 | return plugin_start_input(); |
525 | default: |
526 | return M64ERR_INPUT_INVALID; |
527 | } |
528 | |
529 | return M64ERR_INTERNAL; |
530 | } |
531 | |
532 | m64p_error plugin_check(void) |
533 | { |
534 | if (!l_GfxAttached) |
535 | DebugMessage(M64MSG_WARNING, "No video plugin attached. There will be no video output."); |
536 | if (!l_RspAttached) |
537 | DebugMessage(M64MSG_WARNING, "No RSP plugin attached. The video output will be corrupted."); |
538 | if (!l_AudioAttached) |
539 | DebugMessage(M64MSG_WARNING, "No audio plugin attached. There will be no sound output."); |
540 | if (!l_InputAttached) |
541 | DebugMessage(M64MSG_WARNING, "No input plugin attached. You won't be able to control the game."); |
542 | |
543 | return M64ERR_SUCCESS; |
544 | } |
545 | |