diff --git a/common/include/s147_mmio_hwport.h b/common/include/s147_mmio_hwport.h new file mode 100644 index 00000000000..ef986e99219 --- /dev/null +++ b/common/include/s147_mmio_hwport.h @@ -0,0 +1,131 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +/** + * @file + * Definitions for memory-mapped I/O for System 147. + */ + +#ifndef __S147_MMIO_HWPORT__ +#define __S147_MMIO_HWPORT__ + +typedef struct s147_dev9_mem_mmio_ +{ + vu8 m_unk00; + vu8 m_led; + vu8 m_security_unlock_unlock; + vu8 m_unk03; + vu8 m_rtc_flag; + vu8 m_watchdog_flag2; + vu8 m_unk06; + vu8 m_sram_write_flag; + vu8 m_pad08; + vu8 m_pad09; + vu8 m_pad0A; + vu8 m_pad0B; + vu8 m_security_unlock_set1; + vu8 m_security_unlock_set2; +} s147_dev9_mem_mmio_t; + +#if !defined(USE_S147_DEV9_MEM_MMIO) && defined(_IOP) +// cppcheck-suppress-macro constVariablePointer +#define USE_S147_DEV9_MEM_MMIO() s147_dev9_mem_mmio_t *const s147_dev9_mem_mmio = (s147_dev9_mem_mmio_t *)0xB0000000 +#endif +#if !defined(USE_S147_DEV9_MEM_MMIO) +#define USE_S147_DEV9_MEM_MMIO() +#endif + +typedef struct s147nand_dev9_io_mmio_ +{ + vu8 m_nand_waitflag; // 0 (R/B) + vu8 m_nand_cmd_enable; // 1 (CE+WE) + vu8 m_nand_cmd_sel; // 10 (CE+WE+CLE) + vu8 m_nand_cmd_offs; // 11 (CE+WE+ALE) + vu8 m_nand_write_cmd_unlock; // 100 + vu8 m_pad05; + vu8 m_pad06; + vu8 m_pad07; + vu8 m_nand_outbyte; // 1000 (CE+RE) +} s147nand_dev9_io_mmio_t; + +#if !defined(USE_S147MAMD_DEV9_IO_MMIO) && defined(_IOP) +// cppcheck-suppress-macro constVariablePointer +#define USE_S147MAMD_DEV9_IO_MMIO() s147nand_dev9_io_mmio_t *const s147nand_dev9_io_mmio = (s147nand_dev9_io_mmio_t *)0xB4000000 +#endif +#if !defined(USE_S147MAMD_DEV9_IO_MMIO) +#define USE_S147MAMD_DEV9_IO_MMIO() +#endif + +typedef struct s147link_dev9_mem_mmio_ +{ + vu8 m_pad00; + vu8 m_unk01; + vu8 m_pad02; + vu8 m_unk03; + vu8 m_pad04; + vu8 m_node_unk05; + vu8 m_pad06; + vu8 m_unk07; + vu8 m_pad08; + vu8 m_unk09; + vu8 m_pad0A; + vu8 m_pad0B; + vu8 m_pad0C; + vu8 m_unk0D; + vu8 m_pad0E; + vu8 m_pad0F; + vu8 m_pad10; + vu8 m_pad11; + vu8 m_stsH_unk12; + vu8 m_stsL_unk13; + vu8 m_unk14; + vu8 m_unk15; + vu8 m_pad16; + vu8 m_unk17; + vu8 m_pad18; + vu8 m_pad19; + vu8 m_pad1A; + vu8 m_pad1B; + vu8 m_unk1C; + vu8 m_unk1D; + vu8 m_rxfc_hi_unk1E; + vu8 m_rxfc_lo_unk1F; + vu8 m_pad20; + vu8 m_unk21; + vu8 m_unk22; + vu8 m_unk23; + vu8 m_unk24; + vu8 m_unk25; + vu8 m_pad26; + vu8 m_pad27; + vu8 m_unk28; + vu8 m_unk29; + vu8 m_pad2A; + vu8 m_maxnode_unk2B; + vu8 m_pad2C; + vu8 m_mynode_unk2D; + vu8 m_pad2E; + vu8 m_unk2F; + vu8 m_pad30; + vu8 m_unk31; + vu8 m_pad32; + vu8 m_pad33; + vu8 m_watchdog_flag_unk34; +} s147link_dev9_mem_mmio_t; + +#if !defined(USE_S147LINK_DEV9_MEM_MMIO) && defined(_IOP) +// cppcheck-suppress-macro constVariablePointer +#define USE_S147LINK_DEV9_MEM_MMIO() s147link_dev9_mem_mmio_t *const s147link_dev9_mem_mmio = (s147link_dev9_mem_mmio_t *)0xB0800000 +#endif +#if !defined(USE_S147LINK_DEV9_MEM_MMIO) +#define USE_S147LINK_DEV9_MEM_MMIO() +#endif + +#endif /* __S147_MMIO_HWPORT__ */ diff --git a/iop/arcade/Makefile b/iop/arcade/Makefile index a1e81fde98c..7a84181aded 100644 --- a/iop/arcade/Makefile +++ b/iop/arcade/Makefile @@ -25,7 +25,13 @@ SUBDIRS = \ acsram \ actimer \ acuart \ - acuart_tty + acuart_tty \ + romwrite \ + s147ctrl \ + s147link \ + s147mdev \ + s147nand \ + s147netb include $(PS2SDKSRC)/Defs.make include $(PS2SDKSRC)/Rules.make diff --git a/iop/arcade/romwrite/Makefile b/iop/arcade/romwrite/Makefile new file mode 100644 index 00000000000..e0310bf12c6 --- /dev/null +++ b/iop/arcade/romwrite/Makefile @@ -0,0 +1,25 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= romwrite.irx + +IOP_IMPORT_INCS += \ + system/intrman \ + system/ioman \ + arcade/s147nand \ + system/sysclib \ + system/sysmem \ + system/loadcore \ + system/threadman + +IOP_OBJS = romwrite.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/romwrite/README.md b/iop/arcade/romwrite/README.md new file mode 100644 index 00000000000..88e9835a891 --- /dev/null +++ b/iop/arcade/romwrite/README.md @@ -0,0 +1,15 @@ +# ROMWRITE + +This module allows access to writing the NAND flash of System 147. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `romwrite` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with arguments. diff --git a/iop/arcade/romwrite/src/imports.lst b/iop/arcade/romwrite/src/imports.lst new file mode 100644 index 00000000000..d36fd9c2fdb --- /dev/null +++ b/iop/arcade/romwrite/src/imports.lst @@ -0,0 +1,57 @@ + +s147nand_IMPORTS_start +I_s147nand_6_checkformat +I_s147nand_7_multi_read_dma +I_s147nand_8_multi_write_dma +I_s147nand_9_get_nand_partition +I_s147nand_10_get_nand_partition_size +I_s147nand_11_erasetranslatepageoffs +I_s147nand_12_load_logaddrtable +I_s147nand_13_translate_blockoffs +I_s147nand_16_getnandinfo +I_s147nand_22_nand_write_dma +I_s147nand_24_eraseoffset +I_s147nand_25_nand_blockerase +I_s147nand_26_nand_readid +I_s147nand_27_blocks2pages +I_s147nand_28_pages2blocks +I_s147nand_29_pages2blockround +I_s147nand_30_bytes2pagesnoeccround +s147nand_IMPORTS_end + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +I_Kprintf +sysmem_IMPORTS_end + +intrman_IMPORTS_start +I_CpuSuspendIntr +I_CpuResumeIntr +intrman_IMPORTS_end + +ioman_IMPORTS_start +I_open +I_close +I_read +I_lseek +ioman_IMPORTS_end + +sysclib_IMPORTS_start +I_memset +I_sprintf +I_strcat +I_strcmp +I_strcpy +I_strncmp +I_strncpy +I_strtol +I_vsprintf +sysclib_IMPORTS_end + +thbase_IMPORTS_start +I_CreateThread +I_StartThread +I_ExitThread +I_DelayThread +thbase_IMPORTS_end diff --git a/iop/arcade/romwrite/src/irx_imports.h b/iop/arcade/romwrite/src/irx_imports.h new file mode 100644 index 00000000000..7f11a789c02 --- /dev/null +++ b/iop/arcade/romwrite/src/irx_imports.h @@ -0,0 +1,26 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/romwrite/src/romwrite.c b/iop/arcade/romwrite/src/romwrite.c new file mode 100644 index 00000000000..72037b208c7 --- /dev/null +++ b/iop/arcade/romwrite/src/romwrite.c @@ -0,0 +1,1063 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include +#include +#include + +IRX_ID("ROMWRITE", 7, 1); +// Text section hash: +// 6674c59e79963dd4c1d7f6fccfecbf70 + +typedef struct nand_id_desc_info_ +{ + u32 m_id[5]; + const char *m_nand_name; + const char *m_nand_desc; + int m_page_size_noecc; + int m_page_size_withecc; + int m_pages_per_block; + int m_block_size; +} nand_id_desc_info_t; + +typedef union romwrite_part_buf_ +{ + u8 m_buf[0x20000]; + s147nand_header_t m_hdr; + s147nand_dir_t m_dir; + s147nand_direntry_t m_direntry[64]; +} romwrite_part_buf_t; + +static void thread_proc(void *userdata); +static void do_toggle_dev9addr_inner(int len, int cnt); +static void set_boot_video_mode(int flg); +static void do_set_flag(int flg); +static void do_set_secr_code(char code1, char code2); +static void do_handle_atfile_image(int part, const char *str); +static void do_set_atfile_147_dir(const char *str); +static int do_start_write_proc(void); +static int do_format_device(int abspart); +static int do_write_partition(int part); +static int check_badblock_count(void); +static int get_nand_partition_offset(int part, int abspart); +static int get_nand_partition_size(int part, int abspart); +static int get_nand_block_size_div_32_div_64(void); +static int get_nand_block_size_div_32(void); +static void do_dma_write_bytes_multi(void *ptr, int pageoffs, int pagecnt); +static int do_list_files(int part); +static void do_output_bb_info(int blocksd, int abspart, int bboffs); +static int do_verify(void *buf1, void *buf2, int len); +static const nand_id_desc_info_t *do_parse_device_info(const char *nandid); +// Unofficial: printf to IOP Kprintf instead of EE +#define USER_PRINTF(...) Kprintf(__VA_ARGS__) +// Unofficial: printf to EE is omitted +#define STATUS_PRINTF(...) Kprintf(__VA_ARGS__) + +static const nand_id_desc_info_t g_nand_type_info[4] = { + { + {0xEC, 0xDA, 0xFFFFFFFF, 0x15, 0xFFFFFFFF}, + "SAMSUNG K9F2G08U0M", + "8bit width, 256MBytes", + 0x800, + 0x840, + 0x40, + 0x800, + }, + { + {0xEC, 0xDC, 0x10, 0x95, 0x54}, + "SAMSUNG K9F4G08U0M", + "8bit width, 512MBytes", + 0x800, + 0x840, + 0x40, + 0x1000, + }, + { + {0xEC, 0xD3, 0x51, 0x95, 0x58}, + "SAMSUNG K9K8G08U0M", + "8bit width, 1GBytes", + 0x800, + 0x840, + 0x40, + 0x2000, + }, + {{0x0, 0x0, 0x0, 0x0, 0x0}, NULL, NULL, 0, 0, 0, 0}}; +// Unofficial: move to bss +static char g_secr_code[2]; +// Unofficial: move to bss +static int g_curflag; +// Unofficial: move to bss +static int g_boot_video_mode; +// Unofficial: move to bss +static char *g_page_buf; +// Unofficial: move to bss +static int g_badblock_count; +static char g_product_code_tmp[32]; +static u8 *g_blockinfo_str_buf; +static u16 *g_blockinfo_dat_buf; +static const nand_id_desc_info_t *g_device_info; +static char g_atfile_part_image[8][0x100]; +static char g_atfile_info_image[0x100]; +static char g_atfile_147_dir[0x100]; +static romwrite_part_buf_t g_nand_partbuf __attribute__((__aligned__(16))); + +static void do_format_nand_device(char devindchr) +{ + switch ( devindchr ) + { + case '2': + do_set_flag(0x10000); + break; + case '4': + do_set_flag(0x20000); + break; + case '8': + do_set_flag(0x30000); + break; + default: + do_set_flag(0xF0000); + devindchr = ' '; + break; + } + STATUS_PRINTF(" -f%c: Format NAND(atfile:) device\n", devindchr); +} + +static char *do_read_product_code(int fd) +{ + read(fd, g_product_code_tmp, sizeof(g_product_code_tmp)); + STATUS_PRINTF(" ---> OK, set product code - \"%s\"\n", &g_product_code_tmp[16]); + // Unofficial: omit Blowfish hashing S147NBGI + return &g_product_code_tmp[4]; +} + +int _start(int ac, char **av) +{ + iop_thread_t thparam; + int thid; + int i; + char secrcode1; + char secrcode2; + int fd; + const char *product_code; + int image_file_idx; + + // Unofficial: omit SIF output command set to 30 + if ( ac < 2 ) + { + USER_PRINTF("SYS147 ROM Writer (version 0x%04x)\n\n", 0x701); + DelayThread(10000); + USER_PRINTF("usage: %s [OPTION]... [FILE]...\n", "romwrite.irx"); + DelayThread(10000); + USER_PRINTF(" -m, --main ............. MainPCB mode (Send PRINTF to EE)\n"); + DelayThread(10000); + USER_PRINTF(" -s0 .................... Set default security code\n"); + DelayThread(10000); + USER_PRINTF(" -sr .................... Read \"s147secr.147\" and set security code\n"); + DelayThread(10000); + USER_PRINTF(" -f(f2, f4, f8) ......... Format NAND(atfile:) device\n"); + DelayThread(10000); + USER_PRINTF(" -0([1..7]) filename .... Write \"atfile[0..7]:\" image file\n"); + DelayThread(10000); + USER_PRINTF(" -d directory ........... Search \"atfile*.147\" in the directory and Write\n"); + DelayThread(10000); + USER_PRINTF(" -i filename ............ Write \"atfile9:info\" image from file\n"); + DelayThread(10000); + USER_PRINTF(" -l ..................... Read NAND device and Display all file list\n"); + DelayThread(10000); + USER_PRINTF(" -v, --vga .............. Set boot video mode (VGA)\n"); + DelayThread(10000); + return MODULE_NO_RESIDENT_END; + } + // Unofficial: init var here instead + g_badblock_count = 1; + USER_PRINTF("\n====== romwrite(version 0x%04x): Check argument ======\n", 0x701); + DelayThread(10000); + for ( i = 1; i < ac; i += 1 ) + { + if ( !strcmp(av[i], "-m") || !strcmp(av[i], "--main") ) + { + USER_PRINTF(" -m, --main : MainPCB mode (Send PRINTF to EE)\n"); + DelayThread(10000); + // Unofficial: Flag setting omitted + break; + } + if ( !strcmp(av[i], "-v") || !strcmp(av[i], "--vga") ) + { + USER_PRINTF(" -v, --vga : Set boot video mode (VGA)\n"); + DelayThread(10000); + set_boot_video_mode(2); + break; + } + } + for ( i = 1; i < ac; i += 1 ) + { + if ( av[i][0] != '-' ) + continue; + switch ( av[i][1] ) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + image_file_idx = strtol(av[i] + 1, 0, 10); + STATUS_PRINTF(" -%d : Write \"atfile%d:\" image file\n", image_file_idx, image_file_idx); + do_set_flag(1 << image_file_idx); + i += 1; + do_handle_atfile_image(image_file_idx, av[i]); + break; + case 'd': + STATUS_PRINTF(" -d : Search \"atfile*.147\" in the directory and Write\n"); + i += 1; + do_set_flag(0x2000000); + do_set_atfile_147_dir(av[i]); + break; + case 'f': + do_format_nand_device(av[i][2]); + break; + case 'i': + STATUS_PRINTF(" -i : Write \"atfile9:info\" image\n"); + do_set_flag(0x200); + i += 1; + do_handle_atfile_image(9, av[i]); + break; + case 'l': + STATUS_PRINTF(" -l : Read NAND device and Display all file list\n"); + do_set_flag(0x4000000); + break; + case 's': + switch ( av[i][2] ) + { + case '0': + STATUS_PRINTF(" -s0: Set default security code\n"); + do_set_flag(0x1000000); + do_set_secr_code(0xFF, 0xFF); + break; + case 'r': + STATUS_PRINTF(" -sr: Read \"s147secr.147\" file\n"); + do_set_flag(0x1000000); + i += 1; + fd = open(av[i], O_RDONLY); + if ( fd < 0 ) + { + STATUS_PRINTF(" ---> File not found, set default code\n"); + do_set_secr_code(0xFF, 0xFF); + break; + } + product_code = do_read_product_code(fd); + do_set_secr_code(product_code[0], product_code[1]); + close(fd); + break; + default: + STATUS_PRINTF(" -s : Set immediate secrity code\n"); + i += 1; + secrcode1 = strtol(av[i], 0, 10); + i += 1; + secrcode2 = strtol(av[i], 0, 10); + do_set_flag(0x1000000); + do_set_secr_code(secrcode1, secrcode2); + break; + } + break; + default: + break; + } + } + STATUS_PRINTF("\n"); + thparam.attr = TH_C; + thparam.thread = thread_proc; + thparam.priority = 0x7A; + thparam.stacksize = 0x80000; + thparam.option = 0; + thid = CreateThread(&thparam); + if ( thid <= 0 ) + return MODULE_NO_RESIDENT_END; + StartThread(thid, 0); + return MODULE_RESIDENT_END; +} + +static void thread_proc(void *userdata) +{ + int i; + USE_S147_DEV9_MEM_MMIO(); + + (void)userdata; + if ( do_start_write_proc() ) + { + STATUS_PRINTF("\n****** Aborted ******\n\n"); + for ( ;; ) + { + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + s147_dev9_mem_mmio->m_led = 1; + DelayThread(250000); + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + s147_dev9_mem_mmio->m_led = 0; + DelayThread(250000); + } + } + STATUS_PRINTF("====== Completed ======\n\n"); + for ( ;; ) + { + for ( i = 1; i < 20; i += 1 ) + { + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + do_toggle_dev9addr_inner(5 * i, 50); + } + for ( i = 20; i > 0; i -= 1 ) + { + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + do_toggle_dev9addr_inner(5 * i, 50); + } + } +} + +static void do_toggle_dev9addr_inner(int len, int cnt) +{ + int i; + USE_S147_DEV9_MEM_MMIO(); + + for ( i = 0; i < cnt; i += 1 ) + { + if ( len > 0 ) + { + s147_dev9_mem_mmio->m_led = 3; + DelayThread(10 * len); + } + if ( len < 100 ) + { + s147_dev9_mem_mmio->m_led = 0; + DelayThread(10 * (100 - len)); + } + } +} + +// Unused function omitted + +static unsigned int generate_acio_delay_val(char dmat_val, char rddl_val, char wrdl_val) +{ + return (((dmat_val - 1) & 0xF) << 24) | (((rddl_val - 1) & 0xF) << 4) | 0xA01A0100 | ((wrdl_val - 1) & 0xF); +} + +// Unused function omitted + +// Send print to OSDSYS related omitted + +static void set_boot_video_mode(int flg) +{ + g_boot_video_mode = flg; +} + +static void do_set_flag(int flg) +{ + g_curflag |= flg; +} + +static void do_set_secr_code(char code1, char code2) +{ + g_secr_code[0] = code1; + g_secr_code[1] = code2; +} + +static void do_handle_atfile_image(int part, const char *str) +{ + if ( part == 9 ) + { + strcpy(g_atfile_info_image, str); + return; + } + if ( part >= 0 && part < 8 && g_atfile_part_image[part] != str ) + { + // Unofficial: check if pointer is different + strcpy(g_atfile_part_image[part], str); + } +} + +static void do_set_atfile_147_dir(const char *str) +{ + strcpy(g_atfile_147_dir, str); +} + +static int do_start_write_proc(void) +{ + s147nand_info_t *nandinf; + int state; + int part; + int logaddrtable; + u8 nandid[5]; + USE_S147_DEV9_MEM_MMIO(); + + close(open("ctrl99:watchdog-stop", O_RDONLY)); + if ( (g_curflag & 0x1000000) != 0 ) + { + STATUS_PRINTF("====== Set security code ======\n"); + s147_dev9_mem_mmio->m_security_unlock_set1 = g_secr_code[0]; + s147_dev9_mem_mmio->m_security_unlock_set2 = g_secr_code[1]; + STATUS_PRINTF("\n"); + } + STATUS_PRINTF("====== Device information ======\n"); + s147nand_26_nand_readid(nandid); + g_device_info = do_parse_device_info((char *)nandid); + if ( !g_device_info ) + { + STATUS_PRINTF(" ID = %02X/%02X/%02X/%02X/%02X\n", nandid[0], nandid[1], nandid[2], nandid[3], nandid[4]); + STATUS_PRINTF("\nError: Unknown Device\n"); + return -1; + } + STATUS_PRINTF(" ID = %02X/%02X/%02X/%02X/%02X\n", nandid[0], nandid[1], nandid[2], nandid[3], nandid[4]); + STATUS_PRINTF(" \"%s\", %s\n", g_device_info->m_nand_name, g_device_info->m_nand_desc); + STATUS_PRINTF( + " PageSize = %d + %d (Bytes)\n", + g_device_info->m_page_size_noecc, + g_device_info->m_page_size_withecc - g_device_info->m_page_size_noecc); + STATUS_PRINTF(" Pages/Block = %d (Pages)\n", g_device_info->m_pages_per_block); + STATUS_PRINTF(" BlockSize = %d (Blocks)\n", g_device_info->m_block_size); + STATUS_PRINTF("\n"); + CpuSuspendIntr(&state); + g_blockinfo_str_buf = (u8 *)AllocSysMemory(ALLOC_FIRST, g_device_info->m_block_size, 0); + g_blockinfo_dat_buf = (u16 *)AllocSysMemory(ALLOC_FIRST, sizeof(u16) * g_device_info->m_block_size, 0); + CpuResumeIntr(state); + if ( !g_blockinfo_str_buf || !g_blockinfo_dat_buf ) + { + STATUS_PRINTF("\nError: AllocSysMemory failed\n\n"); + return -1; + } + nandinf = s147nand_16_getnandinfo(); + CpuSuspendIntr(&state); + nandinf->m_page_size_noecc = g_device_info->m_page_size_noecc; + nandinf->m_page_size_withecc = g_device_info->m_page_size_withecc; + nandinf->m_pages_per_block = g_device_info->m_pages_per_block; + nandinf->m_block_size = g_device_info->m_block_size; + nandinf->m_page_count = g_device_info->m_block_size * g_device_info->m_pages_per_block; + CpuResumeIntr(state); + logaddrtable = 0; + switch ( g_curflag & 0xFF0000 ) + { + case 0x10000: + logaddrtable = do_format_device(2); + break; + case 0x20000: + logaddrtable = do_format_device(4); + break; + case 0x30000: + logaddrtable = do_format_device(8); + break; + case 0xF0000: + logaddrtable = do_format_device(0); + break; + default: + break; + } + if ( logaddrtable ) + return logaddrtable; + s147nand_6_checkformat(); + close(open("atfile9:acdelay", O_RDONLY)); + if ( (g_curflag & 0x2000000) != 0 ) + { + STATUS_PRINTF("====== Search directory ======\n"); + for ( part = 0; part < 8; part += 1 ) + { + int fd; + + if ( s147nand_10_get_nand_partition_size(part) <= 0 ) + { + STATUS_PRINTF(" atfile%d: Unformatted - Do nothing\n", part); + continue; + } + sprintf(g_atfile_part_image[part], "%satfile%d.147", g_atfile_147_dir, part); + fd = open(g_atfile_part_image[part], O_RDONLY); + if ( fd < 0 ) + { + DelayThread(10000); + continue; + } + do_set_flag(1 << part); + do_handle_atfile_image(part, g_atfile_part_image[part]); + close(fd); + STATUS_PRINTF(" \"%s\" is found\n", g_atfile_part_image[part]); + } + STATUS_PRINTF(" \n"); + } + for ( part = 0; part < 8; part += 1 ) + { + if ( ((1 << part) & g_curflag) == 0 ) + continue; + STATUS_PRINTF("====== Write \"%s\" to atfile%d: ======\n", g_atfile_part_image[part], part); + logaddrtable = do_write_partition(part); + if ( logaddrtable ) + return logaddrtable; + STATUS_PRINTF(" \n"); + } + if ( (g_curflag & 0x200) != 0 ) + { + STATUS_PRINTF("====== Write \"%s\" to \"atfile9:info\" ======\n", g_atfile_info_image); + logaddrtable = do_write_partition(9); + if ( logaddrtable ) + return logaddrtable; + STATUS_PRINTF(" \n"); + } + if ( (g_curflag & 0x4000000) != 0 ) + { + STATUS_PRINTF("====== Display file list ======\n"); + logaddrtable = s147nand_12_load_logaddrtable(); + if ( logaddrtable ) + { + STATUS_PRINTF(" Error: Unformatted device (%d)\n", logaddrtable); + return logaddrtable; + } + for ( part = 0; part < 8; part += 1 ) + do_list_files(part); + } + return 0; +} + +static int do_format_device(int abspart) +{ + int blocks; + int bboffs; + int nand_partition_offset; + int bbcnt1; + int i; + USE_S147_DEV9_MEM_MMIO(); + + STATUS_PRINTF("====== Format NAND device ======\n"); + STATUS_PRINTF(" [1/3]Block Erase and Check Bad Blocks\n"); + STATUS_PRINTF(" BadBlock ="); + for ( blocks = 0; blocks < g_device_info->m_block_size; blocks += 1 ) + { + int eraseres; + + s147_dev9_mem_mmio->m_led = (blocks >> 4) & 3; + eraseres = blocks ? s147nand_24_eraseoffset(s147nand_27_blocks2pages(blocks)) : + s147nand_25_nand_blockerase(s147nand_27_blocks2pages(0)); + switch ( eraseres ) + { + case -1470020: + g_blockinfo_str_buf[blocks] = 'X'; + STATUS_PRINTF(" %d", blocks); + break; + case 0: + g_blockinfo_str_buf[blocks] = '='; + break; + default: + STATUS_PRINTF(" %d*(%d)", blocks, eraseres); + break; + } + } + STATUS_PRINTF("\n\n"); + STATUS_PRINTF(" [2/3]Replace Bad Blocks ('B':Boot, 'I':Info, 'X':Broken, 'R':Reserved, '@':Occupied)\n"); + g_blockinfo_dat_buf[0] = 0xEEEE; + g_blockinfo_str_buf[0] = 'B'; + nand_partition_offset = get_nand_partition_offset(8, 8); + for ( blocks = 1; blocks < nand_partition_offset - 1; blocks += 1 ) + { + if ( g_blockinfo_str_buf[blocks] != '=' ) + continue; + g_blockinfo_dat_buf[blocks] = 0xEEEE; + g_blockinfo_str_buf[blocks] = 'R'; + } + bbcnt1 = 0; + if ( g_blockinfo_str_buf[nand_partition_offset - 1] == 'X' ) + { + bbcnt1 = check_badblock_count(); + if ( bbcnt1 >= 0 ) + { + g_blockinfo_dat_buf[nand_partition_offset - 1] = bbcnt1; + g_blockinfo_dat_buf[bbcnt1] = 0xCCCC; + g_blockinfo_str_buf[bbcnt1] = '@'; + bboffs = bbcnt1; + } + } + else + { + g_blockinfo_dat_buf[nand_partition_offset - 1] = 0xAAAA; + bboffs = nand_partition_offset - 1; + } + if ( bbcnt1 >= 0 ) + { + for ( blocks = nand_partition_offset; blocks < g_device_info->m_block_size; blocks += 1 ) + { + if ( g_blockinfo_str_buf[blocks] != 'X' ) + { + g_blockinfo_dat_buf[blocks] = 0xAAAA; + continue; + } + bbcnt1 = check_badblock_count(); + if ( bbcnt1 < 0 ) + break; + g_blockinfo_dat_buf[blocks] = bbcnt1; + g_blockinfo_dat_buf[bbcnt1] = 0xCCCC; + g_blockinfo_str_buf[bbcnt1] = '@'; + } + } + if ( bbcnt1 < 0 ) + { + STATUS_PRINTF(" Error: Too many bad blocks to replace\n"); + return -1; + } + for ( blocks = 0; blocks < g_device_info->m_block_size; blocks += 1 ) + { + do_output_bb_info(blocks, abspart, bboffs); + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + } + STATUS_PRINTF("\n"); + STATUS_PRINTF(" [3/3]Write Boot Sector and Logical Address Table\n"); + memset(&g_nand_partbuf.m_hdr, 0, sizeof(g_nand_partbuf.m_hdr)); + strncpy(g_nand_partbuf.m_hdr.m_sig, "S147NAND", 9); + g_nand_partbuf.m_hdr.m_bootsector_ver_1 = 3; + g_nand_partbuf.m_hdr.m_bootsector_ver_2 = 0; + for ( i = 0; i < 8; i += 1 ) + { + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_offset = get_nand_partition_offset(i, abspart); + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_size = get_nand_partition_size(i, abspart); + STATUS_PRINTF( + " atfile%d: StartBlock = 0x%04x(%4d) / BlockSize = 0x%04x(%4d)\n", + i, + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_offset, + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_offset, + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_size, + g_nand_partbuf.m_hdr.m_nand_partition_info[i].m_size); + } + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_offset = get_nand_partition_offset(8, abspart); + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_size = get_nand_partition_size(8, abspart); + STATUS_PRINTF( + " system : StartBlock = 0x%04x(%4d) / BlockSize = 0x%04x(%4d)\n", + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_offset, + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_offset, + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_size, + g_nand_partbuf.m_hdr.m_nand_partition_8_info.m_size); + STATUS_PRINTF("\n"); + g_nand_partbuf.m_hdr.m_nand_seccode[0] = g_secr_code[0]; + g_nand_partbuf.m_hdr.m_nand_seccode[1] = g_secr_code[1]; + g_nand_partbuf.m_hdr.m_nand_vidmode[0] = g_boot_video_mode; + strncpy(g_nand_partbuf.m_hdr.m_nand_desc, g_device_info->m_nand_name, sizeof(g_nand_partbuf.m_hdr.m_nand_desc)); + g_nand_partbuf.m_hdr.m_page_size_noecc = g_device_info->m_page_size_noecc; + g_nand_partbuf.m_hdr.m_page_size_withecc = g_device_info->m_page_size_withecc; + g_nand_partbuf.m_hdr.m_pages_per_block = g_device_info->m_pages_per_block; + g_nand_partbuf.m_hdr.m_block_size = g_device_info->m_block_size; + g_nand_partbuf.m_hdr.m_acmem_delay_val = 0; + g_nand_partbuf.m_hdr.m_acio_delay_val = generate_acio_delay_val(3, 3, 3); + s147nand_22_nand_write_dma(&g_nand_partbuf.m_hdr, 0, 0, sizeof(g_nand_partbuf.m_hdr)); + do_dma_write_bytes_multi(g_blockinfo_dat_buf, 1, sizeof(u16) * g_device_info->m_block_size); + return 0; +} + +static int do_write_partition(int part) +{ + int fd; + int state; + int bytes; + int pages; + int blocks; + int partblocks1; + int actual_readres; + int expected_readres; + int err; + USE_S147_DEV9_MEM_MMIO(); + + actual_readres = 0; + expected_readres = 0; + err = 0; + if ( part == 9 ) + { + partblocks1 = (s147nand_9_get_nand_partition(8) - 1) * g_device_info->m_pages_per_block; + if ( partblocks1 < 0 ) + { + STATUS_PRINTF(" Error: No partition #0 table\n"); + return -1; + } + fd = open(g_atfile_info_image, O_RDONLY); + if ( fd < 0 ) + { + STATUS_PRINTF(" Error: File not found - \"%s\"\n", g_atfile_info_image); + return -1; + } + } + else + { + partblocks1 = s147nand_9_get_nand_partition(part) * g_device_info->m_pages_per_block; + if ( partblocks1 < 0 ) + { + STATUS_PRINTF(" Error: Invalid unit number\n"); + return -1; + } + fd = open(g_atfile_part_image[part], O_RDONLY); + if ( fd < 0 ) + { + STATUS_PRINTF(" Error: File not found - \"%s\"\n", g_atfile_part_image[part]); + return -1; + } + } + CpuSuspendIntr(&state); + g_page_buf = (char *)AllocSysMemory(ALLOC_FIRST, g_device_info->m_page_size_noecc, 0); + CpuResumeIntr(state); + if ( !g_page_buf ) + { + STATUS_PRINTF("\nError: AllocSysMemory failed\n\n"); + err = 1; + } + if ( !err ) + { + if ( part == 9 ) + { + bytes = lseek(fd, 0, SEEK_END); + if ( g_device_info->m_page_size_noecc < bytes ) + { + STATUS_PRINTF(" Error: INFO image file is too large - \"%s\"\n", g_atfile_info_image); + STATUS_PRINTF(" FileSize(%d) > info(%d)\n", bytes, g_device_info->m_page_size_noecc); + err = 1; + } + if ( !err ) + { + lseek(fd, 0, SEEK_SET); + expected_readres = 8; + actual_readres = read(fd, g_page_buf, expected_readres); + if ( actual_readres < expected_readres ) + err = 1; + if ( !err ) + { + if ( strncmp(g_page_buf, "S147INFO", 8) ) + { + STATUS_PRINTF(" Error: \"%s\" is not a S147INFO-image file\n", g_atfile_info_image); + err = 1; + } + if ( !err ) + { + pages = 1; + blocks = 1; + } + } + } + } + else + { + int partsizebytes; + + bytes = lseek(fd, 0, SEEK_END); + partsizebytes = + s147nand_10_get_nand_partition_size(part) * g_device_info->m_pages_per_block * g_device_info->m_page_size_noecc; + if ( partsizebytes < bytes ) + { + STATUS_PRINTF(" Error: ROM image file is too large - \"%s\"\n", g_atfile_part_image[part]); + STATUS_PRINTF(" FileSize(%d) > atfile%d(%d)\n", bytes, part, partsizebytes); + err = 1; + } + if ( !err ) + { + lseek(fd, 0, SEEK_SET); + expected_readres = 0x20; + actual_readres = read(fd, g_page_buf, expected_readres); + if ( actual_readres < expected_readres ) + err = 1; + if ( !err ) + { + if ( strncmp(g_page_buf, "S147ROM", 8) ) + { + STATUS_PRINTF(" Error: \"%s\" is not a S147ROM-image file\n", g_atfile_part_image[part]); + err = 1; + } + if ( !err ) + { + pages = s147nand_30_bytes2pagesnoeccround(bytes); + blocks = s147nand_29_pages2blockround(pages); + } + } + } + } + } + if ( !err ) + { + int xind2; + int xind1; + int pageoffs; + int finished; + + STATUS_PRINTF(" FileSize = %dbytes SectorSize=%dsectors BlockSize=%dblocks\n", bytes, pages, blocks); + lseek(fd, 0, SEEK_SET); + xind2 = 0; + pageoffs = partblocks1; + finished = 0; + for ( xind1 = 0; xind1 < blocks; xind1 += 1 ) + { + int xind3; + + STATUS_PRINTF( + " atfile%d(%d/%d): LogBlock=%d (PhyBlock=%d) ", + part, + xind1, + blocks - 1, + s147nand_28_pages2blocks(pageoffs), + s147nand_13_translate_blockoffs(s147nand_28_pages2blocks(pageoffs))); + s147_dev9_mem_mmio->m_led = s147nand_28_pages2blocks(pageoffs) & 3; + if ( (g_curflag & 0xFF0000) == 0 ) + { + STATUS_PRINTF("Erase -> "); + if ( s147nand_11_erasetranslatepageoffs(pageoffs) == -1470020 ) + { + STATUS_PRINTF("\nromwrite: Bad block error, use \"-f\" option.\n"); + err = 1; + break; + } + } + STATUS_PRINTF("Write -> Verify\n"); + for ( xind3 = 0; xind3 < g_device_info->m_pages_per_block; ) + { + int i; + + // Unofficial: don't use global variable for partition buffer + if ( part != 9 ) + { + int xindbytes; + + xindbytes = bytes - xind2 * g_device_info->m_page_size_noecc; + expected_readres = (xindbytes > 0x20000) ? 0x20000 : xindbytes; + } + else + { + memset(g_nand_partbuf.m_buf, 0, g_device_info->m_page_size_noecc); + expected_readres = (g_device_info->m_page_size_noecc < bytes) ? g_device_info->m_page_size_noecc : bytes; + } + // Unofficial: check against read bytes instead of 0 + actual_readres = read(fd, g_nand_partbuf.m_buf, expected_readres); + if ( actual_readres < expected_readres ) + { + err = 1; + finished = 1; + break; + } + for ( i = 0; i <= 0x1FFFF; i += g_device_info->m_page_size_noecc ) + { + s147nand_8_multi_write_dma(((char *)g_nand_partbuf.m_buf) + i, pageoffs, 1); + s147nand_7_multi_read_dma(g_page_buf, pageoffs, 1); + if ( do_verify(((char *)g_nand_partbuf.m_buf) + i, g_page_buf, g_device_info->m_page_size_noecc) ) + { + STATUS_PRINTF( + "romwrite: Verify error - LogBlock=%d LogPage=%d\n", s147nand_28_pages2blocks(pageoffs), pageoffs); + err = 1; + finished = 1; + break; + } + pageoffs += 1; + xind2 += 1; + xind3 += 1; + if ( xind2 >= pages ) + { + finished = 1; + break; + } + } + if ( finished ) + break; + } + if ( finished ) + break; + } + } + if ( actual_readres < expected_readres ) + STATUS_PRINTF(" Error: File-I/O fault (%d)\n", actual_readres); + if ( fd >= 0 ) + close(fd); + if ( err ) + { + CpuSuspendIntr(&state); + // Unofficial: don't free partition buffer + if ( g_page_buf ) + FreeSysMemory(g_page_buf); + CpuResumeIntr(state); + } + return err ? -1 : 0; +} + +static int check_badblock_count(void) +{ + int retval; + + retval = -1; + for ( ; g_badblock_count < get_nand_partition_offset(8, 8) - 1; g_badblock_count += 1 ) + { + if ( g_blockinfo_str_buf[g_badblock_count] == 'R' ) + { + retval = g_badblock_count; + g_badblock_count += 1; + break; + } + } + return retval; +} + +static int get_nand_partition_offset(int part, int abspart) +{ + if ( part == 8 ) + return get_nand_block_size_div_32(); + if ( abspart ) + { + if ( part < 0 || part >= abspart ) + return -1; + if ( abspart == -1 && g_device_info->m_block_size == (int)0x80000000 ) + __builtin_trap(); + } + if ( !part ) + return get_nand_block_size_div_32_div_64(); + if ( abspart ) + return g_device_info->m_block_size / abspart * part; + if ( part != 1 ) + return -1; + return g_device_info->m_block_size / 4; +} + +static int get_nand_partition_size(int part, int abspart) +{ + if ( part == 8 ) + return get_nand_block_size_div_32_div_64() - get_nand_block_size_div_32(); + if ( abspart ) + { + if ( part < 0 || part >= abspart ) + return 0; + if ( abspart == -1 && g_device_info->m_block_size == (int)0x80000000 ) + __builtin_trap(); + return g_device_info->m_block_size / abspart - (part ? 0 : get_nand_block_size_div_32_div_64()); + } + if ( part ) + return (part == 1) ? (3 * (g_device_info->m_block_size / 4)) : 0; + return g_device_info->m_block_size / 4 - get_nand_block_size_div_32_div_64(); +} + +static int get_nand_block_size_div_32_div_64(void) +{ + return get_nand_block_size_div_32() + g_device_info->m_block_size / 64; +} + +static int get_nand_block_size_div_32(void) +{ + return g_device_info->m_block_size / 32; +} + +static void do_dma_write_bytes_multi(void *ptr, int pageoffs, int pagecnt) +{ + int i; + int bytecnt; + + bytecnt = s147nand_30_bytes2pagesnoeccround(pagecnt); + for ( i = 0; i < bytecnt; i += 1 ) + s147nand_22_nand_write_dma( + (char *)ptr + ((g_device_info->m_page_size_noecc >> 2) << 2) * i, + pageoffs + i, + 0, + g_device_info->m_page_size_noecc); +} + +static int do_list_files(int part) +{ + int hdrret; + int pageoffs; + int xind1; + int i; + int dircnt; + int filcnt; + int finished; + char pathtmp[18]; + + hdrret = -1; + dircnt = 0; + filcnt = 0; + finished = 0; + pageoffs = s147nand_9_get_nand_partition(part) * g_device_info->m_pages_per_block; + if ( pageoffs < 0 ) + return -19; + for ( xind1 = 0; xind1 < 64; xind1 += 1 ) + { + s147nand_7_multi_read_dma(g_nand_partbuf.m_buf, pageoffs + xind1, 1); + for ( i = 0; i < 64; i += 1 ) + { + if ( (xind1 << 6) - 1 + i == -1 ) + { + if ( strncmp(g_nand_partbuf.m_dir.m_sig, "S147ROM", 8) ) + { + STATUS_PRINTF(" \"%s%d:\" ... No data\n", "atfile", part); + STATUS_PRINTF(" -----------------------------\n\n"); + return -19; + } + hdrret = g_nand_partbuf.m_dir.m_entrycnt; + STATUS_PRINTF(" \"%s%d:\"\n", "atfile", part); + STATUS_PRINTF(" -----------------------------\n"); + } + else + { + if ( (xind1 << 6) - 1 + i >= hdrret ) + { + finished = 1; + break; + } + strcpy(pathtmp, g_nand_partbuf.m_direntry[i].m_name); + if ( g_nand_partbuf.m_direntry[i].m_type == 'D' ) + { + strcat(pathtmp, "/"); + dircnt += 1; + } + else + { + filcnt += 1; + } + STATUS_PRINTF(" %9d %s\n", g_nand_partbuf.m_direntry[i].m_size, pathtmp); + DelayThread(20000); + } + } + if ( finished ) + break; + } + STATUS_PRINTF(" -----------------------------\n"); + STATUS_PRINTF(" %d directories, %d files\n", dircnt, filcnt); + STATUS_PRINTF("\n"); + return hdrret; +} + +static void do_output_bb_info(int blocksd, int abspart, int bboffs) +{ + (void)abspart; + if ( (blocksd & 0x3F) == 0 ) + STATUS_PRINTF(" %04X(%4d):", blocksd, blocksd); + STATUS_PRINTF("%c", (blocksd == bboffs) ? 'I' : g_blockinfo_str_buf[blocksd]); + if ( (blocksd & 0xF) == 15 ) + STATUS_PRINTF(" "); + if ( (blocksd & 0x3F) == '?' ) + STATUS_PRINTF("\n"); +} + +static int do_verify(void *buf1, void *buf2, int len) +{ + int i; + + for ( i = 0; i < len / 4; i += 1 ) + if ( ((u32 *)buf1)[i] != ((u32 *)buf2)[i] ) + return ((u32 *)buf1)[i] - ((u32 *)buf2)[i]; + return 0; +} + +static const nand_id_desc_info_t *do_parse_device_info(const char *nandid) +{ + int i; + int j; + + for ( i = 0; g_nand_type_info[i].m_nand_name; i += 1 ) + { + int cmpval; + + cmpval = 0; + for ( j = 0; j < 5; j += 1 ) + if ( ((int)g_nand_type_info[i].m_id[j] == -1) || ((u8)g_nand_type_info[i].m_id[j] == (u8)nandid[j]) ) + cmpval += 1; + if ( cmpval == 5 ) + return &g_nand_type_info[i]; + } + return 0; +} diff --git a/iop/arcade/s147ctrl/Makefile b/iop/arcade/s147ctrl/Makefile new file mode 100644 index 00000000000..08ec5aaa8c5 --- /dev/null +++ b/iop/arcade/s147ctrl/Makefile @@ -0,0 +1,28 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= s147ctrl.irx + +IOP_IMPORT_INCS += \ + arcade/acdev \ + system/intrman \ + system/ioman \ + system/sifcmd \ + system/sifman \ + system/sysclib \ + system/sysmem \ + system/threadman \ + system/timrman \ + system/loadcore + +IOP_OBJS = s147ctrl.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/s147ctrl/README.md b/iop/arcade/s147ctrl/README.md new file mode 100644 index 00000000000..ac69e19e7c9 --- /dev/null +++ b/iop/arcade/s147ctrl/README.md @@ -0,0 +1,16 @@ +# S147CTRL + +This module provides access to the LED, watchdog, SRAM, RTC, and security of +System 147. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `s147ctrl` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with no arguments. diff --git a/iop/arcade/s147ctrl/src/imports.lst b/iop/arcade/s147ctrl/src/imports.lst new file mode 100644 index 00000000000..f31336dc8bf --- /dev/null +++ b/iop/arcade/s147ctrl/src/imports.lst @@ -0,0 +1,61 @@ + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +I_Kprintf +sysmem_IMPORTS_end + +intrman_IMPORTS_start +I_CpuSuspendIntr +I_CpuResumeIntr +intrman_IMPORTS_end + +ioman_IMPORTS_start +I_AddDrv +I_DelDrv +ioman_IMPORTS_end + +sifcmd_IMPORTS_start +I_sceSifSendCmd +I_isceSifSendCmd +I_sceSifInitRpc +I_sceSifRegisterRpc +I_sceSifSetRpcQueue +I_sceSifRpcLoop +sifcmd_IMPORTS_end + +sifman_IMPORTS_start +I_sceSifDmaStat +sifman_IMPORTS_end + +sysclib_IMPORTS_start +I_memcpy +I_memset +I_strcmp +I_vsprintf +sysclib_IMPORTS_end + +thbase_IMPORTS_start +I_CreateThread +I_StartThread +I_GetThreadId +I_SetAlarm +I_USec2SysClock +thbase_IMPORTS_end + +thsemap_IMPORTS_start +I_CreateSema +I_SignalSema +I_WaitSema +thsemap_IMPORTS_end + +timrman_IMPORTS_start +I_AllocHardTimer +I_FreeHardTimer +I_GetTimerCounter +timrman_IMPORTS_end + +acdev_IMPORTS_start +I_SetAcMemDelayReg +I_SetAcIoDelayReg +acdev_IMPORTS_end diff --git a/iop/arcade/s147ctrl/src/irx_imports.h b/iop/arcade/s147ctrl/src/irx_imports.h new file mode 100644 index 00000000000..2d52053d33a --- /dev/null +++ b/iop/arcade/s147ctrl/src/irx_imports.h @@ -0,0 +1,30 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/s147ctrl/src/s147ctrl.c b/iop/arcade/s147ctrl/src/s147ctrl.c new file mode 100644 index 00000000000..359a6068701 --- /dev/null +++ b/iop/arcade/s147ctrl/src/s147ctrl.c @@ -0,0 +1,753 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include +#include +#include +#include + +IRX_ID("S147CTRL", 2, 8); +// Text section hash: +// 0cc30d14ced9b7ccec282df9d56d0bf4 + +typedef struct watchdog_info_ +{ + int g_watchdog_started; + iop_sys_clock_t g_watchdog_clock; +} watchdog_info_t; + +typedef struct sram_drv_privdata_ +{ + u32 m_curpos; + u32 m_maxpos; +} sram_drv_privdata_t; + +static void setup_ac_delay_regs(void); +static int setup_ctrl_ioman_drv(const char *devpfx, const char *devname); +static unsigned int watchdog_alarm_cb(void *userdata); +static int ctrl_drv_op_open(const iop_file_t *f, const char *name, int flags); +static int ctrl_drv_op_close(iop_file_t *f); +static int ctrl_drv_op_read(const iop_file_t *f, void *ptr, int size); +static int ctrl_drv_op_write(const iop_file_t *f, void *ptr, int size); +static int create_ctrl_sema(void); +static int ctrl_do_rtc_read(u32 *rtcbuf); +static int ctrl_do_rtc_read_inner(int flgcnt, int flgmsk); +static int ctrl_do_rtc_write(const u32 *rtcbuf); +static void ctrl_do_rtc_write_inner(int inflg, int flgcnt, int flgmsk); +static int setup_sram_ioman_drv(const char *devpfx, const char *devname); +static int sram_drv_op_open(iop_file_t *f, const char *name, int flags); +static int sram_drv_op_close(iop_file_t *f); +static int sram_drv_op_read(iop_file_t *f, void *ptr, int size); +static int sram_drv_op_write(iop_file_t *f, void *ptr, int size); +static int sram_drv_op_lseek(iop_file_t *f, int offset, int mode); +static int do_rpc_start1(void); +static void rpc_thread1(void *userdata); +static void *rpc_1470000_handler(int fno, void *buffer, int length); +static void *rpc_1470001_handler(int fno, void *buffer, int length); +static void *rpc_1470002_handler(int fno, void *buffer, int length); +static void *rpc_1470003_handler(int fno, void *buffer, int length); +static int do_rpc_start2(void); +static void rpc_thread2(void *userdata); +static void *rpc_1470200_handler(int fno, void *buffer, int length); +static void *rpc_1470201_handler(int fno, void *buffer, int length); + +// Unofficial: merge callbacks that use the same return value +IOMAN_RETURN_VALUE_IMPL(0); + +static iop_device_ops_t g_ops_ctrl_ioman = { + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + (void *)&ctrl_drv_op_open, + (void *)&ctrl_drv_op_close, + (void *)&ctrl_drv_op_read, + (void *)&ctrl_drv_op_write, + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), +}; +// Unofficial: move to bss +static int g_rpc_started; +// Unofficial: move to bss +static int g_watchdog_count_1; +// Unofficial: move to bss +static char g_watchdog_flag_1; +// Unofficial: move to bss +static u32 g_max_timer_counter; +static iop_device_ops_t g_ops_sram_ioman = { + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + (void *)&sram_drv_op_open, + (void *)&sram_drv_op_close, + (void *)&sram_drv_op_read, + (void *)&sram_drv_op_write, + (void *)&sram_drv_op_lseek, + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), +}; +static iop_device_t g_drv_ctrl_ioman; +static int g_rtc_flag; +static int g_timer_id; +static iop_sema_t g_ctrl_sema_param; +static int g_ctrl_sema_id; +static iop_device_t g_drv_sram_ioman; +static int g_rpc1_buf[8]; +static int g_rpc2_buf[260]; +static watchdog_info_t g_watchdog_info; + +int _start(int ac, char **av) +{ + (void)ac; + (void)av; + Kprintf("\n"); + Kprintf("s147ctrl.irx: System147 Control/SRAM Driver v%d.%d\n", 2, 8); + setup_ac_delay_regs(); + if ( setup_ctrl_ioman_drv("ctrl", "Ctrl") < 0 ) + { + Kprintf("s147ctrl.irx: Ctrl initialize failed\n"); + return MODULE_NO_RESIDENT_END; + } + // cppcheck-suppress knownConditionTrueFalse + if ( setup_sram_ioman_drv("sram", "SRAM") < 0 ) + { + Kprintf("s147ctrl.irx: Sram initialize failed\n"); + return MODULE_NO_RESIDENT_END; + } + return MODULE_RESIDENT_END; +} + +static void setup_ac_delay_regs(void) +{ + SetAcMemDelayReg(0x261A2122); + SetAcIoDelayReg(0xA61A0166); +} + +static int setup_ctrl_ioman_drv(const char *devpfx, const char *devname) +{ + g_watchdog_info.g_watchdog_started = 1; + USec2SysClock(0x4E20, &g_watchdog_info.g_watchdog_clock); + SetAlarm(&g_watchdog_info.g_watchdog_clock, watchdog_alarm_cb, &g_watchdog_info); + if ( create_ctrl_sema() < 0 ) + return -1; + g_drv_ctrl_ioman.name = devpfx; + g_drv_ctrl_ioman.type = IOP_DT_FS; + g_drv_ctrl_ioman.version = 0; + g_drv_ctrl_ioman.desc = devname; + g_drv_ctrl_ioman.ops = &g_ops_ctrl_ioman; + DelDrv(devpfx); + AddDrv(&g_drv_ctrl_ioman); + return 0; +} + +static unsigned int watchdog_alarm_cb(void *userdata) +{ + int state; + u8 unk34_tmp; + watchdog_info_t *wdi; + USE_S147_DEV9_MEM_MMIO(); + USE_S147LINK_DEV9_MEM_MMIO(); + + wdi = (watchdog_info_t *)userdata; + if ( wdi->g_watchdog_started != 1 ) + { + s147_dev9_mem_mmio->m_led = 3; + return 0; + } + CpuSuspendIntr(&state); + s147link_dev9_mem_mmio->m_watchdog_flag_unk34 = 0; + unk34_tmp = s147link_dev9_mem_mmio->m_watchdog_flag_unk34; + CpuResumeIntr(state); + if ( unk34_tmp == 0x3E ) + { + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + // Unofficial: add 1 here + s147_dev9_mem_mmio->m_led = g_watchdog_flag_1 + 1; + g_watchdog_flag_1 = ((((unsigned int)g_watchdog_count_1 >> 3) & 1) != 0) ? 1 : 0; + g_watchdog_count_1 += 1; + } + return wdi->g_watchdog_clock.lo; +} + +static int ctrl_drv_op_open(const iop_file_t *f, const char *name, int flags) +{ + int state; + + (void)flags; + if ( f->unit != 99 ) + return 0; + if ( !strcmp(name, "watchdog-start") ) + { + Kprintf("s147ctrl.irx: wdt-start\n"); + CpuSuspendIntr(&state); + g_watchdog_info.g_watchdog_started = 1; + CpuResumeIntr(state); + } + else if ( !strcmp(name, "watchdog-stop") ) + { + Kprintf("s147ctrl.irx: wdt-stop\n"); + CpuSuspendIntr(&state); + g_watchdog_info.g_watchdog_started = 0; + CpuResumeIntr(state); + } + else if ( !strcmp(name, "rpcserv-start") ) + { + Kprintf("s147ctrl.irx: rpcserv-start\n"); + if ( !g_rpc_started ) + { + do_rpc_start1(); + do_rpc_start2(); + CpuSuspendIntr(&state); + g_rpc_started = 1; + CpuResumeIntr(state); + } + } + return 0; +} + +static int ctrl_drv_op_close(iop_file_t *f) +{ + (void)f; + return 0; +} + +static int ctrl_drv_op_read(const iop_file_t *f, void *ptr, int size) +{ + int unit; + int retres; + USE_S147_DEV9_MEM_MMIO(); + + unit = f->unit; + switch ( unit ) + { + case 4: + if ( size != 0x1C ) + return -EINVAL; + retres = ctrl_do_rtc_read(ptr); + if ( retres < 0 ) + Kprintf("s147ctrl.irx: RTC Read failed (%d)\n", retres); + return retres; + case 12: + if ( size != 2 ) + return -EINVAL; + *(u8 *)ptr = s147_dev9_mem_mmio->m_security_unlock_set1; + *((u8 *)ptr + 1) = s147_dev9_mem_mmio->m_security_unlock_set2; + return 2; + default: + if ( size != 1 ) + return -EINVAL; + *(u8 *)ptr = *(u8 *)(unit + 0xB0000000); + return 1; + } +} + +static int ctrl_drv_op_write(const iop_file_t *f, void *ptr, int size) +{ + int unit; + int retres; + USE_S147_DEV9_MEM_MMIO(); + + unit = f->unit; + switch ( unit ) + { + case 4: + if ( size != 0x1C ) + return -EINVAL; + retres = ctrl_do_rtc_write(ptr); + if ( retres < 0 ) + Kprintf("s147ctrl.irx: RTC Write failed (%d)\n", retres); + return retres; + case 12: + if ( size != 2 ) + return -EINVAL; + s147_dev9_mem_mmio->m_security_unlock_set1 = *(u8 *)ptr; + s147_dev9_mem_mmio->m_security_unlock_set2 = *((u8 *)ptr + 1); + return 2; + default: + if ( size != 1 ) + return -EINVAL; + *(u8 *)(unit + 0xB0000000) = *(u8 *)ptr; + return 1; + } +} + +static int create_ctrl_sema(void) +{ + g_ctrl_sema_param.initial = 1; + g_ctrl_sema_param.max = 1; + g_ctrl_sema_param.attr = SA_THPRI; + g_ctrl_sema_id = CreateSema(&g_ctrl_sema_param); + if ( g_ctrl_sema_id < 0 ) + { + Kprintf("s147ctrl.irx: CreateSema error (%d)\n", g_ctrl_sema_id); + return -1; + } + return 0; +} + +static int ctrl_do_rtc_read(u32 *rtcbuf) +{ + USE_S147_DEV9_MEM_MMIO(); + + WaitSema(g_ctrl_sema_id); + g_timer_id = AllocHardTimer(1, 0x20, 1); + if ( g_timer_id < 0 ) + return g_timer_id; + // Unofficial: omit SetupHardTimer/StartHardTimer + g_max_timer_counter = 0x40; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 1; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 9; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + rtcbuf[6] = ctrl_do_rtc_read_inner(8, 0x7F); + rtcbuf[5] = ctrl_do_rtc_read_inner(8, 0x7F); + rtcbuf[4] = ctrl_do_rtc_read_inner(8, 0x3F); + rtcbuf[3] = ctrl_do_rtc_read_inner(4, 7); + rtcbuf[2] = ctrl_do_rtc_read_inner(8, 0x3F); + rtcbuf[1] = ctrl_do_rtc_read_inner(8, 0x1F); + *rtcbuf = ctrl_do_rtc_read_inner(8, 0xFF); + s147_dev9_mem_mmio->m_rtc_flag = 1; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 1; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + // Unofficial: omit StopHardTimer + FreeHardTimer(g_timer_id); + g_max_timer_counter = 0; + SignalSema(g_ctrl_sema_id); + return 0x1C; +} + +static int ctrl_do_rtc_read_inner(int flgcnt, int flgmsk) +{ + int i; + USE_S147_DEV9_MEM_MMIO(); + + g_rtc_flag = 0; + for ( i = 0; i < flgcnt; i += 1 ) + { + s147_dev9_mem_mmio->m_rtc_flag = 0xB; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + g_rtc_flag |= (s147_dev9_mem_mmio->m_rtc_flag & 1) << i; + s147_dev9_mem_mmio->m_rtc_flag = 9; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + } + return g_rtc_flag & flgmsk; +} + +static int ctrl_do_rtc_write(const u32 *rtcbuf) +{ + USE_S147_DEV9_MEM_MMIO(); + + WaitSema(g_ctrl_sema_id); + g_timer_id = AllocHardTimer(1, 0x20, 1); + if ( g_timer_id < 0 ) + return g_timer_id; + // Unofficial: omit SetupHardTimer/StartHardTimer + g_max_timer_counter = 0x40; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 5; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 0xD; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + ctrl_do_rtc_write_inner(rtcbuf[6], 8, 0x7F); + ctrl_do_rtc_write_inner(rtcbuf[5], 8, 0x7F); + ctrl_do_rtc_write_inner(rtcbuf[4], 8, 0x3F); + ctrl_do_rtc_write_inner(rtcbuf[3], 4, 7); + ctrl_do_rtc_write_inner(rtcbuf[2], 8, 0x3F); + ctrl_do_rtc_write_inner(rtcbuf[1], 8, 0x1F); + ctrl_do_rtc_write_inner(*rtcbuf, 8, 0xFF); + s147_dev9_mem_mmio->m_rtc_flag = 5; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = 1; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + // Unofficial: omit StopHardTimer + FreeHardTimer(g_timer_id); + g_max_timer_counter = 0; + SignalSema(g_ctrl_sema_id); + return 0x1C; +} + +static void ctrl_do_rtc_write_inner(int inflg, int flgcnt, int flgmsk) +{ + int i; + unsigned int xval; + USE_S147_DEV9_MEM_MMIO(); + + xval = inflg & flgmsk; + for ( i = 0; i < flgcnt; i += 1 ) + { + s147_dev9_mem_mmio->m_rtc_flag = (xval & 1) | 0xC; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + s147_dev9_mem_mmio->m_rtc_flag = (xval & 1) | 0xE; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; + xval >>= 1; + } + s147_dev9_mem_mmio->m_rtc_flag = (xval & 1) | 0xC; + while ( GetTimerCounter(g_timer_id) < g_max_timer_counter ) + ; + g_max_timer_counter += 0x40; +} + +static int setup_sram_ioman_drv(const char *devpfx, const char *devname) +{ + g_drv_sram_ioman.name = devpfx; + g_drv_sram_ioman.type = IOP_DT_FS; + g_drv_sram_ioman.version = 0; + g_drv_sram_ioman.desc = devname; + g_drv_sram_ioman.ops = &g_ops_sram_ioman; + DelDrv(devpfx); + AddDrv(&g_drv_sram_ioman); + return 0; +} + +static int sram_drv_op_open(iop_file_t *f, const char *name, int flags) +{ + sram_drv_privdata_t *privdata; + int state; + + (void)name; + (void)flags; + CpuSuspendIntr(&state); + f->privdata = AllocSysMemory(ALLOC_FIRST, sizeof(sram_drv_privdata_t), 0); + CpuResumeIntr(state); + privdata = (sram_drv_privdata_t *)f->privdata; + privdata->m_curpos = 0; + privdata->m_maxpos = 0x8000; + return 0; +} + +static int sram_drv_op_close(iop_file_t *f) +{ + int state; + + if ( !f->privdata ) + return 0; + CpuSuspendIntr(&state); + FreeSysMemory(f->privdata); + CpuResumeIntr(state); + f->privdata = 0; + return 0; +} + +static int sram_drv_op_read(iop_file_t *f, void *ptr, int size) +{ + int sizeb; + sram_drv_privdata_t *privdata; + + privdata = (sram_drv_privdata_t *)f->privdata; + if ( (s32)privdata->m_curpos >= (s32)privdata->m_maxpos ) + return 0; + sizeb = ((s32)privdata->m_maxpos < (s32)(privdata->m_curpos + size)) ? (privdata->m_maxpos - privdata->m_curpos) : + (u32)size; + memcpy(ptr, (const void *)(privdata->m_curpos + 0xB0C00000), sizeb); + privdata->m_curpos += sizeb; + return sizeb; +} + +static int sram_drv_op_write(iop_file_t *f, void *ptr, int size) +{ + int sizeb; + sram_drv_privdata_t *privdata; + USE_S147_DEV9_MEM_MMIO(); + + privdata = (sram_drv_privdata_t *)f->privdata; + if ( (s32)privdata->m_curpos >= (s32)privdata->m_maxpos ) + return 0; + sizeb = ((s32)privdata->m_maxpos < (s32)(privdata->m_curpos + size)) ? (privdata->m_maxpos - privdata->m_curpos) : + (u32)size; + s147_dev9_mem_mmio->m_sram_write_flag = 1; + memcpy((void *)(privdata->m_curpos + 0xB0C00000), ptr, sizeb); + s147_dev9_mem_mmio->m_sram_write_flag = 0; + privdata->m_curpos += sizeb; + return sizeb; +} + +static int sram_drv_op_lseek(iop_file_t *f, int offset, int mode) +{ + sram_drv_privdata_t *privdata; + + privdata = (sram_drv_privdata_t *)f->privdata; + switch ( mode ) + { + case SEEK_SET: + privdata->m_curpos = offset; + break; + case SEEK_CUR: + privdata->m_curpos += offset; + break; + case SEEK_END: + privdata->m_curpos = privdata->m_maxpos + offset; + break; + default: + return -EINVAL; + } + if ( (s32)privdata->m_maxpos < (s32)privdata->m_curpos ) + { + privdata->m_curpos = privdata->m_maxpos; + return -EINVAL; + } + return privdata->m_curpos; +} + +static int do_rpc_start1(void) +{ + iop_thread_t thparam; + int thid; + + thparam.attr = TH_C; + thparam.thread = rpc_thread1; + thparam.priority = 10; + thparam.stacksize = 0x800; + thparam.option = 0; + thid = CreateThread(&thparam); + if ( thid <= 0 ) + return 1; + StartThread(thid, 0); + return 0; +} + +static void rpc_thread1(void *userdata) +{ + SifRpcDataQueue_t qd; + SifRpcServerData_t sd[4]; + + (void)userdata; + sceSifInitRpc(0); + sceSifSetRpcQueue(&qd, GetThreadId()); + sceSifRegisterRpc(&sd[0], 0x1470000, rpc_1470000_handler, g_rpc1_buf, 0, 0, &qd); + sceSifRegisterRpc(&sd[1], 0x1470001, rpc_1470001_handler, g_rpc1_buf, 0, 0, &qd); + sceSifRegisterRpc(&sd[2], 0x1470002, rpc_1470002_handler, g_rpc1_buf, 0, 0, &qd); + sceSifRegisterRpc(&sd[3], 0x1470003, rpc_1470003_handler, g_rpc1_buf, 0, 0, &qd); + sceSifRpcLoop(&qd); +} + +static void *rpc_1470000_handler(int fno, void *buffer, int length) +{ + USE_S147_DEV9_MEM_MMIO(); + + (void)length; + switch ( fno ) + { + case 1: + s147_dev9_mem_mmio->m_led = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 2: + s147_dev9_mem_mmio->m_security_unlock_unlock = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 3: + s147_dev9_mem_mmio->m_unk03 = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 4: + s147_dev9_mem_mmio->m_rtc_flag = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 5: + s147_dev9_mem_mmio->m_watchdog_flag2 = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 12: + s147_dev9_mem_mmio->m_security_unlock_set1 = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + case 13: + s147_dev9_mem_mmio->m_security_unlock_set2 = *(u8 *)buffer; + *(u32 *)buffer = 0; + break; + default: + *(u32 *)buffer = -22; + break; + } + return buffer; +} + +static void *rpc_1470001_handler(int fno, void *buffer, int length) +{ + USE_S147_DEV9_MEM_MMIO(); + + (void)length; + switch ( fno ) + { + case 0: + *(u8 *)buffer = s147_dev9_mem_mmio->m_unk00; + *((u32 *)buffer + 1) = 0; + break; + case 1: + *(u8 *)buffer = s147_dev9_mem_mmio->m_led; + *((u32 *)buffer + 1) = 0; + break; + case 2: + *(u8 *)buffer = s147_dev9_mem_mmio->m_security_unlock_unlock; + *((u32 *)buffer + 1) = 0; + break; + case 3: + *(u8 *)buffer = s147_dev9_mem_mmio->m_unk03; + *((u32 *)buffer + 1) = 0; + break; + case 4: + *(u8 *)buffer = s147_dev9_mem_mmio->m_rtc_flag; + *((u32 *)buffer + 1) = 0; + break; + case 5: + *(u8 *)buffer = s147_dev9_mem_mmio->m_watchdog_flag2; + *((u32 *)buffer + 1) = 0; + break; + case 6: + *(u8 *)buffer = s147_dev9_mem_mmio->m_unk06; + *((u32 *)buffer + 1) = 0; + break; + case 12: + *(u8 *)buffer = s147_dev9_mem_mmio->m_security_unlock_set1; + *((u32 *)buffer + 1) = 0; + break; + case 13: + *(u8 *)buffer = s147_dev9_mem_mmio->m_security_unlock_set2; + *((u32 *)buffer + 1) = 0; + break; + default: + *(u8 *)buffer = 0; + *((u32 *)buffer + 1) = -22; + break; + } + return buffer; +} + +static void *rpc_1470002_handler(int fno, void *buffer, int length) +{ + (void)length; + *(u32 *)buffer = (fno == 4) ? ctrl_do_rtc_write(buffer) : -22; + return buffer; +} + +static void *rpc_1470003_handler(int fno, void *buffer, int length) +{ + (void)length; + if ( fno != 4 ) + { + *(u32 *)buffer = 0; + *((u32 *)buffer + 1) = 0; + *((u32 *)buffer + 2) = 0; + *((u32 *)buffer + 3) = 0; + *((u32 *)buffer + 4) = 0; + *((u32 *)buffer + 5) = 0; + *((u32 *)buffer + 6) = 0; + *((u32 *)buffer + 7) = -22; + return buffer; + } + *((u32 *)buffer + 7) = ctrl_do_rtc_read(buffer); + return buffer; +} + +static int do_rpc_start2(void) +{ + iop_thread_t thparam; + int thid; + + thparam.attr = TH_C; + thparam.thread = rpc_thread2; + thparam.priority = 10; + thparam.stacksize = 0x800; + thparam.option = 0; + thid = CreateThread(&thparam); + if ( thid <= 0 ) + return 1; + StartThread(thid, 0); + return 0; +} + +static void rpc_thread2(void *userdata) +{ + SifRpcDataQueue_t qd; + SifRpcServerData_t sd[2]; + + (void)userdata; + sceSifInitRpc(0); + sceSifSetRpcQueue(&qd, GetThreadId()); + sceSifRegisterRpc(&sd[0], 0x1470200, rpc_1470200_handler, g_rpc2_buf, 0, 0, &qd); + sceSifRegisterRpc(&sd[1], 0x1470201, rpc_1470201_handler, g_rpc2_buf, 0, 0, &qd); + sceSifRpcLoop(&qd); +} + +static void *rpc_1470200_handler(int fno, void *buffer, int length) +{ + USE_S147_DEV9_MEM_MMIO(); + + (void)length; + if ( (unsigned int)fno >= 3 ) + { + *(u32 *)buffer = -1; + return buffer; + } + s147_dev9_mem_mmio->m_sram_write_flag = 1; + memcpy((void *)(*((u32 *)buffer + 256) + 0xB0C00000), buffer, *((u32 *)buffer + 257)); + s147_dev9_mem_mmio->m_sram_write_flag = 0; + *(u32 *)buffer = 0; + return buffer; +} + +static void *rpc_1470201_handler(int fno, void *buffer, int length) +{ + (void)length; + if ( (unsigned int)fno >= 3 ) + { + memset(buffer, 0, *((u32 *)buffer + 1)); + *((u32 *)buffer + 256) = -1; + return buffer; + } + memcpy(buffer, (const void *)(*(u32 *)buffer + 0xB0C00000), *((u32 *)buffer + 1)); + *((u32 *)buffer + 256) = 0; + return buffer; +} diff --git a/iop/arcade/s147link/Makefile b/iop/arcade/s147link/Makefile new file mode 100644 index 00000000000..f4e983eccdf --- /dev/null +++ b/iop/arcade/s147link/Makefile @@ -0,0 +1,24 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= s147link.irx + +IOP_IMPORT_INCS += \ + system/intrman \ + system/loadcore \ + system/sifcmd \ + system/stdio \ + system/sysclib \ + system/threadman + +IOP_OBJS = s147link.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/s147link/README.md b/iop/arcade/s147link/README.md new file mode 100644 index 00000000000..019cc6ac789 --- /dev/null +++ b/iop/arcade/s147link/README.md @@ -0,0 +1,16 @@ +# S147LINK + +This module provides functions to access the CircLink of System 147 provided +by the SMSC TMC2074 controller over RS485 medium. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `s147link` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with no arguments. diff --git a/iop/arcade/s147link/src/imports.lst b/iop/arcade/s147link/src/imports.lst new file mode 100644 index 00000000000..282c6ddc022 --- /dev/null +++ b/iop/arcade/s147link/src/imports.lst @@ -0,0 +1,38 @@ + +intrman_IMPORTS_start +I_RegisterIntrHandler +I_ReleaseIntrHandler +I_EnableIntr +I_CpuSuspendIntr +I_CpuResumeIntr +intrman_IMPORTS_end + +loadcore_IMPORTS_start +I_FlushDcache +loadcore_IMPORTS_end + +sifcmd_IMPORTS_start +I_sceSifInitRpc +I_sceSifRegisterRpc +I_sceSifSetRpcQueue +I_sceSifRpcLoop +sifcmd_IMPORTS_end + +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +sysclib_IMPORTS_start +I_toupper +I_memcpy +I_strtol +sysclib_IMPORTS_end + +thbase_IMPORTS_start +I_CreateThread +I_DeleteThread +I_StartThread +I_GetThreadId +I_SetAlarm +I_USec2SysClock +thbase_IMPORTS_end diff --git a/iop/arcade/s147link/src/irx_imports.h b/iop/arcade/s147link/src/irx_imports.h new file mode 100644 index 00000000000..c8031f25280 --- /dev/null +++ b/iop/arcade/s147link/src/irx_imports.h @@ -0,0 +1,26 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/s147link/src/s147link.c b/iop/arcade/s147link/src/s147link.c new file mode 100644 index 00000000000..29bc2ff78ba --- /dev/null +++ b/iop/arcade/s147link/src/s147link.c @@ -0,0 +1,792 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include + +IRX_ID("S147LINK", 2, 7); +// Text section hash: +// f409cc0329bb98d776c9aacef6573aa9 + +typedef struct CL_COM_ +{ + unsigned int mynode; + unsigned int maxnode; + unsigned int nodemask; + u8 *R_top; + unsigned int R_in; + unsigned int R_out; + unsigned int R_remain; + u8 R_number[16]; + unsigned int R_lost[16]; + unsigned int R_pd[16]; + unsigned int R_count; + u8 *T_top; + unsigned int T_in; + unsigned int T_out; + unsigned int T_remain; + unsigned int T_node; + int T_error[16]; + unsigned int T_pd[16]; + unsigned int T_time[16]; + u8 T_number; + unsigned int timeout; + unsigned int online; + unsigned int ontimer; + unsigned int offtimer; + unsigned int rbfix; + iop_sys_clock_t sys_clock; +} CL_COM; + +static int InitS147link(int maxnode, int mynode, int priority); +static unsigned int alarm_handler(void *userdata); +static void s147link_loop(void *userdata); +static void *dispatch(int fno, void *buf, int size); + +static int gbBRE; +static u8 rpc_buf[32784]; +static u8 rx_buff[512][64]; +static u8 tx_buff[256][64]; +static CL_COM cl_info; + +int _start(int argc, char **argv) +{ + int maxnode; + int mynode; + int priority; + + maxnode = (argc >= 2) ? strtol(argv[1], 0, 10) : 0; + if ( maxnode < 2 || maxnode >= 16 ) + maxnode = 2; + mynode = (argc >= 3) ? strtol(argv[2], 0, 10) : 0; + if ( mynode <= 0 || maxnode < mynode ) + mynode = 1; + priority = (argc >= 4) ? strtol(argv[3], 0, 10) : 0; + if ( priority < 9 || priority >= 124 ) + priority = 28; + gbBRE = (argc >= 5 && toupper(*argv[4]) == 'N' && toupper(argv[4][1]) == 'B' && toupper(argv[4][2]) == 'R') ? 0 : 1; + printf("== S147LINK (%d/%d)@%d ", mynode, maxnode, priority); + if ( !gbBRE ) + printf("NBR "); + printf("v2.07 ==\n"); + if ( InitS147link(maxnode, mynode, priority) ) + { + printf("S147LINK: Can't Initialize driver thread.\n"); + return MODULE_NO_RESIDENT_END; + } + return MODULE_RESIDENT_END; +} + +static void T_fix(CL_COM *io_pCommon) +{ + if ( io_pCommon->T_remain >= 0x101 ) + { + io_pCommon->T_remain = 0x100; + io_pCommon->T_out = 0; + io_pCommon->T_in = io_pCommon->T_out; + io_pCommon->rbfix += 1; + if ( !io_pCommon->rbfix ) + io_pCommon->rbfix -= 1; + } + if ( io_pCommon->T_remain == 0x100 && io_pCommon->T_in != io_pCommon->T_out ) + { + io_pCommon->T_out = 0; + io_pCommon->T_in = io_pCommon->T_out; + io_pCommon->rbfix += 1; + if ( !io_pCommon->rbfix ) + io_pCommon->rbfix -= 1; + } +} + +static int clink_InterruptHandler(void *userdata) +{ + u8 *bufptr; + unsigned int i; + u8 stsH; + u8 stsL; + unsigned int rxfs; + unsigned int rxfc; + unsigned int tflag; + int state; + CL_COM *io_pCommon; + USE_S147LINK_DEV9_MEM_MMIO(); + + io_pCommon = (CL_COM *)userdata; + stsH = s147link_dev9_mem_mmio->m_stsH_unk12; + stsL = s147link_dev9_mem_mmio->m_stsL_unk13; + if ( (stsL & 8) != 0 ) + { + if ( (s147link_dev9_mem_mmio->m_unk03 & 8) != 0 ) + { + s147link_dev9_mem_mmio->m_unk17 = 1; + s147link_dev9_mem_mmio->m_unk17 = 0xE; + } + if ( (s147link_dev9_mem_mmio->m_unk01 & 4) != 0 ) + { + s147link_dev9_mem_mmio->m_unk17 = 0x16; + if ( !io_pCommon->ontimer ) + io_pCommon->offtimer = 1; + io_pCommon->ontimer = 1; + } + } + rxfc = 0; + rxfs = + ((s147link_dev9_mem_mmio->m_rxfc_hi_unk1E << 8) | s147link_dev9_mem_mmio->m_rxfc_lo_unk1F) & io_pCommon->nodemask; + if ( rxfs ) + { + for ( i = 1; io_pCommon->maxnode >= i; i += 1 ) + { + if ( i != io_pCommon->mynode ) + { + u8 unk09_tmp; + + if ( (rxfs & (1 << i)) == 0 ) + { + continue; + } + s147link_dev9_mem_mmio->m_node_unk05 = i | 0xC0; + s147link_dev9_mem_mmio->m_unk07 = 0; + unk09_tmp = s147link_dev9_mem_mmio->m_unk09; + if ( unk09_tmp == io_pCommon->mynode ) + { + // cppcheck-suppress incorrectLogicOperator + if ( s147link_dev9_mem_mmio->m_unk09 == 4 && !s147link_dev9_mem_mmio->m_unk09 ) + { + u8 rnum; + + rnum = s147link_dev9_mem_mmio->m_unk09; + if ( io_pCommon->R_number[i] != rnum ) + { + unk09_tmp = s147link_dev9_mem_mmio->m_unk09; + if ( io_pCommon->R_remain ) + { + unsigned int j; + + bufptr = &io_pCommon->R_top[0x40 * io_pCommon->R_in]; + bufptr[0] = i; + bufptr[1] = io_pCommon->mynode; + bufptr[2] = 4; + bufptr[3] = 0; + bufptr[4] = rnum; + bufptr[5] = unk09_tmp; + for ( j = 0; j < 0x3A; j += 1 ) + bufptr[j + 6] = s147link_dev9_mem_mmio->m_unk09; + io_pCommon->R_remain -= 1; + io_pCommon->R_in += 1; + io_pCommon->R_in &= 0x1FF; + io_pCommon->R_number[i] = rnum; + } + else if ( io_pCommon->R_pd[i] ) + { + io_pCommon->R_lost[i] += 1; + if ( !io_pCommon->R_lost[i] ) + io_pCommon->R_lost[i] += 1; + } + else + { + continue; + } + } + } + } + else if ( !unk09_tmp ) + { + if ( s147link_dev9_mem_mmio->m_unk09 == 0x38 ) + { + s147link_dev9_mem_mmio->m_node_unk05 = i | 0xC0; + s147link_dev9_mem_mmio->m_unk07 = 0x38; + unk09_tmp = s147link_dev9_mem_mmio->m_unk09; + if ( (unk09_tmp & 0xE0) == 0x20 || (unk09_tmp & 0xE0) == 0x60 ) + { + if ( io_pCommon->R_remain ) + { + bufptr = &io_pCommon->R_top[0x40 * io_pCommon->R_in]; + bufptr[0] = i; + bufptr[1] = 0; + bufptr[2] = 56; + bufptr[56] = unk09_tmp; + bufptr[57] = s147link_dev9_mem_mmio->m_unk09; + bufptr[58] = s147link_dev9_mem_mmio->m_unk09; + bufptr[59] = s147link_dev9_mem_mmio->m_unk09; + bufptr[60] = s147link_dev9_mem_mmio->m_unk09; + bufptr[61] = s147link_dev9_mem_mmio->m_unk09; + bufptr[62] = s147link_dev9_mem_mmio->m_unk09; + bufptr[63] = s147link_dev9_mem_mmio->m_unk09; + io_pCommon->R_remain -= 1; + io_pCommon->R_in += 1; + io_pCommon->R_in &= 0x1FF; + } + else if ( io_pCommon->R_pd[i] ) + { + io_pCommon->R_lost[i] += 1; + if ( !io_pCommon->R_lost[i] ) + io_pCommon->R_lost[i] += 1; + } + else + { + continue; + } + } + } + } + } + rxfc |= 1 << i; + } + } + tflag = 0; + if ( (stsL & 0x10) != 0 ) + { + s147link_dev9_mem_mmio->m_unk17 = 1; + s147link_dev9_mem_mmio->m_unk17 = 0xE; + } + if ( (stsL & 2) != 0 && (stsL & 4) == 0 && io_pCommon->timeout ) + { + tflag = 1; + } + else if ( (stsL & 1) != 0 ) + { + io_pCommon->timeout = 0; + while ( 1 ) + { + if ( io_pCommon->T_remain == 0x100 ) + { + s147link_dev9_mem_mmio->m_unk15 = 0x1A; + break; + } + bufptr = &io_pCommon->T_top[0x40 * io_pCommon->T_out]; + if ( *bufptr == io_pCommon->mynode ) + { + io_pCommon->T_node = bufptr[1]; + if ( !io_pCommon->T_error[io_pCommon->T_node] || !io_pCommon->T_pd[io_pCommon->T_node] ) + { + s147link_dev9_mem_mmio->m_node_unk05 = (io_pCommon->mynode & 0xFF) | 0x40; + s147link_dev9_mem_mmio->m_unk07 = 0; + for ( i = 0; i < 0x40; i += 1 ) + s147link_dev9_mem_mmio->m_unk09 = bufptr[i]; + io_pCommon->T_remain += 1; + io_pCommon->T_out += 1; + io_pCommon->T_out &= 0xFF; + T_fix(io_pCommon); + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + tflag = 1; + io_pCommon->timeout = 1; + break; + } + } + io_pCommon->T_remain += 1; + io_pCommon->T_out += 1; + io_pCommon->T_out &= 0xFF; + T_fix(io_pCommon); + } + } + CpuSuspendIntr(&state); + if ( tflag ) + s147link_dev9_mem_mmio->m_unk17 = 3; + if ( rxfc ) + { + s147link_dev9_mem_mmio->m_rxfc_hi_unk1E = (rxfc >> 8) & 0xFF; + s147link_dev9_mem_mmio->m_rxfc_lo_unk1F = rxfc; + } + s147link_dev9_mem_mmio->m_stsH_unk12 = stsH; + s147link_dev9_mem_mmio->m_stsL_unk13 = stsL; + CpuResumeIntr(state); + return 1; +} + +static int cl_mread(void *dstptr, int count) +{ + int state; + int size; + int packs; + + CpuSuspendIntr(&state); + size = 0x200 - cl_info.R_remain; + if ( cl_info.R_remain == 0x200 ) + { + CpuResumeIntr(state); + return 0; + } + if ( count >= size ) + count = size; + else + size = count; + packs = cl_info.R_out + size - 0x200; + if ( packs > 0 ) + { + size -= packs; + size <<= 6; + memcpy(dstptr, rx_buff[cl_info.R_out], size); + memcpy((char *)dstptr + size, rx_buff, packs << 6); + } + else + { + memcpy(dstptr, rx_buff[cl_info.R_out], size << 6); + } + cl_info.R_remain += count; + cl_info.R_out += count; + cl_info.R_out &= 0x1FF; + if ( cl_info.R_remain >= 0x201 ) + { + cl_info.R_remain = 0x200; + cl_info.R_out = 0; + cl_info.R_in = 0; + cl_info.rbfix += 1; + if ( !cl_info.rbfix ) + cl_info.rbfix -= 1; + count = 0; + } + if ( cl_info.R_remain == 512 && cl_info.R_in != cl_info.R_out ) + { + cl_info.R_out = 0; + cl_info.R_in = 0; + cl_info.rbfix += 1; + if ( !cl_info.rbfix ) + cl_info.rbfix -= 1; + count = 0; + } + CpuResumeIntr(state); + return count; +} + +static int cl_write(int node, u8 *srcptr, int size) +{ + int state; + USE_S147LINK_DEV9_MEM_MMIO(); + + CpuSuspendIntr(&state); + if ( !cl_info.T_remain || size >= 0x41 ) + { + CpuResumeIntr(state); + return 0; + } + memcpy(tx_buff[cl_info.T_in], srcptr, size); + tx_buff[cl_info.T_in][0] = cl_info.mynode; + tx_buff[cl_info.T_in][1] = node & 0xFF; + tx_buff[cl_info.T_in][2] = 4; + tx_buff[cl_info.T_in][3] = 0; + cl_info.T_number += 1; + tx_buff[cl_info.T_in][4] = cl_info.T_number; + cl_info.T_remain -= 1; + cl_info.T_in += 1; + cl_info.T_in &= 0xFF; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + return size; +} + +static int cl_write_custom(int node, u8 *srcptr, int cpVal) +{ + int state; + USE_S147LINK_DEV9_MEM_MMIO(); + + CpuSuspendIntr(&state); + if ( !cl_info.T_remain ) + { + CpuResumeIntr(state); + return 0; + } + memcpy(tx_buff[cl_info.T_in], srcptr, sizeof(u8[64])); + tx_buff[cl_info.T_in][0] = cl_info.mynode; + tx_buff[cl_info.T_in][1] = node & 0xFF; + tx_buff[cl_info.T_in][2] = cpVal & 0xFF; + cl_info.T_remain -= 1; + cl_info.T_in += 1; + cl_info.T_in &= 0xFF; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + return 64; +} + +static int cl_mwrite(u8 *srcptr, int count) +{ + int state; + int i; + int packs; + USE_S147LINK_DEV9_MEM_MMIO(); + + if ( cl_info.T_remain < (unsigned int)count ) + return 0; + if ( count >= 0x101 ) + return 0; + for ( i = 0; i < count; i += 1 ) + { + srcptr[(i * 0x40)] = cl_info.mynode; + srcptr[(i * 0x40) + 2] = 4; + srcptr[(i * 0x40) + 3] = 0; + srcptr[(i * 0x40) + 4] = cl_info.T_number + i + 1; + } + cl_info.T_number += i; + CpuSuspendIntr(&state); + if ( cl_info.T_remain < (unsigned int)count ) + { + CpuResumeIntr(state); + return 0; + } + packs = cl_info.T_in + count - 0x100; + if ( packs > 0 ) + { + memcpy(tx_buff[cl_info.T_in], srcptr, (count - packs) << 6); + memcpy(tx_buff, &srcptr[0x40 * (count - packs)], packs << 6); + } + else + { + memcpy(tx_buff[cl_info.T_in], srcptr, count << 6); + } + cl_info.T_remain -= count; + cl_info.T_in += count; + cl_info.T_in &= 0xFF; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + return count; +} + +static int InitS147link(int maxnode, int mynode, int priority) +{ + iop_thread_t param; + int thid; + int i; + int j; + int state; + u8 stsH; + u8 stsL; + USE_S147LINK_DEV9_MEM_MMIO(); + + s147link_dev9_mem_mmio->m_unk0D |= 0x80; + s147link_dev9_mem_mmio->m_unk22 = 2; + s147link_dev9_mem_mmio->m_unk23 = gbBRE ? 0x51 : 0x11; + s147link_dev9_mem_mmio->m_maxnode_unk2B = maxnode; + s147link_dev9_mem_mmio->m_mynode_unk2D = mynode; + s147link_dev9_mem_mmio->m_unk31 = 0; + s147link_dev9_mem_mmio->m_unk2F = 2; + for ( i = 0; i < 4; i += 1 ) + { + s147link_dev9_mem_mmio->m_node_unk05 = i | 0x40; + s147link_dev9_mem_mmio->m_unk07 = 0; + for ( j = 0; j < 256; j += 1 ) + s147link_dev9_mem_mmio->m_unk09 = 0; + } + s147link_dev9_mem_mmio->m_unk28 = 0; + s147link_dev9_mem_mmio->m_unk29 = 0; + s147link_dev9_mem_mmio->m_unk21 = 0; + s147link_dev9_mem_mmio->m_unk24 = 0; + s147link_dev9_mem_mmio->m_unk25 = 0xFF; + s147link_dev9_mem_mmio->m_unk0D &= 0x7F; + s147link_dev9_mem_mmio->m_unk22 |= 1; + s147link_dev9_mem_mmio->m_node_unk05 = mynode | 0x40; + s147link_dev9_mem_mmio->m_unk07 = 0; + s147link_dev9_mem_mmio->m_unk09 = mynode; + s147link_dev9_mem_mmio->m_unk09 = 2; + s147link_dev9_mem_mmio->m_unk09 = 4; + cl_info.mynode = mynode; + cl_info.maxnode = maxnode; + j = 1; + for ( i = 0; i < maxnode; i += 1 ) + { + j = (j << 1) | 1; + } + cl_info.nodemask = j; + cl_info.R_top = rx_buff[0]; + cl_info.R_remain = 0x200; + cl_info.R_out = 0; + cl_info.R_in = 0; + for ( i = 0; i < 16; i += 1 ) + { + cl_info.R_number[i] = 0; + cl_info.T_error[i] = 0; + cl_info.R_lost[i] = 0; + cl_info.T_pd[i] = 1; + cl_info.R_pd[i] = 1; + cl_info.T_time[i] = 2; + } + cl_info.T_top = tx_buff[0]; + cl_info.T_remain = 0x100; + cl_info.offtimer = 0; + cl_info.ontimer = 0; + cl_info.online = 0; + cl_info.timeout = 0; + cl_info.T_out = 0; + cl_info.T_in = 0; + cl_info.T_number = 0; + cl_info.T_node = 2; + cl_info.rbfix = 0; + CpuSuspendIntr(&state); + ReleaseIntrHandler(13); + RegisterIntrHandler(13, 1, clink_InterruptHandler, &cl_info); + s147link_dev9_mem_mmio->m_unk01 = 0xC; + s147link_dev9_mem_mmio->m_unk14 = 0x8E; + s147link_dev9_mem_mmio->m_unk15 = 0x1A; + s147link_dev9_mem_mmio->m_unk1C = 0xFF; + s147link_dev9_mem_mmio->m_unk1D = 0xFF; + s147link_dev9_mem_mmio->m_rxfc_hi_unk1E = 0xFF; + s147link_dev9_mem_mmio->m_rxfc_lo_unk1F = 0xFF; + stsH = s147link_dev9_mem_mmio->m_stsH_unk12; + stsL = s147link_dev9_mem_mmio->m_stsL_unk13; + s147link_dev9_mem_mmio->m_stsH_unk12 = stsH; + s147link_dev9_mem_mmio->m_stsL_unk13 = stsL; + CpuResumeIntr(state); + EnableIntr(13); + sceSifInitRpc(0); + param.attr = TH_C; + param.thread = s147link_loop; + param.priority = priority; + param.stacksize = 0x800; + param.option = 0; + thid = CreateThread(¶m); + if ( thid <= 0 ) + { + printf("S147LINK: Cannot create RPC server thread ...\n"); + return -1; + } + if ( StartThread(thid, 0) ) + { + printf("S147LINK: Cannot start RPC server thread ...\n"); + DeleteThread(thid); + return -2; + } + USec2SysClock(0x7D0, &cl_info.sys_clock); + if ( SetAlarm(&cl_info.sys_clock, alarm_handler, &cl_info) ) + { + printf("S147LINK: Cannot set alarm handler ...\n"); + DeleteThread(thid); + return -3; + } + return 0; +} + +#ifdef UNUSED_FUNC +static void reset_circlink(void) +{ + u8 stsH; + u8 stsL; + int i; + int j; + USE_S147LINK_DEV9_MEM_MMIO(); + + s147link_dev9_mem_mmio->m_unk0D |= 0x80; + s147link_dev9_mem_mmio->m_unk22 = 2; + s147link_dev9_mem_mmio->m_unk23 = gbBRE ? 0x51 : 0x11; + s147link_dev9_mem_mmio->m_maxnode_unk2B = cl_info.maxnode; + s147link_dev9_mem_mmio->m_mynode_unk2D = cl_info.mynode; + s147link_dev9_mem_mmio->m_unk31 = 0; + s147link_dev9_mem_mmio->m_unk2F = 2; + for ( i = 0; i < 4; i += 1 ) + { + s147link_dev9_mem_mmio->m_node_unk05 = i | 0x40; + s147link_dev9_mem_mmio->m_unk07 = 0; + for ( j = 0; j < 256; j += 1 ) + s147link_dev9_mem_mmio->m_unk09 = 0; + } + s147link_dev9_mem_mmio->m_unk28 = 0; + s147link_dev9_mem_mmio->m_unk29 = 0; + s147link_dev9_mem_mmio->m_unk21 = 0; + s147link_dev9_mem_mmio->m_unk24 = 0; + s147link_dev9_mem_mmio->m_unk25 = 0xFF; + s147link_dev9_mem_mmio->m_unk0D &= 0x7F; + s147link_dev9_mem_mmio->m_unk22 |= 1; + s147link_dev9_mem_mmio->m_node_unk05 = (cl_info.mynode & 0xFF) | 0x40; + s147link_dev9_mem_mmio->m_unk07 = 0; + s147link_dev9_mem_mmio->m_unk09 = cl_info.mynode; + s147link_dev9_mem_mmio->m_unk09 = 2; + s147link_dev9_mem_mmio->m_unk09 = 4; + s147link_dev9_mem_mmio->m_unk01 = 0xC; + s147link_dev9_mem_mmio->m_unk14 = 0x8E; + s147link_dev9_mem_mmio->m_unk15 = 0x1A; + s147link_dev9_mem_mmio->m_unk1C = 0xFF; + s147link_dev9_mem_mmio->m_unk1D = 0xFF; + s147link_dev9_mem_mmio->m_rxfc_hi_unk1E = 0xFF; + s147link_dev9_mem_mmio->m_rxfc_lo_unk1F = 0xFF; + stsH = s147link_dev9_mem_mmio->m_stsH_unk12; + stsL = s147link_dev9_mem_mmio->m_stsL_unk13; + s147link_dev9_mem_mmio->m_stsH_unk12 = stsH; + s147link_dev9_mem_mmio->m_stsL_unk13 = stsL; +} +#endif + +static unsigned int alarm_handler(void *userdata) +{ + int state; + CL_COM *io_pCommon; + USE_S147LINK_DEV9_MEM_MMIO(); + + io_pCommon = (CL_COM *)userdata; + if ( io_pCommon->timeout ) + { + if ( io_pCommon->T_time[io_pCommon->T_node] ) + { + if ( io_pCommon->T_time[io_pCommon->T_node] >= io_pCommon->timeout ) + { + io_pCommon->timeout += 1; + } + else + { + CpuSuspendIntr(&state); + (void)s147link_dev9_mem_mmio->m_stsL_unk13; + io_pCommon->timeout = 0; + s147link_dev9_mem_mmio->m_unk17 = 1; + s147link_dev9_mem_mmio->m_unk17 = 0xE; + cl_info.T_error[cl_info.T_node] = 0xFFFFFFFE; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + } + } + else + { + io_pCommon->timeout = 0; + } + } + if ( io_pCommon->ontimer ) + { + if ( io_pCommon->ontimer < 0xFA ) + { + io_pCommon->ontimer += 1; + } + else + { + io_pCommon->online = 1; + io_pCommon->offtimer = 0; + io_pCommon->ontimer = io_pCommon->offtimer; + } + } + if ( io_pCommon->offtimer ) + { + if ( io_pCommon->offtimer < 0xFA ) + io_pCommon->offtimer += 1; + else + io_pCommon->online = 0; + } + return io_pCommon->sys_clock.lo; +} + +static void s147link_loop(void *userdata) +{ + SifRpcDataQueue_t qd; + SifRpcServerData_t sd; + + (void)userdata; + sceSifSetRpcQueue(&qd, GetThreadId()); + sceSifRegisterRpc(&sd, 0x14799, dispatch, rpc_buf, 0, 0, &qd); + sceSifRpcLoop(&qd); +} + +static void *dispatch(int fno, void *buf, int size) +{ + int state; + int node; + int sizeb; + unsigned int i; + USE_S147LINK_DEV9_MEM_MMIO(); + + (void)size; + FlushDcache(); + node = fno & 0xFF; + sizeb = (fno & 0xFFFF00) >> 8; + switch ( fno >> 24 ) + { + case 0x00: + *(u32 *)buf = 1; + break; + case 0x01: + cl_info.R_pd[node] = *(u32 *)buf; + cl_info.T_pd[node] = *((u32 *)buf + 1); + cl_info.T_time[node] = *((u32 *)buf + 2); + break; + case 0x10: + CpuSuspendIntr(&state); + cl_info.T_out = 0; + cl_info.T_in = 0; + cl_info.T_remain = 0x100; + s147link_dev9_mem_mmio->m_unk17 = 1; + s147link_dev9_mem_mmio->m_unk17 = 0xE; + cl_info.T_error[cl_info.T_node] = 0xFFFFFFFD; + *(u32 *)buf = cl_info.T_node; + CpuResumeIntr(state); + break; + case 0x11: + *(u32 *)buf = cl_info.rbfix; + break; + case 0x20: + *(u32 *)buf = cl_mread((char *)buf + 4, *(u32 *)buf); + CpuSuspendIntr(&state); + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + break; + case 0x30: + *(u32 *)buf = cl_write(node, (u8 *)buf, sizeb); + break; + case 0x40: + *(u32 *)buf = cl_mwrite((u8 *)buf, sizeb); + break; + case 0x50: + CpuSuspendIntr(&state); + cl_info.R_out = 0; + cl_info.R_in = 0; + cl_info.R_remain = 0x200; + CpuResumeIntr(state); + break; + case 0x60: + *(u32 *)buf = cl_info.R_remain; + break; + case 0x70: + *(u32 *)buf = cl_info.T_remain; + break; + case 0x80: + *(u32 *)buf = cl_info.online; + break; + case 0x90: + *(u32 *)buf = cl_info.T_error[node]; + break; + case 0xA0: + CpuSuspendIntr(&state); + cl_info.T_error[node] = 0; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + break; + case 0xB0: + CpuSuspendIntr(&state); + s147link_dev9_mem_mmio->m_unk17 = 1; + s147link_dev9_mem_mmio->m_unk17 = 0xE; + cl_info.T_error[cl_info.T_node] = 0xFFFFFFFD; + *(u32 *)buf = cl_info.T_node; + s147link_dev9_mem_mmio->m_unk15 = 0x1B; + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + break; + case 0xC0: + *(u32 *)buf = cl_info.R_lost[node]; + cl_info.R_lost[node] = 0; + break; + case 0xD0: + *(u32 *)buf = cl_write_custom(node, (u8 *)buf, sizeb); + break; + case 0xF0: + CpuSuspendIntr(&state); + clink_InterruptHandler(&cl_info); + CpuResumeIntr(state); + break; + default: + printf("S147LINK: Unknown RPC command (%X)\n", fno); + break; + } + *(u32 *)buf |= (cl_info.online ? 0x10000 : 0); + for ( i = 1; i < cl_info.maxnode; i += 1 ) + { + if ( cl_info.T_error[i] ) + *(u32 *)buf |= 0x10000 << i; + if ( cl_info.R_lost[i] ) + *(u32 *)buf |= 0x10000 << i; + } + FlushDcache(); + return buf; +} diff --git a/iop/arcade/s147mdev/Makefile b/iop/arcade/s147mdev/Makefile new file mode 100644 index 00000000000..fb0ae800148 --- /dev/null +++ b/iop/arcade/s147mdev/Makefile @@ -0,0 +1,22 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= s147mdev.irx + +IOP_IMPORT_INCS += \ + system/ioman \ + system/loadcore \ + system/sysclib \ + system/sysmem + +IOP_OBJS = s147mdev.o exports.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/s147mdev/README.md b/iop/arcade/s147mdev/README.md new file mode 100644 index 00000000000..91ad2d28a95 --- /dev/null +++ b/iop/arcade/s147mdev/README.md @@ -0,0 +1,15 @@ +# S147MDEV + +This module muxes together access to System 147 storage: NAND, USB, and HTTP. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `s147mdev` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with no arguments. diff --git a/iop/arcade/s147mdev/include/s147mdev.h b/iop/arcade/s147mdev/include/s147mdev.h new file mode 100644 index 00000000000..391963a9f87 --- /dev/null +++ b/iop/arcade/s147mdev/include/s147mdev.h @@ -0,0 +1,39 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +/** + * @file + * Interface for System 147 multi-device device. + */ + +#ifndef _S147MDEV_H +#define _S147MDEV_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + extern int s147mdev_4_addfs(iop_device_t *drv, int unit10); + extern int s147mdev_5_delfs(int unit10); + +#define s147mdev_IMPORTS_start DECLARE_IMPORT_TABLE(s147mdev, 1, 1) +#define s147mdev_IMPORTS_end END_IMPORT_TABLE + +#define I_s147mdev_4_addfs DECLARE_IMPORT(4, s147mdev_4_addfs) +#define I_s147mdev_5_delfs DECLARE_IMPORT(5, s147mdev_5_delfs) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iop/arcade/s147mdev/src/exports.tab b/iop/arcade/s147mdev/src/exports.tab new file mode 100644 index 00000000000..22df2253680 --- /dev/null +++ b/iop/arcade/s147mdev/src/exports.tab @@ -0,0 +1,11 @@ + +DECLARE_EXPORT_TABLE(s147mdev, 1, 1) + DECLARE_EXPORT(_start) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(s147mdev_4_addfs) + DECLARE_EXPORT(s147mdev_5_delfs) +END_EXPORT_TABLE + +void _retonly() {} diff --git a/iop/arcade/s147mdev/src/imports.lst b/iop/arcade/s147mdev/src/imports.lst new file mode 100644 index 00000000000..dc3012c4fbf --- /dev/null +++ b/iop/arcade/s147mdev/src/imports.lst @@ -0,0 +1,17 @@ + +sysmem_IMPORTS_start +I_Kprintf +sysmem_IMPORTS_end + +ioman_IMPORTS_start +I_AddDrv +I_DelDrv +ioman_IMPORTS_end + +loadcore_IMPORTS_start +I_RegisterLibraryEntries +loadcore_IMPORTS_end + +sysclib_IMPORTS_start +I_vsprintf +sysclib_IMPORTS_end diff --git a/iop/arcade/s147mdev/src/irx_imports.h b/iop/arcade/s147mdev/src/irx_imports.h new file mode 100644 index 00000000000..59df6855b02 --- /dev/null +++ b/iop/arcade/s147mdev/src/irx_imports.h @@ -0,0 +1,24 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/s147mdev/src/s147mdev.c b/iop/arcade/s147mdev/src/s147mdev.c new file mode 100644 index 00000000000..b999a9c4a12 --- /dev/null +++ b/iop/arcade/s147mdev/src/s147mdev.c @@ -0,0 +1,266 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include +#include + +IRX_ID("S147MDEV", 2, 1); +// Text section hash: +// bda8a15d6a4c9a560598c37fd397d263 + +static int register_atfile_ioman_device(const char *atfile_name, const char *atfile_desc); +static int atfile_drv_op_nulldev(const iop_file_t *f); +static int atfile_drv_op_init(iop_device_t *dev); +static int atfile_drv_op_deinit(iop_device_t *dev); +static int atfile_drv_op_open(iop_file_t *f, const char *name, int flags); +static int atfile_drv_op_close(iop_file_t *f); +static int atfile_drv_op_read(iop_file_t *f, void *ptr, int size); +static int atfile_drv_op_write(iop_file_t *f, void *ptr, int size); +static int atfile_drv_op_lseek(iop_file_t *f, int offset, int mode); + +extern struct irx_export_table _exp_s147mdev; +static iop_device_ops_t atfile_drv_ops = { + &atfile_drv_op_init, + &atfile_drv_op_deinit, + (void *)&atfile_drv_op_nulldev, + &atfile_drv_op_open, + &atfile_drv_op_close, + &atfile_drv_op_read, + &atfile_drv_op_write, + &atfile_drv_op_lseek, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, + (void *)&atfile_drv_op_nulldev, +}; +static iop_device_t g_atfile_device; +static iop_device_t *g_atfile_unit_info[10]; + +int _start(int ac, char **av) +{ + (void)ac; + (void)av; + Kprintf("\ns147mdev.irx: System147 Multi Device File System Manager v%d.%d\n", 2, 1); + register_atfile_ioman_device("atfile", "Multi Device File System"); + if ( RegisterLibraryEntries(&_exp_s147mdev) ) + { + Kprintf("s147mdev.irx: RegisterLibraryEntries - Failed.\n"); + return MODULE_NO_RESIDENT_END; + } + Kprintf("s147mdev.irx: RegisterLibraryEntries - OK.\n"); + return MODULE_RESIDENT_END; +} + +static int register_atfile_ioman_device(const char *atfile_name, const char *atfile_desc) +{ + int i; + + for ( i = 0; i < 10; i += 1 ) + g_atfile_unit_info[i] = 0; + g_atfile_device.name = atfile_name; + g_atfile_device.type = IOP_DT_FS; + g_atfile_device.version = 0; + g_atfile_device.desc = atfile_desc; + g_atfile_device.ops = &atfile_drv_ops; + DelDrv(atfile_name); + AddDrv(&g_atfile_device); + return 0; +} + +int s147mdev_4_addfs(iop_device_t *drv, int unit10) +{ + int retres; + + if ( unit10 < 0 || unit10 >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -1; + } + if ( !drv ) + { + Kprintf("s147mdev.irx: Invalid device table\n"); + return -1; + } + retres = drv->ops->init(drv); + if ( retres >= 0 ) + g_atfile_unit_info[unit10 / 10] = drv; + return retres; +} + +int s147mdev_5_delfs(int unit10) +{ + int retres; + + if ( unit10 < 0 || unit10 >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -1; + } + retres = (g_atfile_unit_info[unit10 / 10]) ? + g_atfile_unit_info[unit10 / 10]->ops->deinit(g_atfile_unit_info[unit10 / 10]) : + 0; + if ( retres >= 0 ) + g_atfile_unit_info[unit10 / 10] = 0; + return retres; +} + +static int atfile_drv_op_nulldev(const iop_file_t *f) +{ + int unit; + + unit = f->unit; + // Unofficial: add bounds check here + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + return 0; +} + +static int atfile_drv_op_init(iop_device_t *dev) +{ + (void)dev; + return 0; +} + +static int atfile_drv_op_deinit(iop_device_t *dev) +{ + (void)dev; + return 0; +} + +static int atfile_drv_op_open(iop_file_t *f, const char *name, int flags) +{ + iop_file_t fstk; + int unit; + int retres; + + unit = f->unit; + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + fstk.mode = f->mode; + fstk.unit = f->unit % 10; + fstk.device = f->device; + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + retres = g_atfile_unit_info[unit / 10]->ops->open(&fstk, name, flags); + f->privdata = fstk.privdata; + return retres; +} + +static int atfile_drv_op_close(iop_file_t *f) +{ + iop_file_t fstk; + int unit; + + unit = f->unit; + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + fstk.mode = f->mode; + fstk.unit = f->unit % 10; + fstk.device = f->device; + fstk.privdata = f->privdata; + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + return g_atfile_unit_info[unit / 10]->ops->close(&fstk); +} + +static int atfile_drv_op_read(iop_file_t *f, void *ptr, int size) +{ + iop_file_t fstk; + int unit; + + unit = f->unit; + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + fstk.mode = f->mode; + fstk.unit = f->unit % 10; + fstk.device = f->device; + fstk.privdata = f->privdata; + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + return g_atfile_unit_info[unit / 10]->ops->read(&fstk, ptr, size); +} + +static int atfile_drv_op_write(iop_file_t *f, void *ptr, int size) +{ + iop_file_t fstk; + int unit; + + unit = f->unit; + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + fstk.mode = f->mode; + fstk.unit = f->unit % 10; + fstk.device = f->device; + fstk.privdata = f->privdata; + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + return g_atfile_unit_info[unit / 10]->ops->write(&fstk, ptr, size); +} + +static int atfile_drv_op_lseek(iop_file_t *f, int offset, int mode) +{ + iop_file_t fstk; + int unit; + + unit = f->unit; + if ( unit < 0 || unit >= 100 ) + { + Kprintf("s147mdev.irx: Invalid unit number\n"); + return -ENODEV; + } + fstk.mode = f->mode; + fstk.unit = f->unit % 10; + fstk.device = f->device; + fstk.privdata = f->privdata; + if ( !g_atfile_unit_info[unit / 10] ) + { + Kprintf("s147mdev.irx: Undefined unit number (%d), do nothing\n", unit); + return -ENODEV; + } + return g_atfile_unit_info[unit / 10]->ops->lseek(&fstk, offset, mode); +} diff --git a/iop/arcade/s147nand/Makefile b/iop/arcade/s147nand/Makefile new file mode 100644 index 00000000000..4b8813cbd54 --- /dev/null +++ b/iop/arcade/s147nand/Makefile @@ -0,0 +1,28 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= s147nand.irx + +IOP_IMPORT_INCS += \ + arcade/acdev \ + system/dmacman \ + system/intrman \ + system/ioman \ + system/loadcore \ + arcade/s147mdev \ + system/stdio \ + system/sysclib \ + system/sysmem \ + system/threadman + +IOP_OBJS = s147nand.o exports.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/s147nand/README.md b/iop/arcade/s147nand/README.md new file mode 100644 index 00000000000..ba987377c4c --- /dev/null +++ b/iop/arcade/s147nand/README.md @@ -0,0 +1,15 @@ +# S147NAND + +This module provides access to the NAND flash of System 147. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `s147nand` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with no arguments. diff --git a/iop/arcade/s147nand/include/s147nand.h b/iop/arcade/s147nand/include/s147nand.h new file mode 100644 index 00000000000..8f16f52b9b9 --- /dev/null +++ b/iop/arcade/s147nand/include/s147nand.h @@ -0,0 +1,145 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +/** + * @file + * Interface for System 147 NAND flash. + */ + +#ifndef _S147NAND_H +#define _S147NAND_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct s147nand_info_ + { + int m_page_size_noecc; + int m_page_size_withecc; + int m_pages_per_block; + int m_block_size; + int m_page_count; + } s147nand_info_t; + + typedef struct s147nand_header_part_ + { + int m_offset; + int m_size; + } s147nand_header_part_t; + + typedef struct s147nand_header_ + { + char m_sig[16]; + int m_bootsector_ver_1; + int m_bootsector_ver_2; + s147nand_header_part_t m_nand_partition_info[8]; + char m_nand_seccode[2]; + char pad[2]; + int m_nand_vidmode[1]; + char m_nand_desc[32]; + int m_page_size_noecc; + int m_page_size_withecc; + int m_pages_per_block; + int m_block_size; + unsigned int m_acmem_delay_val; + unsigned int m_acio_delay_val; + s147nand_header_part_t m_nand_partition_8_info; + } s147nand_header_t; + + typedef struct s147nand_direntry_ + { + char m_name[16]; + u32 m_unk; + u8 m_type; + u8 m_pad[3]; + u32 m_size; + u32 m_offset; + } s147nand_direntry_t; + + typedef struct s147nand_dir_ + { + char m_sig[8]; + u16 m_ver; + char m_unk0[6]; + u32 m_entrycnt; + u32 m_unk1; + u32 m_unk2; + u32 m_unk3; + s147nand_direntry_t m_direntry[63]; + } s147nand_dir_t; + + extern int s147nand_4_dumpprintinfo(int part); + extern int s147nand_5_outerinit(void); + extern void s147nand_6_checkformat(void); + extern int s147nand_7_multi_read_dma(void *ptr, int pageoffs, int pagecnt); + extern int s147nand_8_multi_write_dma(void *ptr, int pageoffs, int pagecnt); + extern int s147nand_9_get_nand_partition(int part); + extern int s147nand_10_get_nand_partition_size(int part); + extern int s147nand_11_erasetranslatepageoffs(int pageoffs); + extern int s147nand_12_load_logaddrtable(void); + extern int s147nand_13_translate_blockoffs(int blockoffs); + extern int s147nand_14_translate_pageoffs(int pageoffs); + extern int s147nand_15_nandinit(void); + extern s147nand_info_t *s147nand_16_getnandinfo(void); + extern int s147nand_17_get_sema(void); + extern void s147nand_18_enable_nand_watchdog(void); + extern int s147nand_19_logaddr_read(u16 *tbl, int pageoffs, int bytecnt); + extern int s147nand_20_nand_read_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt); + extern int s147nand_21_nand_read_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt); + extern int s147nand_22_nand_write_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt); + extern int s147nand_23_nand_write_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt); + extern int s147nand_24_eraseoffset(int pageoffs); + extern int s147nand_25_nand_blockerase(int pageoffs); + extern int s147nand_26_nand_readid(void *ptr); + extern int s147nand_27_blocks2pages(int blocks); + extern int s147nand_28_pages2blocks(int pages); + extern int s147nand_29_pages2blockround(int pages); + extern int s147nand_30_bytes2pagesnoeccround(int bytes); + +#define s147nand_IMPORTS_start DECLARE_IMPORT_TABLE(s147nand, 4, 2) +#define s147nand_IMPORTS_end END_IMPORT_TABLE + +#define I_s147nand_4_dumpprintinfo DECLARE_IMPORT(4, s147nand_4_dumpprintinfo) +#define I_s147nand_5_outerinit DECLARE_IMPORT(5, s147nand_5_outerinit) +#define I_s147nand_6_checkformat DECLARE_IMPORT(6, s147nand_6_checkformat) +#define I_s147nand_7_multi_read_dma DECLARE_IMPORT(7, s147nand_7_multi_read_dma) +#define I_s147nand_8_multi_write_dma DECLARE_IMPORT(8, s147nand_8_multi_write_dma) +#define I_s147nand_9_get_nand_partition DECLARE_IMPORT(9, s147nand_9_get_nand_partition) +#define I_s147nand_10_get_nand_partition_size DECLARE_IMPORT(10, s147nand_10_get_nand_partition_size) +#define I_s147nand_11_erasetranslatepageoffs DECLARE_IMPORT(11, s147nand_11_erasetranslatepageoffs) +#define I_s147nand_12_load_logaddrtable DECLARE_IMPORT(12, s147nand_12_load_logaddrtable) +#define I_s147nand_13_translate_blockoffs DECLARE_IMPORT(13, s147nand_13_translate_blockoffs) +#define I_s147nand_14_translate_pageoffs DECLARE_IMPORT(14, s147nand_14_translate_pageoffs) +#define I_s147nand_15_nandinit DECLARE_IMPORT(15, s147nand_15_nandinit) +#define I_s147nand_16_getnandinfo DECLARE_IMPORT(16, s147nand_16_getnandinfo) +#define I_s147nand_17_get_sema DECLARE_IMPORT(17, s147nand_17_get_sema) +#define I_s147nand_18_enable_nand_watchdog DECLARE_IMPORT(18, s147nand_18_enable_nand_watchdog) +#define I_s147nand_19_logaddr_read DECLARE_IMPORT(19, s147nand_19_logaddr_read) +#define I_s147nand_20_nand_read_dma DECLARE_IMPORT(20, s147nand_20_nand_read_dma) +#define I_s147nand_21_nand_read_pio DECLARE_IMPORT(21, s147nand_21_nand_read_pio) +#define I_s147nand_22_nand_write_dma DECLARE_IMPORT(22, s147nand_22_nand_write_dma) +#define I_s147nand_23_nand_write_pio DECLARE_IMPORT(23, s147nand_23_nand_write_pio) +#define I_s147nand_24_eraseoffset DECLARE_IMPORT(24, s147nand_24_eraseoffset) +#define I_s147nand_25_nand_blockerase DECLARE_IMPORT(25, s147nand_25_nand_blockerase) +#define I_s147nand_26_nand_readid DECLARE_IMPORT(26, s147nand_26_nand_readid) +#define I_s147nand_27_blocks2pages DECLARE_IMPORT(27, s147nand_27_blocks2pages) +#define I_s147nand_28_pages2blocks DECLARE_IMPORT(28, s147nand_28_pages2blocks) +#define I_s147nand_29_pages2blockround DECLARE_IMPORT(29, s147nand_29_pages2blockround) +#define I_s147nand_30_bytes2pagesnoeccround DECLARE_IMPORT(30, s147nand_30_bytes2pagesnoeccround) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iop/arcade/s147nand/src/exports.tab b/iop/arcade/s147nand/src/exports.tab new file mode 100644 index 00000000000..4e3f41d99a7 --- /dev/null +++ b/iop/arcade/s147nand/src/exports.tab @@ -0,0 +1,36 @@ + +DECLARE_EXPORT_TABLE(s147nand, 4, 2) + DECLARE_EXPORT(_start) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(_retonly) + DECLARE_EXPORT(s147nand_4_dumpprintinfo) + DECLARE_EXPORT(s147nand_5_outerinit) + DECLARE_EXPORT(s147nand_6_checkformat) + DECLARE_EXPORT(s147nand_7_multi_read_dma) + DECLARE_EXPORT(s147nand_8_multi_write_dma) + DECLARE_EXPORT(s147nand_9_get_nand_partition) + DECLARE_EXPORT(s147nand_10_get_nand_partition_size) + DECLARE_EXPORT(s147nand_11_erasetranslatepageoffs) + DECLARE_EXPORT(s147nand_12_load_logaddrtable) + DECLARE_EXPORT(s147nand_13_translate_blockoffs) + DECLARE_EXPORT(s147nand_14_translate_pageoffs) + DECLARE_EXPORT(s147nand_15_nandinit) + DECLARE_EXPORT(s147nand_16_getnandinfo) + DECLARE_EXPORT(s147nand_17_get_sema) + DECLARE_EXPORT(s147nand_18_enable_nand_watchdog) + DECLARE_EXPORT(s147nand_19_logaddr_read) + DECLARE_EXPORT(s147nand_20_nand_read_dma) + DECLARE_EXPORT(s147nand_21_nand_read_pio) + DECLARE_EXPORT(s147nand_22_nand_write_dma) + DECLARE_EXPORT(s147nand_23_nand_write_pio) + DECLARE_EXPORT(s147nand_24_eraseoffset) + DECLARE_EXPORT(s147nand_25_nand_blockerase) + DECLARE_EXPORT(s147nand_26_nand_readid) + DECLARE_EXPORT(s147nand_27_blocks2pages) + DECLARE_EXPORT(s147nand_28_pages2blocks) + DECLARE_EXPORT(s147nand_29_pages2blockround) + DECLARE_EXPORT(s147nand_30_bytes2pagesnoeccround) +END_EXPORT_TABLE + +void _retonly() {} diff --git a/iop/arcade/s147nand/src/imports.lst b/iop/arcade/s147nand/src/imports.lst new file mode 100644 index 00000000000..40a398bc285 --- /dev/null +++ b/iop/arcade/s147nand/src/imports.lst @@ -0,0 +1,65 @@ + +sysmem_IMPORTS_start +I_AllocSysMemory +I_FreeSysMemory +I_Kprintf +sysmem_IMPORTS_end + +intrman_IMPORTS_start +I_RegisterIntrHandler +I_ReleaseIntrHandler +I_EnableIntr +I_DisableIntr +I_CpuSuspendIntr +I_CpuResumeIntr +intrman_IMPORTS_end + +loadcore_IMPORTS_start +I_RegisterLibraryEntries +loadcore_IMPORTS_end + +stdio_IMPORTS_start +I_printf +stdio_IMPORTS_end + +sysclib_IMPORTS_start +I_memcpy +I_memset +I_strcat +I_strcmp +I_strcpy +I_strncmp +I_strncpy +I_vsprintf +sysclib_IMPORTS_end + +thbase_IMPORTS_start +I_GetThreadId +I_SleepThread +I_iWakeupThread +I_DelayThread +thbase_IMPORTS_end + +thsemap_IMPORTS_start +I_CreateSema +I_SignalSema +I_WaitSema +thsemap_IMPORTS_end + +dmacman_IMPORTS_start +I_sceSetSliceDMA +I_sceStartDMA +I_sceSetDMAPriority +I_sceEnableDMAChannel +I_sceDisableDMAChannel +dmacman_IMPORTS_end + +acdev_IMPORTS_start +I_SetAcMemDelayReg +I_SetAcIoDelayReg +acdev_IMPORTS_end + +s147mdev_IMPORTS_start +I_s147mdev_4_addfs +I_s147mdev_5_delfs +s147mdev_IMPORTS_end diff --git a/iop/arcade/s147nand/src/irx_imports.h b/iop/arcade/s147nand/src/irx_imports.h new file mode 100644 index 00000000000..734afa67578 --- /dev/null +++ b/iop/arcade/s147nand/src/irx_imports.h @@ -0,0 +1,30 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/s147nand/src/s147nand.c b/iop/arcade/s147nand/src/s147nand.c new file mode 100644 index 00000000000..abe286aa1d3 --- /dev/null +++ b/iop/arcade/s147nand/src/s147nand.c @@ -0,0 +1,1372 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include +#include +#include +#include +#include + +IRX_ID("S147NAN2", 5, 2); +// Text section hash: +// 7894f2d18e733e5f2422b6c61af3b0da + +typedef struct s147nand_mdev_privdata_ +{ + int m_seek_cur; + int m_flags; + int m_seek_max; + int m_partition_offset; +} s147nand_mdev_privdata_t; + +static int do_register_nand_to_mdev(const char *drv_name, const char *drv_desc); +static int nand_mdev_op_init(iop_device_t *dev); +static int nand_mdev_op_deinit(iop_device_t *dev); +static int nand_mdev_op_open(iop_file_t *f, const char *name, int flags); +static int nand_mdev_op_close(iop_file_t *f); +static int nand_mdev_op_read(iop_file_t *f, void *ptr, int size); +static int nand_mdev_op_write(iop_file_t *f, void *ptr, int size); +static int nand_mdev_op_lseek(iop_file_t *f, int offset, int mode); +static int do_nand_open_inner1(s147nand_mdev_privdata_t *privdat, int part, const char *name); +static int do_nand_open_inner2(s147nand_mdev_privdata_t *privdat, const char *name); +static u32 do_get_nand_direntry(s147nand_mdev_privdata_t *privdat, const char *name, int idx, char typ); +static int do_nand_bytes2sector(int pageoffs, int byteoffs); +static int do_nand_bytes2sector_remainder(int byteoffs); +static int do_nand_sector_rw(void *ptr, int pageoffs, int byteoffs, int size); +static int get_nand_partition_offset(int part); +static int nand_mdev_open_special(iop_file_t *f, const char *name); +static int nand_mdev_read_special(iop_file_t *f, void *ptr, int size); +static int nand_mdev_write_special(iop_file_t *f, void *ptr, int size); +static int do_nand_copy_seccode_from_buf(iop_file_t *f, void *ptr, int size); +static int do_nand_copy_videomode_from_buf(iop_file_t *f, void *ptr, int size); +static int nand_lowlevel_read_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt); +static int nand_lowlevel_read_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt); +static int nand_lowlevel_write_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt); +static int nand_lowlevel_write_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt); +static int nand_lowlevel_blockerase(int pageoffs); +static int nand_lowlevel_readid(void *ptr); + +extern struct irx_export_table _exp_s147nand; + +IOMAN_RETURN_VALUE_IMPL(0); + +static iop_device_ops_t nand_mdev_ops = { + &nand_mdev_op_init, + &nand_mdev_op_deinit, + IOMAN_RETURN_VALUE(0), + &nand_mdev_op_open, + &nand_mdev_op_close, + &nand_mdev_op_read, + &nand_mdev_op_write, + &nand_mdev_op_lseek, + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), + IOMAN_RETURN_VALUE(0), +}; +// Unofficial: move to bss +static void *g_nand_unaligned_buf; +// Unofficial: move to bss +static int g_nand_watchdog_enabled; +// Unofficial: move to bss +static s147nand_info_t g_nand_info; +static iop_device_t g_drv; +static void *g_nand_sector_buffer; +static int g_sema_id_dev; +static int g_sema_id_init; +static s147nand_header_t g_nand_header __attribute__((__aligned__(16))); +static u16 *g_logical_addr_tbl; +static int g_sema_id_nand; +static int g_thid; + +int _start(int ac, char **av) +{ + (void)ac; + (void)av; + Kprintf("\ns147nand.irx: System147 NAND-Flash File System Driver v%d.%d\n", 5, 2); + // Unofficial: init vars here instead + g_nand_info.m_page_size_noecc = 0x800; + g_nand_info.m_page_size_withecc = 0x840; + g_nand_info.m_pages_per_block = 0x40; + g_nand_info.m_block_size = 0x800; + g_nand_info.m_page_count = 0x20000; + if ( do_register_nand_to_mdev("nand", "NAND-Flash") ) + return MODULE_NO_RESIDENT_END; + if ( RegisterLibraryEntries(&_exp_s147nand) ) + { + Kprintf("s147nand.irx: RegisterLibraryEntries - Failed.\n"); + return MODULE_NO_RESIDENT_END; + } + Kprintf("s147nand.irx: RegisterLibraryEntries - OK.\n"); + return MODULE_RESIDENT_END; +} + +static int do_register_nand_to_mdev(const char *drv_name, const char *drv_desc) +{ + iop_sema_t semaparam; + + if ( s147nand_5_outerinit() < 0 ) + return -1; + // Unofficial: make semaparam local var + semaparam.initial = 1; + semaparam.max = 1; + semaparam.attr = SA_THPRI; + semaparam.option = 0; + g_sema_id_dev = CreateSema(&semaparam); + if ( g_sema_id_dev < 0 ) + { + Kprintf("s147nand.irx: CreateSema error (%d)\n", g_sema_id_dev); + return -1; + } + g_drv.name = drv_name; + g_drv.type = IOP_DT_FS; + g_drv.version = 0; + g_drv.desc = drv_desc; + g_drv.ops = &nand_mdev_ops; + s147mdev_5_delfs(0); + s147mdev_4_addfs(&g_drv, 0); + // Unofficial: remove redundant var + return 0; +} + +static int nand_mdev_op_init(iop_device_t *dev) +{ + int state; + + (void)dev; + Kprintf("s147nand.irx: SectorBuffer=%d, FileParam=%d\n", 0, 1); + CpuSuspendIntr(&state); + g_nand_sector_buffer = AllocSysMemory(ALLOC_FIRST, 2048, 0); + CpuResumeIntr(state); + if ( g_nand_sector_buffer ) + return 0; + Kprintf("s147nand.irx: AllocSysMemory failed (s147file_Init)\n"); + return -ENOMEM; +} + +static int nand_mdev_op_deinit(iop_device_t *dev) +{ + int state; + + (void)dev; + if ( g_nand_sector_buffer ) + { + CpuSuspendIntr(&state); + FreeSysMemory(g_nand_sector_buffer); + CpuResumeIntr(state); + } + return 0; +} + +static int nand_mdev_op_open(iop_file_t *f, const char *name, int flags) +{ + s147nand_mdev_privdata_t *privdat; + int state; + int retres; + + (void)flags; + retres = 0; + WaitSema(g_sema_id_dev); + if ( f->unit == 9 ) + { + retres = nand_mdev_open_special(f, name); + SignalSema(g_sema_id_dev); + return retres; + } + CpuSuspendIntr(&state); + f->privdata = AllocSysMemory(ALLOC_LAST, sizeof(s147nand_mdev_privdata_t), 0); + CpuResumeIntr(state); + if ( !f->privdata ) + { + Kprintf("s147nand.irx: AllocSysMemory failed (Open)\n"); + retres = -ENOMEM; + } + if ( retres >= 0 ) + { + privdat = (s147nand_mdev_privdata_t *)f->privdata; + memset(privdat, 0, sizeof(s147nand_mdev_privdata_t)); + retres = do_nand_open_inner1(privdat, f->unit, name); + } + if ( retres < 0 ) + { + // Unofficial: check if not NULL + if ( f->privdata ) + { + CpuSuspendIntr(&state); + FreeSysMemory(f->privdata); + CpuResumeIntr(state); + } + SignalSema(g_sema_id_dev); + return retres; + } + privdat->m_seek_cur = 0; + SignalSema(g_sema_id_dev); + return 0; +} + +static int nand_mdev_op_close(iop_file_t *f) +{ + int state; + + WaitSema(g_sema_id_dev); + if ( f->privdata ) + { + CpuSuspendIntr(&state); + FreeSysMemory(f->privdata); + CpuResumeIntr(state); + f->privdata = 0; + } + SignalSema(g_sema_id_dev); + return 0; +} + +static int nand_mdev_op_read(iop_file_t *f, void *ptr, int size) +{ + int xsize3; + s147nand_mdev_privdata_t *privdat; + int xsector1; + int xsector2; + int xsize2; + int cursz; + + privdat = (s147nand_mdev_privdata_t *)f->privdata; + WaitSema(g_sema_id_dev); + if ( privdat->m_seek_cur >= privdat->m_seek_max ) + { + SignalSema(g_sema_id_dev); + return 0; + } + xsize2 = (privdat->m_seek_max >= privdat->m_seek_cur + size) ? size : (privdat->m_seek_max - privdat->m_seek_cur); + if ( privdat->m_seek_cur < 0 || privdat->m_seek_max < 0 ) + Kprintf( + "s147file: CallBack_Read -> Param=0x%08x Seek=%d/%d Count=%d CountEnd=%d\n", + privdat, + privdat->m_seek_cur, + privdat->m_seek_max, + size, + xsize2); + if ( f->unit == 9 ) + { + int special; + + special = nand_mdev_read_special(f, ptr, size); + SignalSema(g_sema_id_dev); + return special; + } + xsector1 = do_nand_bytes2sector(privdat->m_partition_offset, privdat->m_seek_cur + xsize2); + xsector2 = do_nand_bytes2sector_remainder(privdat->m_seek_cur + xsize2); + for ( cursz = 0; cursz < xsize2; cursz += xsize3 ) + { + int pageoffs; + + pageoffs = do_nand_bytes2sector(privdat->m_partition_offset, privdat->m_seek_cur); + xsize3 = ((pageoffs >= xsector1) ? xsector2 : 2048) - do_nand_bytes2sector_remainder(privdat->m_seek_cur); + do_nand_sector_rw(((char *)ptr) + cursz, pageoffs, do_nand_bytes2sector_remainder(privdat->m_seek_cur), xsize3); + privdat->m_seek_cur += xsize3; + } + SignalSema(g_sema_id_dev); + return xsize2; +} + +static int nand_mdev_op_write(iop_file_t *f, void *ptr, int size) +{ + WaitSema(g_sema_id_dev); + if ( f->unit == 9 ) + { + int retres; + + retres = nand_mdev_write_special(f, ptr, size); + SignalSema(g_sema_id_dev); + return retres; + } + SignalSema(g_sema_id_dev); + return size; +} + +static int nand_mdev_op_lseek(iop_file_t *f, int offset, int mode) +{ + s147nand_mdev_privdata_t *privdat; + + privdat = (s147nand_mdev_privdata_t *)f->privdata; + WaitSema(g_sema_id_dev); + switch ( mode ) + { + case SEEK_SET: + privdat->m_seek_cur = offset; + break; + case SEEK_CUR: + privdat->m_seek_cur += offset; + break; + case SEEK_END: + privdat->m_seek_cur = privdat->m_seek_max + offset; + break; + default: + SignalSema(g_sema_id_dev); + return -EINVAL; + } + if ( privdat->m_seek_max < privdat->m_seek_cur ) + { + Kprintf("s147nand.irx: Out of range (seek=%d, filesize=%d)\n", privdat->m_seek_cur, privdat->m_seek_max); + privdat->m_seek_cur = privdat->m_seek_max; + SignalSema(g_sema_id_dev); + return -EINVAL; + } + SignalSema(g_sema_id_dev); + return privdat->m_seek_cur; +} + +int s147nand_4_dumpprintinfo(int part) +{ + int hdrret; + int nand_partition_offset; + int i; + int j; + int dircnt; + int filcnt; + int finished; + char pathtmp[18]; + + hdrret = -1; + dircnt = 0; + filcnt = 0; + finished = 0; + nand_partition_offset = get_nand_partition_offset(part); + if ( nand_partition_offset < 0 ) + return -ENODEV; + for ( i = 0; i < 64; i += 1 ) + { + s147nand_7_multi_read_dma(g_nand_sector_buffer, nand_partition_offset + i, 1); + for ( j = 0; j < 64; j += 1 ) + { + if ( (i << 6) - 1 + j == -1 ) + { + const s147nand_dir_t *hdrbuf; + + hdrbuf = (const s147nand_dir_t *)g_nand_sector_buffer; + if ( strncmp(hdrbuf->m_sig, "S147ROM", 8) ) + { + // Unofficial: use g_drv.name + Kprintf(" \"%s%d:\" ... No data\n", g_drv.name, part); + Kprintf(" -----------------------------\n\n"); + return -ENODEV; + } + hdrret = hdrbuf->m_entrycnt; + // Unofficial: use g_drv.name + Kprintf(" \"%s%d:\"\n", g_drv.name, part); + Kprintf(" -----------------------------\n"); + } + else + { + const s147nand_direntry_t *dirbuf; + + dirbuf = (const s147nand_direntry_t *)g_nand_sector_buffer; + if ( (i << 6) - 1 + j >= hdrret ) + { + finished = 1; + break; + } + strcpy(pathtmp, dirbuf[j].m_name); + if ( dirbuf[j].m_type == 'D' ) + { + strcat(pathtmp, "/"); + dircnt += 1; + } + else + { + filcnt += 1; + } + Kprintf(" %9d %s\n", dirbuf[j].m_size, pathtmp); + } + } + if ( finished ) + break; + } + Kprintf(" -----------------------------\n"); + Kprintf(" %d directories, %d files\n", dircnt, filcnt); + Kprintf("\n"); + return hdrret; +} + +static int do_nand_open_inner1(s147nand_mdev_privdata_t *privdat, int part, const char *name) +{ + int nand_partition_offset; + + nand_partition_offset = get_nand_partition_offset(part); + if ( nand_partition_offset < 0 ) + { + Kprintf("s147nand.irx: Error invalid unit number\n"); + return -ENODEV; + } + privdat->m_partition_offset = nand_partition_offset; + return do_nand_open_inner2(privdat, name + ((name[0] == '/') ? 1 : 0)); +} + +static int do_nand_open_inner2(s147nand_mdev_privdata_t *privdat, const char *name) +{ + int i; + + for ( i = 0; name[i] && name[i] != '/'; i += 1 ) + ; + if ( name[i] == '/' ) + { + int nand_direntry; + + nand_direntry = do_get_nand_direntry(privdat, name, i, 'D'); + return (nand_direntry >= 0) ? do_nand_open_inner2(privdat, &name[i + 1]) : nand_direntry; + } + return do_get_nand_direntry(privdat, name, i, 'F'); +} + +static u32 do_get_nand_direntry(s147nand_mdev_privdata_t *privdat, const char *name, int idx, char typ) +{ + int lvtyp; + int size; + int hdrret; + int offscnt; + int i; + char name_trunc[18]; + + hdrret = -1; + size = (idx > (int)(sizeof(name_trunc) - 2)) ? (int)(sizeof(name_trunc) - 2) : idx; + strncpy(name_trunc, name, size); + name_trunc[size] = 0; + for ( offscnt = 0; offscnt < 64; offscnt += 1 ) + { + s147nand_7_multi_read_dma(g_nand_sector_buffer, privdat->m_partition_offset + offscnt, 1); + + for ( i = 0; i < 64; i += 1 ) + { + if ( (offscnt << 6) - 1 + i == -1 ) + { + const s147nand_dir_t *hdrbuf; + + hdrbuf = (const s147nand_dir_t *)g_nand_sector_buffer; + if ( strncmp(hdrbuf->m_sig, "S147ROM", 8) ) + { + Kprintf("s147nand.irx: No directory entries\n"); + return -ENODEV; + } + if ( hdrbuf->m_ver >= 0x101 ) + { + Kprintf("s147nand.irx: Version 0x%04x format is not supported\n", hdrbuf->m_ver); + return -ENODEV; + } + hdrret = hdrbuf->m_entrycnt; + } + else + { + const s147nand_direntry_t *dirbuf; + + dirbuf = (const s147nand_direntry_t *)g_nand_sector_buffer; + if ( (offscnt << 6) - 1 + i >= hdrret ) + return -ENOENT; + lvtyp = (char)dirbuf[i].m_type; + if ( + (((lvtyp == 'D') && typ == 'D') || ((lvtyp == 'F' || lvtyp == '\x00') && typ == 'F')) + && (!strcmp(dirbuf[i].m_name, name_trunc)) ) + { + privdat->m_seek_max = dirbuf[i].m_size; + privdat->m_partition_offset += dirbuf[i].m_offset; + return dirbuf[i].m_size; + } + } + } + } + return -ENOENT; +} + +static int do_nand_bytes2sector(int pageoffs, int byteoffs) +{ + return pageoffs + byteoffs / 2048; +} + +static int do_nand_bytes2sector_remainder(int byteoffs) +{ + return byteoffs % 2048; +} + +int s147nand_5_outerinit(void) +{ + int initres; + iop_sema_t semaparam; + + initres = s147nand_15_nandinit(); + if ( initres ) + { + Kprintf("s147nand.irx: NAND initialize failed (%d)\n", initres); + return -1; + } + // Unofficial: make semaparam local var + semaparam.initial = 1; + semaparam.max = 1; + semaparam.attr = SA_THPRI; + semaparam.option = 0; + g_sema_id_init = CreateSema(&semaparam); + if ( g_sema_id_init < 0 ) + { + Kprintf("s147nand.irx: CreateSema error (%d)\n", g_sema_id_init); + return -1; + } + s147nand_6_checkformat(); + return 0; +} + +void s147nand_6_checkformat(void) +{ + int state; + s147nand_info_t *nandinf; + + nandinf = s147nand_16_getnandinfo(); + s147nand_20_nand_read_dma(&g_nand_header, 0, 0, sizeof(g_nand_header)); + if ( strncmp(g_nand_header.m_sig, "S147NAND", 9) ) + { + Kprintf("s147nand.irx: Unformatted device\n"); + Kprintf("\n"); + return; + } + Kprintf( + "s147nand.irx: BootSector format version = %d.%d\n", + g_nand_header.m_bootsector_ver_1, + g_nand_header.m_bootsector_ver_2); + if ( (u32)g_nand_header.m_bootsector_ver_1 < 2 ) + { + Kprintf("s147nand.irx: Old version format, 256MB-NAND only\n"); + } + else + { + Kprintf("s147nand.irx: %-.32s\n", g_nand_header.m_nand_desc); + CpuSuspendIntr(&state); + nandinf->m_page_size_noecc = g_nand_header.m_page_size_noecc; + nandinf->m_page_size_withecc = g_nand_header.m_page_size_withecc; + nandinf->m_pages_per_block = g_nand_header.m_pages_per_block; + nandinf->m_block_size = g_nand_header.m_block_size; + nandinf->m_page_count = g_nand_header.m_block_size * g_nand_header.m_pages_per_block; + CpuResumeIntr(state); + } + Kprintf( + "s147nand.irx: PageSize = %d + %d (Bytes)\n", + nandinf->m_page_size_noecc, + nandinf->m_page_size_withecc - nandinf->m_page_size_noecc); + Kprintf("s147nand.irx: Pages/Block = %d (Pages)\n", nandinf->m_pages_per_block); + Kprintf("s147nand.irx: BlockSize = %d (Blocks)\n", nandinf->m_block_size); + Kprintf("s147nand.irx: PageSize = %d (Pages)\n", nandinf->m_page_count); + Kprintf("\n"); +} + +static void do_update_acdelay(void) +{ + int state; + + Kprintf("s147nand.irx: Update Acdelay\n", g_nand_header.m_bootsector_ver_1, g_nand_header.m_bootsector_ver_2); + DelayThread(10000); + if ( (u32)g_nand_header.m_bootsector_ver_1 < 2 ) + { + Kprintf("s147nand.irx: Old version format, no update\n"); + DelayThread(10000); + return; + } + if ( !g_nand_header.m_acmem_delay_val || (int)g_nand_header.m_acmem_delay_val == -1 ) + { + Kprintf("s147nand.irx: AcMem = 0x%08x (Default)\n", g_nand_header.m_acmem_delay_val); + } + else + { + CpuSuspendIntr(&state); + SetAcMemDelayReg(g_nand_header.m_acmem_delay_val); + CpuResumeIntr(state); + Kprintf( + "s147nand.irx: AcMem = 0x%08x (DMA=%d, Read=%d, Write=%d)\n", + g_nand_header.m_acmem_delay_val, + ((g_nand_header.m_acmem_delay_val & 0xF000000) >> 24) + 1, + ((u8)(g_nand_header.m_acmem_delay_val & 0xF0) >> 4) + 1, + (g_nand_header.m_acmem_delay_val & 0xF) + 1); + } + DelayThread(10000); + if ( !g_nand_header.m_acio_delay_val || (int)g_nand_header.m_acio_delay_val == -1 ) + { + Kprintf("s147nand.irx: AcIo = 0x%08x (Default)\n", g_nand_header.m_acio_delay_val); + } + else + { + CpuSuspendIntr(&state); + SetAcIoDelayReg(g_nand_header.m_acio_delay_val); + CpuResumeIntr(state); + Kprintf( + "s147nand.irx: AcIo = 0x%08x (DMA=%d, Read=%d, Write=%d)\n", + g_nand_header.m_acio_delay_val, + ((g_nand_header.m_acio_delay_val & 0xF000000) >> 24) + 1, + ((u8)(g_nand_header.m_acio_delay_val & 0xF0) >> 4) + 1, + (g_nand_header.m_acio_delay_val & 0xF) + 1); + } + DelayThread(10000); + Kprintf("\n"); + DelayThread(10000); +} + +static int do_nand_sector_rw(void *ptr, int pageoffs, int byteoffs, int size) +{ + int dma; + + WaitSema(g_sema_id_init); + if ( ((uiptr)ptr & 3) != 0 || (byteoffs & 3) != 0 || (size & 3) != 0 ) + { + dma = s147nand_20_nand_read_dma( + g_nand_unaligned_buf, s147nand_14_translate_pageoffs(pageoffs), 0, s147nand_16_getnandinfo()->m_page_size_noecc); + memcpy(ptr, (char *)g_nand_unaligned_buf + byteoffs, size); + } + else + { + dma = s147nand_20_nand_read_dma(ptr, s147nand_14_translate_pageoffs(pageoffs), byteoffs, size); + } + SignalSema(g_sema_id_init); + return dma; +} + +int s147nand_7_multi_read_dma(void *ptr, int pageoffs, int pagecnt) +{ + int i; + int retres; + + // Unofficial: initialize retres + retres = 0; + WaitSema(g_sema_id_init); + for ( i = 0; i < pagecnt; i += 1 ) + { + retres = s147nand_20_nand_read_dma( + (char *)ptr + ((s147nand_16_getnandinfo()->m_page_size_noecc >> 2) << 2) * i, + s147nand_14_translate_pageoffs(pageoffs + i), + 0, + s147nand_16_getnandinfo()->m_page_size_noecc); + if ( retres ) + return retres; + } + SignalSema(g_sema_id_init); + return retres; +} + +int s147nand_8_multi_write_dma(void *ptr, int pageoffs, int pagecnt) +{ + int i; + int retres; + + // Unofficial: initialize retres + retres = 0; + for ( i = 0; i < pagecnt; i += 1 ) + { + retres = s147nand_22_nand_write_dma( + (char *)ptr + ((s147nand_16_getnandinfo()->m_page_size_noecc >> 2) << 2) * i, + s147nand_14_translate_pageoffs(pageoffs + i), + 0, + s147nand_16_getnandinfo()->m_page_size_noecc); + if ( retres ) + return retres; + } + return retres; +} + +int s147nand_9_get_nand_partition(int part) +{ + if ( part == 8 ) + return g_nand_header.m_nand_partition_8_info.m_offset; + if ( part >= 0 && part < 8 ) + return g_nand_header.m_nand_partition_info[part].m_offset; + return 0; +} + +static int get_nand_partition_offset(int part) +{ + return s147nand_9_get_nand_partition(part) * g_nand_header.m_pages_per_block; +} + +int s147nand_10_get_nand_partition_size(int part) +{ + if ( part == 8 ) + return g_nand_header.m_nand_partition_8_info.m_size; + if ( part >= 0 && part < 8 ) + return g_nand_header.m_nand_partition_info[part].m_size; + return 0; +} + +static int nand_mdev_open_special(iop_file_t *f, const char *name) +{ + s147nand_mdev_privdata_t *privdat; + int state; + + CpuSuspendIntr(&state); + f->privdata = AllocSysMemory(ALLOC_FIRST, sizeof(s147nand_mdev_privdata_t), 0); + CpuResumeIntr(state); + if ( !f->privdata ) + { + Kprintf("s147nand.irx: AllocSysMemory failed (9:Open)\n"); + // Unofficial: return early on error + return -ENOENT; + } + privdat = (s147nand_mdev_privdata_t *)f->privdata; + memset(privdat, 0, sizeof(s147nand_mdev_privdata_t)); + privdat->m_seek_cur = 0; + if ( !strcmp(name, "watchdog-enable") ) + { + s147nand_18_enable_nand_watchdog(); + privdat->m_flags = 0; + privdat->m_seek_max = 0; + privdat->m_partition_offset = 0; + privdat->m_seek_cur = 0; + Kprintf("s147nand.irx: WatchDogTimer Enable\n"); + DelayThread(10000); + } + else if ( !strcmp(name, "acdelay") ) + { + do_update_acdelay(); + privdat->m_flags = 0; + privdat->m_seek_max = 0; + privdat->m_partition_offset = 0; + privdat->m_seek_cur = 0; + } + else if ( !strcmp(name, "seccode") ) + { + privdat->m_flags = 0x10000; + privdat->m_seek_max = 2; + privdat->m_partition_offset = 0; + privdat->m_seek_cur = 0; + } + else if ( !strcmp(name, "videomode") ) + { + privdat->m_flags = 0x40000; + privdat->m_seek_max = 4; + privdat->m_partition_offset = 0; + privdat->m_seek_cur = 0; + } + else if ( !strcmp(name, "info") ) + { + privdat->m_flags = 0x100000; + privdat->m_seek_max = 2048; + privdat->m_partition_offset = (s147nand_9_get_nand_partition(8) - 1) * g_nand_header.m_pages_per_block; + privdat->m_seek_cur = 0; + } + else if ( !strcmp(name, "romwrite-tmp") ) + { + privdat->m_flags = 0x3000000; + privdat->m_seek_max = 0; + privdat->m_partition_offset = s147nand_9_get_nand_partition(8) * g_nand_header.m_pages_per_block; + privdat->m_seek_cur = 0; + } + else + { + CpuSuspendIntr(&state); + FreeSysMemory(f->privdata); + CpuResumeIntr(state); + return -ENOENT; + } + return 0; +} + +static int nand_mdev_read_special(iop_file_t *f, void *ptr, int size) +{ + s147nand_mdev_privdata_t *privdata; + int retres1; + + privdata = (s147nand_mdev_privdata_t *)f->privdata; + if ( (privdata->m_flags & 0x10000) != 0 ) + return do_nand_copy_seccode_from_buf(f, ptr, size); + if ( (privdata->m_flags & 0x40000) != 0 ) + return do_nand_copy_videomode_from_buf(f, ptr, size); + if ( (privdata->m_flags & 0x100000) != 0 ) + { + retres1 = do_nand_sector_rw(ptr, privdata->m_partition_offset, privdata->m_seek_cur, size); + if ( retres1 < 0 ) + return retres1; + privdata->m_seek_cur += size; + return size; + } + if ( (privdata->m_flags & 0x1000000) != 0 ) + { + retres1 = do_nand_sector_rw(ptr, privdata->m_partition_offset, privdata->m_seek_cur, size); + if ( retres1 < 0 ) + return retres1; + privdata->m_seek_cur += size; + return size; + } + return -ENOENT; +} + +static int nand_mdev_write_special(iop_file_t *f, void *ptr, int size) +{ + s147nand_mdev_privdata_t *privdata; + int retres1; + int xsz; + + privdata = (s147nand_mdev_privdata_t *)f->privdata; + xsz = + g_nand_header.m_nand_partition_8_info.m_size * g_nand_header.m_pages_per_block * g_nand_header.m_page_size_noecc; + if ( (privdata->m_flags & 0x1000000) == 0 ) + return -EINVAL; + if ( xsz < privdata->m_seek_cur + size ) + { + Kprintf("s147nand.irx: Out of rewritable partition, lseek(%d) > max(%d)\n", privdata->m_seek_cur + size, xsz); + return -EFBIG; + } + if ( (privdata->m_flags & 0x2000000) != 0 ) + { + int i; + + retres1 = 0; + for ( i = 0; i < g_nand_header.m_nand_partition_8_info.m_size; i += 1 ) + retres1 = s147nand_11_erasetranslatepageoffs( + s147nand_27_blocks2pages(i + g_nand_header.m_nand_partition_8_info.m_offset)); + privdata->m_flags &= ~0x2000000; + if ( retres1 ) + return retres1; + } + if ( !g_nand_header.m_page_size_noecc ) + __builtin_trap(); + if ( g_nand_header.m_page_size_noecc == -1 && privdata->m_seek_cur == (int)0x80000000 ) + __builtin_trap(); + if ( !g_nand_header.m_page_size_noecc ) + __builtin_trap(); + if ( g_nand_header.m_page_size_noecc == -1 && size == (int)0x80000000 ) + __builtin_trap(); + retres1 = s147nand_8_multi_write_dma( + ptr, + privdata->m_seek_cur / g_nand_header.m_page_size_noecc + privdata->m_partition_offset, + size / g_nand_header.m_page_size_noecc); + if ( retres1 < 0 ) + return retres1; + privdata->m_seek_cur += size; + privdata->m_seek_max = privdata->m_seek_cur; + return size; +} + +static int do_nand_copy_seccode_from_buf(iop_file_t *f, void *ptr, int size) +{ + s147nand_mdev_privdata_t *privdata; + int xsize; + + privdata = (s147nand_mdev_privdata_t *)f->privdata; + if ( privdata->m_seek_cur >= privdata->m_seek_max ) + return 0; + xsize = + (privdata->m_seek_max >= (int)(privdata->m_seek_cur + size)) ? size : (privdata->m_seek_max - privdata->m_seek_cur); + memcpy(ptr, &g_nand_header.m_nand_seccode[privdata->m_seek_cur], xsize); + privdata->m_seek_cur += xsize; + return xsize; +} + +static int do_nand_copy_videomode_from_buf(iop_file_t *f, void *ptr, int size) +{ + s147nand_mdev_privdata_t *privdata; + int xsize; + + privdata = (s147nand_mdev_privdata_t *)f->privdata; + if ( privdata->m_seek_cur >= privdata->m_seek_max ) + return 0; + xsize = + (privdata->m_seek_max >= (int)(privdata->m_seek_cur + size)) ? size : (privdata->m_seek_max - privdata->m_seek_cur); + memcpy(ptr, &g_nand_header.m_nand_vidmode[privdata->m_seek_cur], xsize); + privdata->m_seek_cur += xsize; + return xsize; +} + +int s147nand_11_erasetranslatepageoffs(int pageoffs) +{ + return s147nand_24_eraseoffset(s147nand_14_translate_pageoffs(pageoffs)); +} + +int s147nand_12_load_logaddrtable(void) +{ + s147nand_header_t hdr __attribute__((__aligned__(16))); + int state; + + s147nand_20_nand_read_dma(&hdr, 0, 0, sizeof(hdr)); + if ( strncmp(hdr.m_sig, "S147NAND", 9) ) + { + Kprintf("s147nand.irx: Unformatted device error.\n"); + return -19; + } + CpuSuspendIntr(&state); + g_logical_addr_tbl = (u16 *)AllocSysMemory(ALLOC_FIRST, sizeof(u16) * hdr.m_block_size, 0); + CpuResumeIntr(state); + s147nand_19_logaddr_read(g_logical_addr_tbl, 1, sizeof(u16) * hdr.m_block_size); + CpuSuspendIntr(&state); + g_nand_unaligned_buf = AllocSysMemory(ALLOC_FIRST, s147nand_16_getnandinfo()->m_page_size_noecc, 0); + CpuResumeIntr(state); + if ( !g_nand_unaligned_buf ) + { + Kprintf("s147nand.irx: AllocSysMemory failed (LogAddrTable)\n"); + return -1; + } + // Unofficial: remove redundant var + return 0; +} + +int s147nand_13_translate_blockoffs(int blockoffs) +{ + int tbladdr; + + if ( blockoffs <= 0 || blockoffs >= s147nand_16_getnandinfo()->m_block_size ) + { + Kprintf("s147nand.irx: Invalid logical block address %d\n", blockoffs); + return -1470010; + } + // Unofficial: check g_nand_unaligned_buf instead + if ( !g_nand_unaligned_buf ) + { + int logaddrtable; + + logaddrtable = s147nand_12_load_logaddrtable(); + if ( logaddrtable < 0 ) + return logaddrtable; + } + tbladdr = g_logical_addr_tbl[blockoffs]; + switch ( tbladdr ) + { + case 0xAAAA: + return blockoffs; + case 0xCCCC: + case 0xEEEE: + return -1470010; + default: + return tbladdr; + } +} + +int s147nand_14_translate_pageoffs(int pageoffs) +{ + int tblockoffs; + + tblockoffs = s147nand_13_translate_blockoffs(s147nand_28_pages2blocks(pageoffs)); + if ( tblockoffs == -1470010 ) + return -1470010; + if ( !g_nand_header.m_pages_per_block ) + __builtin_trap(); + if ( g_nand_header.m_pages_per_block == -1 && pageoffs == (int)0x80000000 ) + __builtin_trap(); + return s147nand_27_blocks2pages(tblockoffs) + (pageoffs % g_nand_header.m_pages_per_block); +} + +static int dev9_intr_handler(void *unusd) +{ + (void)unusd; + + iWakeupThread(g_thid); + return 1; +} + +int s147nand_15_nandinit(void) +{ + int intrstate; + iop_sema_t semaparam; + USE_IOP_MMIO_HWPORT(); + + DisableIntr(IOP_IRQ_DMA_DEV9, &intrstate); + ReleaseIntrHandler(IOP_IRQ_DMA_DEV9); + // Unofficial: removed unused userdata var + RegisterIntrHandler(IOP_IRQ_DMA_DEV9, 1, dev9_intr_handler, NULL); + EnableIntr(IOP_IRQ_DMA_DEV9); + sceDisableDMAChannel(IOP_DMAC_DEV9); + sceSetDMAPriority(IOP_DMAC_DEV9, 7); + sceEnableDMAChannel(IOP_DMAC_DEV9); + // Unofficial: use uncached mirror + iop_mmio_hwport->ssbus2.ind_B_address = 0xB4000008; + // Unofficial: make semaparam local var + semaparam.initial = 1; + semaparam.max = 1; + semaparam.attr = SA_THPRI; + semaparam.option = 0; + g_sema_id_nand = CreateSema(&semaparam); + if ( g_sema_id_nand >= 0 ) + return 0; + printf("nand_Init: CreateSema error (%d)\n", g_sema_id_nand); + return -1; +} + +s147nand_info_t *s147nand_16_getnandinfo(void) +{ + return &g_nand_info; +} + +int s147nand_17_get_sema(void) +{ + return g_sema_id_nand; +} + +void s147nand_18_enable_nand_watchdog(void) +{ + g_nand_watchdog_enabled = 1; +} + +int s147nand_19_logaddr_read(u16 *tbl, int pageoffs, int bytecnt) +{ + int i; + int pagecnt; + + pagecnt = s147nand_30_bytes2pagesnoeccround(bytecnt); + for ( i = 0; i < pagecnt; i += 1 ) + { + int retres; + + retres = s147nand_20_nand_read_dma( + &tbl[((g_nand_info.m_page_size_noecc >> 2) << 1) * i], pageoffs + i, 0, g_nand_info.m_page_size_noecc); + if ( retres ) + return retres; + } + return 0; +} + +int s147nand_20_nand_read_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int retres; + + WaitSema(g_sema_id_nand); + retres = nand_lowlevel_read_dma(ptr, pageoffs, byteoffs, bytecnt); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_21_nand_read_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int retres; + int state; + + WaitSema(g_sema_id_nand); + CpuSuspendIntr(&state); + retres = nand_lowlevel_read_pio(ptr, pageoffs, byteoffs, bytecnt); + CpuResumeIntr(state); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_22_nand_write_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int retres; + + WaitSema(g_sema_id_nand); + retres = nand_lowlevel_write_dma(ptr, pageoffs, byteoffs, bytecnt); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_23_nand_write_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int retres; + int state; + + WaitSema(g_sema_id_nand); + CpuSuspendIntr(&state); + retres = nand_lowlevel_write_pio(ptr, pageoffs, byteoffs, bytecnt); + CpuResumeIntr(state); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_24_eraseoffset(int pageoffs) +{ + int retres; + int state; + u8 val1; + u8 val2; + + s147nand_21_nand_read_pio( + &val1, + s147nand_27_blocks2pages(s147nand_28_pages2blocks(pageoffs)) + 0, + g_nand_info.m_page_size_noecc, + sizeof(val1)); + s147nand_21_nand_read_pio( + &val2, + s147nand_27_blocks2pages(s147nand_28_pages2blocks(pageoffs)) + 1, + g_nand_info.m_page_size_noecc, + sizeof(val2)); + if ( val1 != 255 || val2 != 255 ) + return -1470020; + WaitSema(g_sema_id_nand); + CpuSuspendIntr(&state); + retres = nand_lowlevel_blockerase(pageoffs); + CpuResumeIntr(state); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_25_nand_blockerase(int pageoffs) +{ + int retres; + int state; + + WaitSema(g_sema_id_nand); + CpuSuspendIntr(&state); + retres = nand_lowlevel_blockerase(pageoffs); + CpuResumeIntr(state); + SignalSema(g_sema_id_nand); + return retres; +} + +int s147nand_26_nand_readid(void *ptr) +{ + int retres; + int state; + + WaitSema(g_sema_id_nand); + CpuSuspendIntr(&state); + retres = nand_lowlevel_readid(ptr); + CpuResumeIntr(state); + SignalSema(g_sema_id_nand); + return retres; +} + +static int nand_lowlevel_read_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int state; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( pageoffs < 0 || pageoffs >= g_nand_info.m_page_count ) + return -1470010; + if ( byteoffs < 0 || byteoffs >= g_nand_info.m_page_size_withecc ) + return -1470010; + if ( bytecnt < 4 || g_nand_info.m_page_size_withecc < byteoffs + bytecnt ) + return -1470010; + CpuSuspendIntr(&state); + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs); + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs & 0xF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = pageoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(pageoffs & 0xFF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (pageoffs & 0xFF0000) >> 16; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x30; + CpuResumeIntr(state); + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + CpuSuspendIntr(&state); + s147_dev9_mem_mmio->m_security_unlock_unlock = 0; + sceSetSliceDMA(IOP_DMAC_DEV9, ptr, bytecnt >> 2, 1, 0); + g_thid = GetThreadId(); + CpuResumeIntr(state); + sceStartDMA(IOP_DMAC_DEV9); + SleepThread(); + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + return 0; +} + +static int nand_lowlevel_read_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int i; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( pageoffs < 0 || pageoffs >= g_nand_info.m_page_count ) + return -1470010; + if ( byteoffs < 0 || byteoffs >= g_nand_info.m_page_size_withecc ) + return -1470010; + if ( bytecnt <= 0 || g_nand_info.m_page_size_withecc < byteoffs + bytecnt ) + return -1470010; + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0; + s147nand_dev9_io_mmio->m_nand_cmd_offs = byteoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs & 0xF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = pageoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(pageoffs & 0xFF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (pageoffs & 0xFF0000) >> 16; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x30; + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + for ( i = 0; i < bytecnt; i += 1 ) + ((u8 *)ptr)[i] = s147nand_dev9_io_mmio->m_nand_outbyte; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + return 0; +} + +static int nand_lowlevel_write_dma(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + int state; + u8 flgtmp; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( pageoffs < 0 || pageoffs >= g_nand_info.m_page_count ) + return -1470010; + if ( byteoffs < 0 || byteoffs >= g_nand_info.m_page_size_withecc ) + return -1470010; + if ( bytecnt < 4 || g_nand_info.m_page_size_withecc < byteoffs + bytecnt ) + return -1470010; + CpuSuspendIntr(&state); + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0xA5; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x80; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs); + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs & 0xF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = pageoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(pageoffs & 0xFF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (pageoffs & 0xFF0000) >> 16; + s147_dev9_mem_mmio->m_security_unlock_unlock = 0; + sceSetSliceDMA(IOP_DMAC_DEV9, ptr, bytecnt >> 2, 1, 1); + g_thid = GetThreadId(); + CpuResumeIntr(state); + sceStartDMA(IOP_DMAC_DEV9); + SleepThread(); + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x10; + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x70; + flgtmp = s147nand_dev9_io_mmio->m_nand_outbyte; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + if ( (flgtmp & 0x80) == 0 ) + return -1470030; + if ( (flgtmp & 1) != 0 ) + return -1470020; + return 0; +} + +static int nand_lowlevel_write_pio(void *ptr, int pageoffs, int byteoffs, int bytecnt) +{ + u8 flgtmp; + int i; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( pageoffs < 0 || pageoffs >= g_nand_info.m_page_count ) + return -1470010; + if ( byteoffs < 0 || byteoffs >= g_nand_info.m_page_size_withecc ) + return -1470010; + if ( bytecnt <= 0 || g_nand_info.m_page_size_withecc < byteoffs + bytecnt ) + return -1470010; + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0xA5; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x80; + s147nand_dev9_io_mmio->m_nand_cmd_offs = byteoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(byteoffs & 0xF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = pageoffs; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(pageoffs & 0xFF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (pageoffs & 0xFF0000) >> 16; + for ( i = 0; i < bytecnt; i += 1 ) + s147nand_dev9_io_mmio->m_nand_outbyte = ((u8 *)ptr)[i]; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x10; + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x70; + flgtmp = s147nand_dev9_io_mmio->m_nand_outbyte; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + if ( (flgtmp & 0x80) == 0 ) + return -1470030; + if ( (flgtmp & 1) != 0 ) + return -1470020; + return 0; +} + +static int nand_lowlevel_blockerase(int pageoffs) +{ + u8 flgtmp; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( pageoffs < 0 || pageoffs >= g_nand_info.m_page_count ) + return -1470010; + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0xA5; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x60; + s147nand_dev9_io_mmio->m_nand_cmd_offs = pageoffs & 0xC0; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (u16)(pageoffs & 0xFF00) >> 8; + s147nand_dev9_io_mmio->m_nand_cmd_offs = (pageoffs & 0xFF0000) >> 16; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0xD0; + while ( (s147nand_dev9_io_mmio->m_nand_waitflag & 1) != 0 ) + ; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x70; + flgtmp = s147nand_dev9_io_mmio->m_nand_outbyte; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + s147nand_dev9_io_mmio->m_nand_write_cmd_unlock = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + if ( (flgtmp & 0x80) == 0 ) + return -1470030; + if ( (flgtmp & 1) != 0 ) + return -1470020; + return 0; +} + +static int nand_lowlevel_readid(void *ptr) +{ + int i; + USE_S147_DEV9_MEM_MMIO(); + USE_S147MAMD_DEV9_IO_MMIO(); + + if ( !ptr ) + return -1470010; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 1; + s147nand_dev9_io_mmio->m_nand_cmd_sel = 0x90; + s147nand_dev9_io_mmio->m_nand_cmd_offs = 0; + for ( i = 0; i < 5; i += 1 ) + ((u8 *)ptr)[i] = s147nand_dev9_io_mmio->m_nand_outbyte; + s147nand_dev9_io_mmio->m_nand_cmd_enable = 0; + if ( g_nand_watchdog_enabled == 1 ) + s147_dev9_mem_mmio->m_watchdog_flag2 = 0; + return 0; +} + +int s147nand_27_blocks2pages(int blocks) +{ + return blocks * g_nand_info.m_pages_per_block; +} + +int s147nand_28_pages2blocks(int pages) +{ + if ( !g_nand_info.m_pages_per_block ) + __builtin_trap(); + if ( g_nand_info.m_pages_per_block == -1 && pages == (int)0x80000000 ) + __builtin_trap(); + return pages / g_nand_info.m_pages_per_block; +} + +int s147nand_29_pages2blockround(int pages) +{ + int blocks; + + if ( !g_nand_info.m_pages_per_block ) + __builtin_trap(); + if ( g_nand_info.m_pages_per_block == -1 && pages == (int)0x80000000 ) + __builtin_trap(); + if ( !g_nand_info.m_pages_per_block ) + __builtin_trap(); + blocks = pages / g_nand_info.m_pages_per_block; + if ( g_nand_info.m_pages_per_block == -1 && pages == (int)0x80000000 ) + __builtin_trap(); + return blocks + ((pages % g_nand_info.m_pages_per_block) ? 1 : 0); +} + +int s147nand_30_bytes2pagesnoeccround(int bytes) +{ + int pages; + + if ( !g_nand_info.m_page_size_noecc ) + __builtin_trap(); + if ( g_nand_info.m_page_size_noecc == -1 && bytes == (int)0x80000000 ) + __builtin_trap(); + if ( !g_nand_info.m_page_size_noecc ) + __builtin_trap(); + pages = bytes / g_nand_info.m_page_size_noecc; + if ( g_nand_info.m_page_size_noecc == -1 && bytes == (int)0x80000000 ) + __builtin_trap(); + return pages + ((bytes % g_nand_info.m_page_size_noecc) ? 1 : 0); +} diff --git a/iop/arcade/s147netb/Makefile b/iop/arcade/s147netb/Makefile new file mode 100644 index 00000000000..9c251f7ed51 --- /dev/null +++ b/iop/arcade/s147netb/Makefile @@ -0,0 +1,24 @@ +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. + +IOP_BIN ?= s147netb.irx + +IOP_IMPORT_INCS += \ + system/ioman \ + system/modload \ + system/sysclib \ + system/sysmem \ + system/loadcore \ + system/threadman + +IOP_OBJS = s147netb.o imports.o + +include $(PS2SDKSRC)/Defs.make +include $(PS2SDKSRC)/iop/Rules.bin.make +include $(PS2SDKSRC)/iop/Rules.make +include $(PS2SDKSRC)/iop/Rules.release diff --git a/iop/arcade/s147netb/README.md b/iop/arcade/s147netb/README.md new file mode 100644 index 00000000000..c22c9e05e18 --- /dev/null +++ b/iop/arcade/s147netb/README.md @@ -0,0 +1,15 @@ +# S147NETB + +This module initializes the network/HTTP functionality of System 147. + +## Configurations + +There are multiple configurations of this library, allowing the choice of +balancing between size, speed, and features. + +* `s147netb` -> The recommended version. + +## How to use this module in your program + +In order to use this module in your program, use `LoadModule` or \ +`LoadModuleBuffer` with no arguments. diff --git a/iop/arcade/s147netb/src/imports.lst b/iop/arcade/s147netb/src/imports.lst new file mode 100644 index 00000000000..84d7e2e5205 --- /dev/null +++ b/iop/arcade/s147netb/src/imports.lst @@ -0,0 +1,22 @@ + +sysmem_IMPORTS_start +I_Kprintf +sysmem_IMPORTS_end + +ioman_IMPORTS_start +I_open +I_close +I_read +ioman_IMPORTS_end + +modload_IMPORTS_start +I_LoadStartModule +modload_IMPORTS_end + +sysclib_IMPORTS_start +I_vsprintf +sysclib_IMPORTS_end + +thbase_IMPORTS_start +I_DelayThread +thbase_IMPORTS_end diff --git a/iop/arcade/s147netb/src/irx_imports.h b/iop/arcade/s147netb/src/irx_imports.h new file mode 100644 index 00000000000..887d5e71667 --- /dev/null +++ b/iop/arcade/s147netb/src/irx_imports.h @@ -0,0 +1,25 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +# +# Defines all IRX imports. +*/ + +#ifndef IOP_IRX_IMPORTS_H +#define IOP_IRX_IMPORTS_H + +#include + +/* Please keep these in alphabetical order! */ +#include +#include +#include +#include +#include + +#endif /* IOP_IRX_IMPORTS_H */ diff --git a/iop/arcade/s147netb/src/s147netb.c b/iop/arcade/s147netb/src/s147netb.c new file mode 100644 index 00000000000..c1cb94364f7 --- /dev/null +++ b/iop/arcade/s147netb/src/s147netb.c @@ -0,0 +1,91 @@ +/* +# _____ ___ ____ ___ ____ +# ____| | ____| | | |____| +# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. +#----------------------------------------------------------------------- +# Copyright ps2dev - http://www.ps2dev.org +# Licenced under Academic Free License version 2.0 +# Review ps2sdk README & LICENSE files for further details. +*/ + +#include "irx_imports.h" +#include +#include + +IRX_ID("S147NETB", 2, 2); +// Text section hash: +// 49d8ea7bd41706df5cfcebac25acdc5e + +int _start(int ac, char **av) +{ + char probebuf; + int fd; + int probe_i; + + (void)ac; + (void)av; + Kprintf("\ns147netb.irx: System147 Network Boot Manager v%d.%d\n", 2, 2); + fd = open("atfile19:usb-probe", O_RDONLY); + if ( fd < 0 ) + { + Kprintf("s147netb.irx: Could not initialize USB memory driver\n"); + return MODULE_NO_RESIDENT_END; + } + for ( probe_i = 5; probe_i > 0; probe_i -= 1 ) + { + read(fd, &probebuf, sizeof(probebuf)); + Kprintf("\ns147netb.irx: === Wait %dsec for USB initialize... (probe=%d) ===\n", probe_i, (u8)probebuf); + if ( probebuf == 1 ) + break; + DelayThread(1000000); + } + close(fd); + if ( !probebuf ) + { + Kprintf("\ns147netb.irx: *** No USB memory ***\n"); + return MODULE_RESIDENT_END; + } + fd = open("atfile10:ifc000.cnf", O_RDONLY); + if ( fd < 0 ) + { + Kprintf("s147netb.irx: Could not find \"%s\"\n", "atfile10:ifc000.cnf"); + return MODULE_RESIDENT_END; + } + close(fd); + Kprintf("s147netb.irx: \"%s\" is found\n", "atfile10:ifc000.cnf"); + fd = open("atfile10:inet.irx", O_RDONLY); + if ( fd < 0 ) + { + Kprintf("s147netb.irx: Could not find \"%s\"\n", "atfile10:inet.irx"); + return MODULE_RESIDENT_END; + } + close(fd); + Kprintf("s147netb.irx: \"%s\" is found\n", "atfile10:inet.irx"); + fd = open("atfile10:an986.irx", O_RDONLY); + if ( fd < 0 ) + { + Kprintf("s147netb.irx: Could not find \"%s\"\n", "atfile10:an986.irx"); + return MODULE_RESIDENT_END; + } + close(fd); + Kprintf("s147netb.irx: \"%s\" is found\n", "atfile10:an986.irx"); + fd = open("atfile10:s147http.irx", O_RDONLY); + if ( fd < 0 ) + { + Kprintf("s147netb.irx: Could not find \"%s\"\n", "atfile10:s147http.irx"); + return MODULE_RESIDENT_END; + } + close(fd); + Kprintf("s147netb.irx: \"%s\" is found\n", "atfile10:s147http.irx"); + Kprintf( + "s147netb.irx: LoadStartModule \"%s\" (%d)\n", "atfile10:inet.irx", LoadStartModule("atfile10:inet.irx", 0, 0, 0)); + Kprintf( + "s147netb.irx: LoadStartModule \"%s\" (%d)\n", + "atfile10:an986.irx", + LoadStartModule("atfile10:an986.irx", 0, 0, 0)); + Kprintf( + "s147netb.irx: LoadStartModule \"%s\" (%d)\n", + "atfile10:s147http.irx", + LoadStartModule("atfile10:s147http.irx", 0, 0, 0)); + return MODULE_RESIDENT_END; +}