1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2014-2016 - Ali Bouhlel
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <sys/iosupport.h>
21 #include <net/net_compat.h>
22 #include <sys/socket.h>
23 #include <arpa/inet.h>
24
25 #include <wiiu/types.h>
26 #include <wiiu/ac.h>
27 #include <file/file_path.h>
28
29 #ifndef IS_SALAMANDER
30 #include <lists/file_list.h>
31 #endif
32
33 #include <string/stdstring.h>
34
35 #include <wiiu/gx2.h>
36 #include <wiiu/kpad.h>
37 #include <wiiu/ios.h>
38 #include <wiiu/os.h>
39 #include <wiiu/procui.h>
40 #include <wiiu/sysapp.h>
41
42 #include "file_path_special.h"
43
44 #include "../frontend.h"
45 #include "../frontend_driver.h"
46 #include "../../defaults.h"
47 #include "../../paths.h"
48 #include "../../retroarch.h"
49 #include "../../verbosity.h"
50
51 #include "hbl.h"
52 #include "wiiu_dbg.h"
53 #include "system/exception_handler.h"
54 #include "tasks/tasks_internal.h"
55
56 #ifndef IS_SALAMANDER
57 #ifdef HAVE_MENU
58 #include "../../menu/menu_driver.h"
59 #endif
60 #endif
61
62 #define WIIU_SD_PATH "sd:/"
63 #define WIIU_USB_PATH "usb:/"
64 #define WIIU_STORAGE_USB_PATH "storage_usb:/"
65
66 /**
67 * The Wii U frontend driver, along with the main() method.
68 */
69
70 #ifndef IS_SALAMANDER
71 static enum frontend_fork wiiu_fork_mode = FRONTEND_FORK_NONE;
72 #endif
73 static const char *elf_path_cst = WIIU_SD_PATH "retroarch/retroarch.elf";
74
exists(char * path)75 static bool exists(char *path)
76 {
77 struct stat stat_buf = {0};
78
79 if (!path)
80 return false;
81
82 return (stat(path, &stat_buf) == 0);
83 }
84
fix_asset_directory(void)85 static void fix_asset_directory(void)
86 {
87 char src_path_buf[PATH_MAX_LENGTH] = {0};
88 char dst_path_buf[PATH_MAX_LENGTH] = {0};
89
90 fill_pathname_join(src_path_buf, g_defaults.dirs[DEFAULT_DIR_PORT], "media", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
91 fill_pathname_join(dst_path_buf, g_defaults.dirs[DEFAULT_DIR_PORT], "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
92
93 if (exists(dst_path_buf) || !exists(src_path_buf))
94 return;
95
96 rename(src_path_buf, dst_path_buf);
97 }
98
frontend_wiiu_get_env_settings(int * argc,char * argv[],void * args,void * params_data)99 static void frontend_wiiu_get_env_settings(int *argc, char *argv[],
100 void *args, void *params_data)
101 {
102 fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], elf_path_cst, sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));
103
104 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
105 "downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
106 fix_asset_directory();
107 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_ASSETS], g_defaults.dirs[DEFAULT_DIR_PORT],
108 "assets", sizeof(g_defaults.dirs[DEFAULT_DIR_ASSETS]));
109 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], g_defaults.dirs[DEFAULT_DIR_PORT],
110 "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE]));
111 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_INFO], g_defaults.dirs[DEFAULT_DIR_CORE],
112 "info", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_INFO]));
113 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SAVESTATE], g_defaults.dirs[DEFAULT_DIR_CORE],
114 "savestates", sizeof(g_defaults.dirs[DEFAULT_DIR_SAVESTATE]));
115 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SRAM], g_defaults.dirs[DEFAULT_DIR_CORE],
116 "savefiles", sizeof(g_defaults.dirs[DEFAULT_DIR_SRAM]));
117 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_SYSTEM], g_defaults.dirs[DEFAULT_DIR_CORE],
118 "system", sizeof(g_defaults.dirs[DEFAULT_DIR_SYSTEM]));
119 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST], g_defaults.dirs[DEFAULT_DIR_CORE],
120 "playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
121 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG], g_defaults.dirs[DEFAULT_DIR_PORT],
122 "config", sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONFIG]));
123 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_REMAP], g_defaults.dirs[DEFAULT_DIR_PORT],
124 "config/remaps", sizeof(g_defaults.dirs[DEFAULT_DIR_REMAP]));
125 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER], g_defaults.dirs[DEFAULT_DIR_PORT],
126 "filters", sizeof(g_defaults.dirs[DEFAULT_DIR_VIDEO_FILTER]));
127 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_DATABASE], g_defaults.dirs[DEFAULT_DIR_PORT],
128 "database/rdb", sizeof(g_defaults.dirs[DEFAULT_DIR_DATABASE]));
129 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CURSOR], g_defaults.dirs[DEFAULT_DIR_PORT],
130 "database/cursors", sizeof(g_defaults.dirs[DEFAULT_DIR_CURSOR]));
131 fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_LOGS], g_defaults.dirs[DEFAULT_DIR_CORE],
132 "logs", sizeof(g_defaults.dirs[DEFAULT_DIR_LOGS]));
133 fill_pathname_join(g_defaults.path_config, g_defaults.dirs[DEFAULT_DIR_PORT],
134 FILE_PATH_MAIN_CONFIG, sizeof(g_defaults.path_config));
135
136 #ifndef IS_SALAMANDER
137 dir_check_defaults("custom.ini");
138 #endif
139 }
140
frontend_wiiu_deinit(void * data)141 static void frontend_wiiu_deinit(void *data)
142 {
143 (void)data;
144 }
145
frontend_wiiu_shutdown(bool unused)146 static void frontend_wiiu_shutdown(bool unused)
147 {
148 (void)unused;
149 }
150
frontend_wiiu_init(void * data)151 static void frontend_wiiu_init(void *data)
152 {
153 (void)data;
154 DEBUG_LINE();
155 verbosity_enable();
156 DEBUG_LINE();
157 }
158
frontend_wiiu_get_rating(void)159 static int frontend_wiiu_get_rating(void) { return 10; }
160
frontend_wiiu_get_arch(void)161 enum frontend_architecture frontend_wiiu_get_arch(void)
162 {
163 return FRONTEND_ARCH_PPC;
164 }
165
frontend_wiiu_parse_drive_list(void * data,bool load_content)166 static int frontend_wiiu_parse_drive_list(void *data, bool load_content)
167 {
168 #ifndef IS_SALAMANDER
169 file_list_t *list = (file_list_t *)data;
170 enum msg_hash_enums enum_idx = load_content ?
171 MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
172 MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
173
174 if (!list)
175 return -1;
176
177 menu_entries_append_enum(list, WIIU_SD_PATH,
178 msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
179 enum_idx,
180 FILE_TYPE_DIRECTORY, 0, 0);
181
182 menu_entries_append_enum(list, WIIU_USB_PATH,
183 msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
184 enum_idx,
185 FILE_TYPE_DIRECTORY, 0, 0);
186 menu_entries_append_enum(list, WIIU_STORAGE_USB_PATH,
187 msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR),
188 enum_idx,
189 FILE_TYPE_DIRECTORY, 0, 0);
190 #endif
191 return 0;
192 }
193
frontend_wiiu_exec(const char * path,bool should_load_content)194 static void frontend_wiiu_exec(const char *path, bool should_load_content)
195 {
196 struct
197 {
198 u32 magic;
199 u32 argc;
200 char * argv[3];
201 char args[];
202 }*param = getApplicationEndAddr();
203 int len = 0;
204 param->argc = 0;
205
206 if (!path || !*path)
207 {
208 RARCH_LOG("No executable path provided, cannot Restart\n");
209 }
210
211 DEBUG_STR(path);
212
213 strcpy(param->args + len, elf_path_cst);
214 param->argv[param->argc] = param->args + len;
215 len += strlen(param->args + len) + 1;
216 param->argc++;
217
218 RARCH_LOG("Attempt to load core: [%s].\n", path);
219 #ifndef IS_SALAMANDER
220 if (should_load_content && !path_is_empty(RARCH_PATH_CONTENT))
221 {
222 strcpy(param->args + len, path_get(RARCH_PATH_CONTENT));
223 param->argv[param->argc] = param->args + len;
224 len += strlen(param->args + len) + 1;
225 param->argc++;
226
227 RARCH_LOG("content path: [%s].\n", path_get(RARCH_PATH_CONTENT));
228 }
229 #endif
230 param->argv[param->argc] = NULL;
231
232 {
233 if (HBL_loadToMemory(path, (u32)param->args - (u32)param + len) < 0)
234 RARCH_LOG("Failed to load core\n");
235 else
236 {
237 param->magic = ARGV_MAGIC;
238 ARGV_PTR = param;
239 DEBUG_VAR(param->argc);
240 DEBUG_VAR(param->argv);
241
242 }
243 }
244 }
245
246 #ifndef IS_SALAMANDER
frontend_wiiu_set_fork(enum frontend_fork fork_mode)247 static bool frontend_wiiu_set_fork(enum frontend_fork fork_mode)
248 {
249 switch (fork_mode)
250 {
251 case FRONTEND_FORK_CORE:
252 RARCH_LOG("FRONTEND_FORK_CORE\n");
253 wiiu_fork_mode = fork_mode;
254 break;
255 case FRONTEND_FORK_CORE_WITH_ARGS:
256 RARCH_LOG("FRONTEND_FORK_CORE_WITH_ARGS\n");
257 wiiu_fork_mode = fork_mode;
258 break;
259 case FRONTEND_FORK_RESTART:
260 RARCH_LOG("FRONTEND_FORK_RESTART\n");
261 /* NOTE: We don't implement Salamander, so just turn
262 * this into FRONTEND_FORK_CORE. */
263 wiiu_fork_mode = FRONTEND_FORK_CORE;
264 break;
265 case FRONTEND_FORK_NONE:
266 default:
267 return false;
268 }
269
270 return true;
271 }
272 #endif
273
frontend_wiiu_exitspawn(char * s,size_t len,char * args)274 static void frontend_wiiu_exitspawn(char *s, size_t len, char *args)
275 {
276 bool should_load_content = false;
277 #ifndef IS_SALAMANDER
278 if (wiiu_fork_mode == FRONTEND_FORK_NONE)
279 return;
280
281 switch (wiiu_fork_mode)
282 {
283 case FRONTEND_FORK_CORE_WITH_ARGS:
284 should_load_content = true;
285 break;
286 default:
287 break;
288 }
289 #endif
290 frontend_wiiu_exec(s, should_load_content);
291 }
292
293 frontend_ctx_driver_t frontend_ctx_wiiu =
294 {
295 frontend_wiiu_get_env_settings,
296 frontend_wiiu_init,
297 frontend_wiiu_deinit,
298 frontend_wiiu_exitspawn,
299 NULL, /* process_args */
300 frontend_wiiu_exec,
301 #ifdef IS_SALAMANDER
302 NULL, /* set_fork */
303 #else
304 frontend_wiiu_set_fork,
305 #endif
306 frontend_wiiu_shutdown,
307 NULL, /* get_name */
308 NULL, /* get_os */
309 frontend_wiiu_get_rating,
310 NULL, /* content_loaded */
311 frontend_wiiu_get_arch, /* get_architecture */
312 NULL, /* get_powerstate */
313 frontend_wiiu_parse_drive_list,
314 NULL, /* get_total_mem */
315 NULL, /* get_free_mem */
316 NULL, /* install_signal_handler */
317 NULL, /* get_signal_handler_state */
318 NULL, /* set_signal_handler_state */
319 NULL, /* destroy_signal_handler_state */
320 NULL, /* attach_console */
321 NULL, /* detach_console */
322 NULL, /* get_lakka_version */
323 NULL, /* set_screen_brightness */
324 NULL, /* watch_path_for_changes */
325 NULL, /* check_for_path_changes */
326 NULL, /* set_sustained_performance_mode */
327 NULL, /* get_cpu_model_name */
328 NULL, /* get_user_language */
329 NULL, /* is_narrator_running */
330 NULL, /* accessibility_speak */
331 "wiiu", /* ident */
332 NULL /* get_video_driver */
333 };
334
335 /* main() and its supporting functions */
336
337 static void main_setup(void);
338 static void get_arguments(int *argc, char ***argv);
339 #ifndef IS_SALAMANDER
340 static void main_loop(void);
341 #endif
342 static void main_teardown(void);
343
344 static void init_network(void);
345 static void deinit_network(void);
346 static void init_logging(void);
347 static void deinit_logging(void);
348 static void wiiu_log_init(int port);
349 static void wiiu_log_deinit(void);
350 static ssize_t wiiu_log_write(struct _reent *r, void *fd, const char *ptr, size_t len);
351 static void init_pad_libraries(void);
352 static void deinit_pad_libraries(void);
353 static void SaveCallback(void);
354
355 static struct sockaddr_in broadcast;
356 static int wiiu_log_socket = -1;
357 static volatile int wiiu_log_lock = 0;
358
359 #if !defined(PC_DEVELOPMENT_TCP_PORT)
360 #define PC_DEVELOPMENT_TCP_PORT 4405
361 #endif
362
363 static devoptab_t dotab_stdout =
364 {
365 "stdout_net", /* device name */
366 0, /* size of file structure */
367 NULL, /* device open */
368 NULL, /* device close */
369 wiiu_log_write, /* device write */
370 NULL, /* ... */
371 };
372
main(int argc,char ** argv)373 int main(int argc, char **argv)
374 {
375 main_setup();
376 get_arguments(&argc, &argv);
377
378 #ifdef IS_SALAMANDER
379 int salamander_main(int argc, char **argv);
380 salamander_main(argc, argv);
381 #else
382 rarch_main(argc, argv, NULL);
383 main_loop();
384 main_exit(NULL);
385 #endif /* IS_SALAMANDER */
386 main_teardown();
387
388 /* We always return 0 because if we don't, it can prevent loading a
389 * different RPX/ELF in HBL. */
390 return 0;
391 }
392
get_arguments(int * argc,char *** argv)393 static void get_arguments(int *argc, char ***argv)
394 {
395 DEBUG_VAR(ARGV_PTR);
396 if (ARGV_PTR && ((u32)ARGV_PTR < 0x01000000))
397 {
398 struct
399 {
400 u32 magic;
401 u32 argc;
402 char *argv[3];
403 } *param = ARGV_PTR;
404
405 if (param->magic == ARGV_MAGIC)
406 {
407 *argc = param->argc;
408 *argv = param->argv;
409 }
410 ARGV_PTR = NULL;
411 }
412
413 DEBUG_VAR(argc);
414 DEBUG_VAR(argv[0]);
415 DEBUG_VAR(argv[1]);
416 fflush(stdout);
417 }
418
main_setup(void)419 static void main_setup(void)
420 {
421 setup_os_exceptions();
422 ProcUIInit(&SaveCallback);
423 init_network();
424 init_logging();
425 init_pad_libraries();
426 verbosity_enable();
427 fflush(stdout);
428 }
429
main_teardown(void)430 static void main_teardown(void)
431 {
432 deinit_pad_libraries();
433 ProcUIShutdown();
434 deinit_logging();
435 deinit_network();
436 }
437
438 #ifndef IS_SALAMANDER
swap_is_pending(void * start_time)439 static bool swap_is_pending(void *start_time)
440 {
441 uint32_t swap_count, flip_count;
442 OSTime last_flip, last_vsync;
443
444 GX2GetSwapStatus(&swap_count, &flip_count, &last_flip, &last_vsync);
445 return last_vsync < *(OSTime *)start_time;
446 }
447
main_loop(void)448 static void main_loop(void)
449 {
450 OSTime start_time;
451 int status;
452
453 for (;;)
454 {
455 if (video_driver_get_ptr())
456 {
457 start_time = OSGetSystemTime();
458 task_queue_wait(swap_is_pending, &start_time);
459 }
460 else
461 task_queue_wait(NULL, NULL);
462
463 status = runloop_iterate();
464
465 if (status == -1)
466 break;
467 }
468 }
469 #endif
470
SaveCallback(void)471 static void SaveCallback(void)
472 {
473 OSSavesDone_ReadyToRelease();
474 }
475
476
init_network(void)477 static void init_network(void)
478 {
479 ACInitialize();
480 ACConnect();
481 #ifdef IS_SALAMANDER
482 socket_lib_init();
483 #else
484 network_init();
485 #endif /* IS_SALAMANDER */
486 }
487
deinit_network(void)488 static void deinit_network(void)
489 {
490 ACClose();
491 ACFinalize();
492 }
493
getBroadcastAddress(ACIpAddress * broadcast)494 int getBroadcastAddress(ACIpAddress *broadcast)
495 {
496 ACIpAddress myIp, mySubnet;
497 ACResult result;
498
499 if (!broadcast)
500 return -1;
501
502 result = ACGetAssignedAddress(&myIp);
503 if (result < 0)
504 return -1;
505 result = ACGetAssignedSubnet(&mySubnet);
506 if (result < 0)
507 return -1;
508
509 *broadcast = myIp | (~mySubnet);
510 return 0;
511 }
512
init_logging(void)513 static void init_logging(void)
514 {
515 wiiu_log_init(PC_DEVELOPMENT_TCP_PORT);
516 devoptab_list[STD_OUT] = &dotab_stdout;
517 devoptab_list[STD_ERR] = &dotab_stdout;
518 }
519
deinit_logging(void)520 static void deinit_logging(void)
521 {
522 fflush(stdout);
523 fflush(stderr);
524
525 wiiu_log_deinit();
526 }
527
broadcast_init(int port)528 static int broadcast_init(int port)
529 {
530 ACIpAddress broadcast_ip;
531 if (getBroadcastAddress(&broadcast_ip) < 0)
532 return -1;
533
534 memset(&broadcast, 0, sizeof(broadcast));
535 broadcast.sin_family = AF_INET;
536 broadcast.sin_port = htons(port);
537 broadcast.sin_addr.s_addr = htonl(broadcast_ip);
538
539 return 0;
540 }
541
wiiu_log_init(int port)542 static void wiiu_log_init(int port)
543 {
544 wiiu_log_lock = 0;
545
546 if (wiiu_log_socket >= 0)
547 return;
548
549 if (broadcast_init(port) < 0)
550 return;
551
552 wiiu_log_socket = socket(AF_INET, SOCK_DGRAM, 0);
553
554 if (wiiu_log_socket < 0)
555 return;
556
557 struct sockaddr_in connect_addr;
558 memset(&connect_addr, 0, sizeof(connect_addr));
559 connect_addr.sin_family = AF_INET;
560 connect_addr.sin_port = 0;
561 connect_addr.sin_addr.s_addr = htonl(INADDR_ANY);
562
563 if ( bind(wiiu_log_socket, (struct sockaddr *)&connect_addr, sizeof(connect_addr)) < 0)
564 {
565 socketclose(wiiu_log_socket);
566 wiiu_log_socket = -1;
567 return;
568 }
569 }
570
wiiu_log_deinit(void)571 static void wiiu_log_deinit(void)
572 {
573 if (wiiu_log_socket >= 0)
574 {
575 socketclose(wiiu_log_socket);
576 wiiu_log_socket = -1;
577 }
578 }
579
init_pad_libraries(void)580 static void init_pad_libraries(void)
581 {
582 #ifndef IS_SALAMANDER
583 KPADInit();
584 WPADEnableURCC(true);
585 WPADEnableWiiRemote(true);
586 #endif /* IS_SALAMANDER */
587 }
588
deinit_pad_libraries(void)589 static void deinit_pad_libraries(void)
590 {
591 #ifndef IS_SALAMANDER
592 KPADShutdown();
593 #endif /* IS_SALAMANDER */
594 }
595
596 /* logging routines */
597
net_print(const char * str)598 void net_print(const char *str)
599 {
600 wiiu_log_write(NULL, 0, str, strlen(str));
601 }
602
net_print_exp(const char * str)603 void net_print_exp(const char *str)
604 {
605 sendto(wiiu_log_socket, str, strlen(str), 0, (struct sockaddr *)&broadcast, sizeof(broadcast));
606 }
607
608 /* RFC 791 specifies that any IP host must be able
609 * to receive a datagram of 576 bytes.
610 * Since we're generally never logging more than a
611 * line or two's worth of data (~100 bytes)
612 * this is a reasonable size for our use. */
613 #define DGRAM_SIZE 576
614
wiiu_log_write(struct _reent * r,void * fd,const char * ptr,size_t len)615 static ssize_t wiiu_log_write(struct _reent *r,
616 void *fd, const char *ptr, size_t len)
617 {
618 int remaining;
619 if (wiiu_log_socket < 0)
620 return len;
621
622 while (wiiu_log_lock)
623 OSSleepTicks(((248625000 / 4)) / 1000);
624
625 wiiu_log_lock = 1;
626
627 remaining = len;
628
629 while (remaining > 0)
630 {
631 int block = remaining < DGRAM_SIZE ? remaining : DGRAM_SIZE;
632 int sent = sendto(wiiu_log_socket, ptr, block, 0,
633 (struct sockaddr *)&broadcast, sizeof(broadcast));
634
635 if (sent < 0)
636 break;
637
638 remaining -= sent;
639 ptr += sent;
640 }
641
642 wiiu_log_lock = 0;
643
644 return len;
645 }
646