/* devkitPPC is missing a few functions that are kinda needed for some cores. * This should add them back in. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* This is usually in libogc; we can't use that on wiiu */ int usleep(useconds_t microseconds) { OSSleepTicks(us_to_ticks(microseconds)); return 0; } /* Can't find this one anywhere for some reason :/ */ /* This could probably be done a lot better with some love */ int access(const char* path, int mode) { return 0; /* TODO temp hack, real code below */ FILE* fd = fopen(path, "rb"); if (fd < 0) { fclose(fd); /* We're supposed to set errono here */ return -1; } else { fclose(fd); return 0; } } /* Just hardcode the Linux User ID, we're not on linux anyway */ /* Feasible cool addition: nn::act for this? */ uid_t getuid(void) { return 1000; } /* Fake user info */ /* Not thread safe, but avoids returning local variable, so... */ struct passwd out; struct passwd* getpwuid(uid_t uid) { out.pw_name = "retroarch"; out.pw_passwd = "Wait, what?"; out.pw_uid = uid; out.pw_gid = 1000; out.pw_gecos = "retroarch"; out.pw_dir = "sd:/"; out.pw_shell = "/vol/system_slc/fw.img"; return &out; } /* Basic Cafe OS clock thingy. */ int _gettimeofday_r(struct _reent *ptr, struct timeval* ptimeval, void* ptimezone) { OSTime cosTime; uint64_t cosSecs; uint32_t cosUSecs; time_t unixSecs; /* We need somewhere to put our output */ if (ptimeval == NULL) { errno = EFAULT; return -1; } /* Get Cafe OS clock in seconds; epoch 2000-01-01 00:00 */ cosTime = OSGetTime(); cosSecs = ticks_to_sec(cosTime); /* Get extra milliseconds */ cosUSecs = ticks_to_us(cosTime) - (cosSecs * 1000000); /* Convert to Unix time, epoch 1970-01-01 00:00. Constant value is seconds between 1970 and 2000. time_t is 32bit here, so the Wii U is vulnerable to the 2038 problem. */ unixSecs = cosSecs + 946684800; ptimeval->tv_sec = unixSecs; ptimeval->tv_usec = cosUSecs; return 0; } /* POSIX clock in all its glory */ int clock_gettime(clockid_t clk_id, struct timespec* tp) { struct timeval ptimeval = { 0 }; int ret = 0; if (tp == NULL) { errno = EFAULT; return -1; } switch (clk_id) { case CLOCK_REALTIME: /* Just wrap gettimeofday. Cheating, I know. */ ret = _gettimeofday_r(NULL, &ptimeval, NULL); if (ret) return -1; tp->tv_sec = ptimeval.tv_sec; tp->tv_nsec = ptimeval.tv_usec * 1000; break; default: errno = EINVAL; return -1; } return 0; } /* Fake sysconf for page size and processor count */ long sysconf(int name) { switch (name) { case _SC_PAGESIZE: //case _SC_PAGE_SIZE: return 128 * 1024; case _SC_NPROCESSORS_CONF: case _SC_NPROCESSORS_ONLN: return 3; default: errno = EINVAL; return -1; } } /** * Intended to replace libgcc's __clear_cache builtin. * For cores that need it, add -D__clear_cache=wiiu_clear_cache to CFLAGS. */ void wiiu_clear_cache (char *beg, char *end) { DCFlushRange(beg, (uint32_t)(end - beg)); ICInvalidateRange(beg, (uint32_t)(end - beg)); } /** * Implementation of getifaddrs() and freeifaddrs() for WiiU. */ // the Wii U doesn't define an interface name, so we'll use something generic. static const char *wiiu_iface_name = "eth0"; /** * Allocate and zeroize the hunk of memory for the ifaddrs struct and its contents; the struct will be filled * out later. * * returns NULL if any of the memory allocations fail. */ static struct ifaddrs *buildEmptyIfa(void) { struct ifaddrs *result = (struct ifaddrs *)malloc(sizeof(struct ifaddrs)); if (result) { memset(result, 0, sizeof(struct ifaddrs)); result->ifa_name = strdup(wiiu_iface_name); result->ifa_addr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); result->ifa_netmask = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); result->ifa_dstaddr = (struct sockaddr *)malloc(sizeof(struct sockaddr_in)); if ( !result->ifa_name || !result->ifa_addr || !result->ifa_netmask || !result->ifa_dstaddr) goto error; memset(result->ifa_addr, 0, sizeof(struct sockaddr_in)); result->ifa_addr->sa_family = AF_INET; memset(result->ifa_netmask, 0, sizeof(struct sockaddr_in)); result->ifa_netmask->sa_family = AF_INET; memset(result->ifa_dstaddr, 0, sizeof(struct sockaddr_in)); result->ifa_dstaddr->sa_family = AF_INET; } return result; error: freeifaddrs(result); return NULL; } static int getAssignedAddress(struct sockaddr_in *sa) { ACIpAddress addr; int result; if (!sa) return -1; result = ACGetAssignedAddress(&addr); if (result == 0) sa->sin_addr.s_addr = addr; return result; } static int getAssignedSubnet(struct sockaddr_in *sa) { ACIpAddress mask; int result; if (!sa) return -1; result = ACGetAssignedSubnet(&mask); if (result == 0) sa->sin_addr.s_addr = mask; return result; } static int getBroadcastAddress(struct sockaddr_in *sa, struct sockaddr_in *addr, struct sockaddr_in *mask) { if (!sa || !addr || !mask) return -1; sa->sin_addr.s_addr = addr->sin_addr.s_addr | (~mask->sin_addr.s_addr); return 0; } static struct ifaddrs *getWiiUInterfaceAddressData(void) { struct ifaddrs *result = buildEmptyIfa(); if (result) { if (getAssignedAddress((struct sockaddr_in *)result->ifa_addr) < 0 || getAssignedSubnet((struct sockaddr_in *)result->ifa_netmask) < 0 || getBroadcastAddress((struct sockaddr_in *)result->ifa_dstaddr, (struct sockaddr_in *)result->ifa_addr, (struct sockaddr_in *)result->ifa_netmask) < 0) { goto error; } } return result; error: freeifaddrs(result); return NULL; } int getifaddrs(struct ifaddrs **ifap) { if (!ifap) return -1; *ifap = getWiiUInterfaceAddressData(); return (*ifap == NULL) ? -1 : 0; } void freeifaddrs(struct ifaddrs *ifp) { if (ifp) { if (ifp->ifa_name) { free(ifp->ifa_name); ifp->ifa_name = NULL; } if (ifp->ifa_addr) { free(ifp->ifa_addr); ifp->ifa_addr = NULL; } if (ifp->ifa_netmask) { free(ifp->ifa_netmask); ifp->ifa_netmask = NULL; } if (ifp->ifa_dstaddr) { free(ifp->ifa_dstaddr); ifp->ifa_dstaddr = NULL; } free(ifp); } }