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