Big up for Volca ... slowdown the busy icon
[open-ps2-loader.git] / src / system.c
blobfbffca83d9a1141f75c7c895a258ab32ae80671e
1 /*
2 Copyright 2009, Ifcaro
3 Licenced under Academic Free License version 3.0
4 Review OpenUsbLd README & LICENSE files for further details.
5 */
7 #include "include/usbld.h"
8 #include "include/util.h"
9 #include "include/pad.h"
10 #include "include/system.h"
11 #include "include/ioman.h"
12 #ifdef VMC
13 typedef struct {
14 char VMC_filename[1024];
15 int VMC_size_mb;
16 int VMC_blocksize;
17 int VMC_thread_priority;
18 int VMC_card_slot;
19 } createVMCparam_t;
21 extern void *genvmc_irx;
22 extern int size_genvmc_irx;
23 #endif
25 extern void *imgdrv_irx;
26 extern int size_imgdrv_irx;
28 extern void *eesync_irx;
29 extern int size_eesync_irx;
31 extern void *cdvdfsv_irx;
32 extern int size_cdvdfsv_irx;
34 extern void *cddev_irx;
35 extern int size_cddev_irx;
37 extern void *ps2dev9_irx;
38 extern int size_ps2dev9_irx;
40 extern void *smstcpip_irx;
41 extern int size_smstcpip_irx;
43 extern void *ingame_smstcpip_irx;
44 extern int size_ingame_smstcpip_irx;
46 extern void *smsmap_irx;
47 extern int size_smsmap_irx;
49 extern void *udptty_irx;
50 extern int size_udptty_irx;
52 extern void *ioptrap_irx;
53 extern int size_ioptrap_irx;
55 extern void *smbman_irx;
56 extern int size_smbman_irx;
58 extern void *discid_irx;
59 extern int size_discid_irx;
61 extern void *iomanx_irx;
62 extern int size_iomanx_irx;
64 extern void *filexio_irx;
65 extern int size_filexio_irx;
67 extern void *poweroff_irx;
68 extern int size_poweroff_irx;
70 extern void *ps2atad_irx;
71 extern int size_ps2atad_irx;
73 extern void *ps2hdd_irx;
74 extern int size_ps2hdd_irx;
76 extern void *hdldsvr_irx;
77 extern int size_hdldsvr_irx;
79 extern void *eecore_elf;
80 extern int size_eecore_elf;
82 extern void *alt_eecore_elf;
83 extern int size_alt_eecore_elf;
85 extern void *elfldr_elf;
86 extern int size_elfldr_elf;
88 extern void *kpatch_10K_elf;
89 extern int size_kpatch_10K_elf;
91 extern void *smsutils_irx;
92 extern int size_smsutils_irx;
94 extern void *usbd_irx;
95 extern int size_usbd_irx;
97 #define MAX_MODULES 32
98 static void *g_sysLoadedModBuffer[MAX_MODULES];
100 #define ELF_MAGIC 0x464c457f
101 #define ELF_PT_LOAD 1
103 // CDVD Registers
104 #define CDVD_R_SCMD ((volatile u8*)0xBF402016)
105 #define CDVD_R_SDIN ((volatile u8*)0xBF402017)
107 // DEV9 Registers
108 #define DEV9_R_1460 ((volatile u16*)0xBF801460)
109 #define DEV9_R_1464 ((volatile u16*)0xBF801464)
110 #define DEV9_R_1466 ((volatile u16*)0xBF801466)
111 #define DEV9_R_146C ((volatile u16*)0xBF80146C)
112 #define DEV9_R_146E ((volatile u16*)0xBF80146E)
113 #define DEV9_R_1474 ((volatile u16*)0xBF801474)
115 #define ROMSEG0(vaddr) (0xbfc00000 | vaddr) // arghhh! avoid using this macro: some PS2 with modchips badly disabled seems
116 // to not tolerate very well direct BIOS access!!!
117 #define KSEG0(vaddr) (0x80000000 | vaddr)
118 #define JAL(addr) (0x0c000000 | ((addr & 0x03ffffff) >> 2))
120 typedef struct {
121 u8 ident[16]; // struct definition for ELF object header
122 u16 type;
123 u16 machine;
124 u32 version;
125 u32 entry;
126 u32 phoff;
127 u32 shoff;
128 u32 flags;
129 u16 ehsize;
130 u16 phentsize;
131 u16 phnum;
132 u16 shentsize;
133 u16 shnum;
134 u16 shstrndx;
135 } elf_header_t;
137 typedef struct {
138 u32 type; // struct definition for ELF program section header
139 u32 offset;
140 void *vaddr;
141 u32 paddr;
142 u32 filesz;
143 u32 memsz;
144 u32 flags;
145 u32 align;
146 } elf_pheader_t;
148 typedef struct {
149 void *irxaddr;
150 int irxsize;
151 } irxptr_t;
153 typedef struct {
154 char fileName[10];
155 u16 extinfoSize;
156 int fileSize;
157 } romdir_t;
159 int sysLoadModuleBuffer(void *buffer, int size, int argc, char *argv) {
161 int i, id, ret, index = 0;
163 // check we have not reached MAX_MODULES
164 for (i=0; i<MAX_MODULES; i++) {
165 if (g_sysLoadedModBuffer[i] == NULL) {
166 index = i;
167 break;
170 if (i == MAX_MODULES)
171 return -1;
173 // check if the module was already loaded
174 for (i=0; i<MAX_MODULES; i++) {
175 if (g_sysLoadedModBuffer[i] == buffer) {
176 return 0;
180 // load the module
181 id = SifExecModuleBuffer(buffer, size, argc, argv, &ret);
182 if ((id < 0) || (ret))
183 return -2;
185 // add the module to the list
186 g_sysLoadedModBuffer[index] = buffer;
188 return 0;
191 void sysReset(int modload_mask) {
193 SifInitRpc(0);
194 cdInit(CDVD_INIT_NOCHECK);
195 cdInit(CDVD_INIT_EXIT);
197 while(!SifIopReset("rom0:UDNL rom0:EELOADCNF",0));
198 while(!SifIopSync());
200 fioExit();
201 SifExitIopHeap();
202 SifLoadFileExit();
203 SifExitRpc();
204 SifExitCmd();
206 SifInitRpc(0);
207 FlushCache(0);
208 FlushCache(2);
210 // init loadfile & iopheap services
211 SifLoadFileInit();
212 SifInitIopHeap();
214 // apply sbv patches
215 sbv_patch_enable_lmb();
216 sbv_patch_disable_prefix_check();
217 sbv_patch_fioremove();
219 SifLoadModule("rom0:SIO2MAN", 0, NULL);
221 if (modload_mask & SYS_LOAD_MC_MODULES) {
222 SifLoadModule("rom0:MCMAN", 0, NULL);
223 SifLoadModule("rom0:MCSERV", 0, NULL);
225 if (modload_mask & SYS_LOAD_PAD_MODULES) {
226 SifLoadModule("rom0:PADMAN", 0, NULL);
229 // clears modules list
230 memset((void *)&g_sysLoadedModBuffer[0], 0, MAX_MODULES*4);
232 // load modules
233 sysLoadModuleBuffer(&discid_irx, size_discid_irx, 0, NULL);
234 sysLoadModuleBuffer(&iomanx_irx, size_iomanx_irx, 0, NULL);
235 sysLoadModuleBuffer(&filexio_irx, size_filexio_irx, 0, NULL);
236 sysLoadModuleBuffer(&poweroff_irx, size_poweroff_irx, 0, NULL);
237 #ifdef VMC
238 sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL);
239 #endif
241 poweroffInit();
244 void sysPowerOff(void) {
245 u16 dev9_hw_type;
247 DIntr();
248 ee_kmode_enter();
250 // Get dev9 hardware type
251 dev9_hw_type = *DEV9_R_146E & 0xf0;
253 // Shutdown Pcmcia
254 if ( dev9_hw_type == 0x20 )
256 *DEV9_R_146C = 0;
257 *DEV9_R_1474 = 0;
259 // Shutdown Expansion Bay
260 else if ( dev9_hw_type == 0x30 )
262 *DEV9_R_1466 = 1;
263 *DEV9_R_1464 = 0;
264 *DEV9_R_1460 = *DEV9_R_1464;
265 *DEV9_R_146C = *DEV9_R_146C & ~4;
266 *DEV9_R_1460 = *DEV9_R_146C & ~1;
269 //Wait a sec
270 delay(5);
272 // PowerOff PS2
273 *CDVD_R_SDIN = 0;
274 *CDVD_R_SCMD = 0xF;
276 ee_kmode_exit();
277 EIntr();
280 void delay(int count) {
281 int i;
282 int ret;
283 for (i = 0; i < count; i++) {
284 ret = 0x01000000;
285 while(ret--) asm("nop\nnop\nnop\nnop");
289 int sysPS3Detect(void) { //return 0=PS2 1=PS3-HARD 2=PS3-SOFT
290 int i, size = -1;
291 void* buffer = readFile("rom0:XPARAM2", -1, &size);
292 if (buffer) {
293 for (i = 0; i < size; i++)
294 if (!strcmp((const char*) ((u32) buffer + i), "SCPS_110.01")) {
295 free(buffer);
296 return 2;
299 free(buffer);
300 return 1;
302 return 0;
305 int sysSetIPConfig(char* ipconfig) {
306 int ipconfiglen;
307 char str[16];
309 memset(ipconfig, 0, IPCONFIG_MAX_LEN);
310 ipconfiglen = 0;
312 // add ip to g_ipconfig buf
313 sprintf(str, "%d.%d.%d.%d", ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3]);
314 strncpy(&ipconfig[ipconfiglen], str, 15);
315 ipconfiglen += strlen(str) + 1;
317 // add netmask to g_ipconfig buf
318 sprintf(str, "%d.%d.%d.%d", ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3]);
319 strncpy(&ipconfig[ipconfiglen], str, 15);
320 ipconfiglen += strlen(str) + 1;
322 // add gateway to g_ipconfig buf
323 sprintf(str, "%d.%d.%d.%d", ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
324 strncpy(&ipconfig[ipconfiglen], str, 15);
325 ipconfiglen += strlen(str) + 1;
327 return ipconfiglen;
330 static unsigned int crctab[0x400];
332 unsigned int USBA_crc32(char *string) {
333 int crc, table, count, byte;
335 for (table=0; table<256; table++) {
336 crc = table << 24;
338 for (count=8; count>0; count--) {
339 if (crc < 0) crc = crc << 1;
340 else crc = (crc << 1) ^ 0x04C11DB7;
342 crctab[255-table] = crc;
345 do {
346 byte = string[count++];
347 crc = crctab[byte ^ ((crc >> 24) & 0xFF)] ^ ((crc << 8) & 0xFFFFFF00);
348 } while (string[count-1] != 0);
350 return crc;
353 int sysGetDiscID(char *hexDiscID) {
354 cdInit(CDVD_INIT_NOCHECK);
355 LOG("SYSTEM CDVD RPC inited\n");
356 if (cdStatus() == CDVD_STAT_OPEN) // If tray is open, error
357 return -1;
359 while (cdGetDiscType() == CDVD_TYPE_DETECT) {;} // Trick : if tray is open before startup it detects it as closed...
360 if (cdGetDiscType() == CDVD_TYPE_NODISK)
361 return -1;
363 cdDiskReady(0);
364 LOG("SYSTEM Disc drive is ready\n");
365 CdvdDiscType_t cdmode = cdGetDiscType(); // If tray is closed, get disk type
366 if (cdmode == CDVD_TYPE_NODISK)
367 return -1;
369 if ((cdmode != CDVD_TYPE_PS2DVD) && (cdmode != CDVD_TYPE_PS2CD) && (cdmode != CDVD_TYPE_PS2CDDA)) {
370 cdStop();
371 cdSync(0);
372 LOG("SYSTEM Disc stopped, Disc is not ps2 disc!\n");
373 return -2;
376 cdStandby();
377 cdSync(0);
378 LOG("SYSTEM Disc standby\n");
380 int fd = fioOpen("discID:", O_RDONLY);
381 if (fd < 0) {
382 cdStop();
383 cdSync(0);
384 LOG("SYSTEM Disc stopped\n");
385 return -3;
388 unsigned char discID[5];
389 memset(discID, 0, 5);
390 fioRead(fd, discID, 5);
391 fioClose(fd);
393 cdStop();
394 cdSync(0);
395 LOG("SYSTEM Disc stopped\n");
397 // convert to hexadecimal string
398 snprintf(hexDiscID, 15, "%02X %02X %02X %02X %02X", discID[0], discID[1], discID[2], discID[3], discID[4]);
399 LOG("SYSTEM PS2 Disc ID = %s\n", hexDiscID);
401 return 1;
404 int sysPcmciaCheck(void) {
405 int ret;
407 fileXioInit();
408 ret = fileXioDevctl("dev9x0:", 0x4401, NULL, 0, NULL, 0);
410 if (ret == 0) // PCMCIA
411 return 1;
413 return 0; // ExpBay
416 void sysGetCDVDFSV(void **data_irx, int *size_irx)
418 *data_irx = (void *)&cdvdfsv_irx;
419 *size_irx = size_cdvdfsv_irx;
422 void sysExecExit() {
423 __asm__ __volatile__(
424 " li $3, 0x04;"
425 " syscall;"
426 " nop;"
430 static void restoreSyscallHandler(void)
432 __asm__ __volatile__ (
433 "addiu $a0, $zero, 8\n\t"
434 "lui $a1, 0x8000\n\t"
435 "ori $a1, $a1, 0x0280\n\t"
436 "addiu $v1, $zero, 0x0e\n\t"
437 "syscall\n\t"
438 "nop\n\t"
442 #ifdef VMC
443 #define IRX_NUM 11
444 #else
445 #define IRX_NUM 10
446 #endif
448 #ifdef VMC
449 static void sendIrxKernelRAM(int size_cdvdman_irx, void **cdvdman_irx, int size_mcemu_irx, void **mcemu_irx) { // Send IOP modules that core must use to Kernel RAM
450 #else
451 static void sendIrxKernelRAM(int size_cdvdman_irx, void **cdvdman_irx) { // Send IOP modules that core must use to Kernel RAM
452 #endif
454 restoreSyscallHandler();
456 void *irxtab = (void *)0x80033010;
457 void *irxptr = (void *)0x80033100;
458 irxptr_t irxptr_tab[IRX_NUM];
459 void *irxsrc[IRX_NUM];
460 int i, n;
461 u32 irxsize, curIrxSize;
463 n = 0;
464 irxptr_tab[n++].irxsize = size_imgdrv_irx;
465 irxptr_tab[n++].irxsize = size_eesync_irx;
466 irxptr_tab[n++].irxsize = size_cdvdman_irx;
467 irxptr_tab[n++].irxsize = size_cdvdfsv_irx;
468 irxptr_tab[n++].irxsize = size_cddev_irx;
469 irxptr_tab[n++].irxsize = size_usbd_irx;
470 irxptr_tab[n++].irxsize = size_smsmap_irx;
471 irxptr_tab[n++].irxsize = size_udptty_irx;
472 irxptr_tab[n++].irxsize = size_ioptrap_irx;
473 irxptr_tab[n++].irxsize = size_ingame_smstcpip_irx;
474 #ifdef VMC
475 irxptr_tab[n++].irxsize = size_mcemu_irx;
476 #endif
478 n = 0;
479 irxsrc[n++] = (void *)&imgdrv_irx;
480 irxsrc[n++] = (void *)&eesync_irx;
481 irxsrc[n++] = (void *)cdvdman_irx;
482 irxsrc[n++] = (void *)&cdvdfsv_irx;
483 irxsrc[n++] = (void *)&cddev_irx;
484 irxsrc[n++] = (void *)usbd_irx;
485 irxsrc[n++] = (void *)&smsmap_irx;
486 irxsrc[n++] = (void *)&udptty_irx;
487 irxsrc[n++] = (void *)&ioptrap_irx;
488 irxsrc[n++] = (void *)&ingame_smstcpip_irx;
489 #ifdef VMC
490 irxsrc[n++] = (void *)mcemu_irx;
491 #endif
493 irxsize = 0;
495 DIntr();
496 ee_kmode_enter();
498 *(u32 *)0x80033000 = 0x80033010;
500 for (i = 0; i < IRX_NUM; i++) {
501 curIrxSize = irxptr_tab[i].irxsize;
502 if ((((u32)irxptr + curIrxSize) >= 0x80050000) && ((u32)irxptr < 0x80060000))
503 irxptr = (void *)0x80060000;
504 irxptr_tab[i].irxaddr = irxptr;
506 if (curIrxSize > 0) {
507 ee_kmode_exit();
508 EIntr();
509 LOG("SYSTEM IRX address start: %08x end: %08x\n", (int)irxptr_tab[i].irxaddr, (int)(irxptr_tab[i].irxaddr+curIrxSize));
510 DIntr();
511 ee_kmode_enter();
513 memcpy((void *)irxptr_tab[i].irxaddr, (void *)irxsrc[i], curIrxSize);
515 irxptr += curIrxSize;
516 irxsize += curIrxSize;
520 memcpy((void *)irxtab, (void *)&irxptr_tab[0], sizeof(irxptr_tab));
522 ee_kmode_exit();
523 EIntr();
526 #ifdef VMC
527 void sysLaunchLoaderElf(char *filename, char *mode_str, int size_cdvdman_irx, void **cdvdman_irx, int size_mcemu_irx, void **mcemu_irx, int compatflags, int alt_ee_core) {
528 #else
529 void sysLaunchLoaderElf(char *filename, char *mode_str, int size_cdvdman_irx, void **cdvdman_irx, int compatflags, int alt_ee_core) {
530 #endif
531 u8 *boot_elf = NULL;
532 elf_header_t *eh;
533 elf_pheader_t *eph;
534 void *pdata;
535 int i;
536 char *argv[3];
537 char config_str[255];
538 char ipconfig[IPCONFIG_MAX_LEN] __attribute__((aligned(64)));
540 sysSetIPConfig(ipconfig); // TODO only needed for ETH mode, and already done in ethsupport.ethLoadModules
542 if (gExitPath[0] == '\0')
543 strncpy(gExitPath, "Browser", 32);
545 #ifdef VMC
546 LOG("SYSTEM LaunchLoaderElf called with size_mcemu_irx = %d\n", size_mcemu_irx);
547 sendIrxKernelRAM(size_cdvdman_irx, cdvdman_irx, size_mcemu_irx, mcemu_irx);
548 #else
549 sendIrxKernelRAM(size_cdvdman_irx, cdvdman_irx);
550 #endif
552 // NB: LOADER.ELF is embedded
553 if (alt_ee_core)
554 boot_elf = (u8 *)&alt_eecore_elf;
555 else
556 boot_elf = (u8 *)&eecore_elf;
557 eh = (elf_header_t *)boot_elf;
558 if (_lw((u32)&eh->ident) != ELF_MAGIC)
559 while (1);
561 eph = (elf_pheader_t *)(boot_elf + eh->phoff);
563 // Scan through the ELF's program headers and copy them into RAM, then
564 // zero out any non-loaded regions.
565 for (i = 0; i < eh->phnum; i++) {
566 if (eph[i].type != ELF_PT_LOAD)
567 continue;
569 pdata = (void *)(boot_elf + eph[i].offset);
570 memcpy(eph[i].vaddr, pdata, eph[i].filesz);
572 if (eph[i].memsz > eph[i].filesz)
573 memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
576 // Let's go.
577 fioExit();
578 SifInitRpc(0);
579 SifExitRpc();
580 FlushCache(0);
581 FlushCache(2);
583 sprintf(config_str, "%s %d %s %d %d %d.%d.%d.%d %d.%d.%d.%d %d.%d.%d.%d", mode_str, gDisableDebug, gExitPath, gUSBDelay, gHDDSpindown, \
584 ps2_ip[0], ps2_ip[1], ps2_ip[2], ps2_ip[3], \
585 ps2_netmask[0], ps2_netmask[1], ps2_netmask[2], ps2_netmask[3], \
586 ps2_gateway[0], ps2_gateway[1], ps2_gateway[2], ps2_gateway[3]);
588 char cmask[10];
589 snprintf(cmask, 10, "%d", compatflags);
590 argv[0] = config_str;
591 argv[1] = filename;
592 argv[2] = cmask;
594 ExecPS2((void *)eh->entry, 0, 3, argv);
597 int sysExecElf(char *path, int argc, char **argv) {
598 u8 *boot_elf = NULL;
599 elf_header_t *eh;
600 elf_pheader_t *eph;
602 void *pdata;
603 int i;
604 char *elf_argv[1];
606 // NB: ELFLDR.ELF is embedded
607 boot_elf = (u8 *)&elfldr_elf;
608 eh = (elf_header_t *)boot_elf;
609 if (_lw((u32)&eh->ident) != ELF_MAGIC)
610 while (1);
612 eph = (elf_pheader_t *)(boot_elf + eh->phoff);
614 // Scan through the ELF's program headers and copy them into RAM, then
615 // zero out any non-loaded regions.
616 for (i = 0; i < eh->phnum; i++) {
617 if (eph[i].type != ELF_PT_LOAD)
618 continue;
620 pdata = (void *)(boot_elf + eph[i].offset);
621 memcpy(eph[i].vaddr, pdata, eph[i].filesz);
623 if (eph[i].memsz > eph[i].filesz)
624 memset(eph[i].vaddr + eph[i].filesz, 0, eph[i].memsz - eph[i].filesz);
627 // Let's go.
628 fioExit();
629 SifInitRpc(0);
630 SifExitRpc();
631 FlushCache(0);
632 FlushCache(2);
634 elf_argv[0] = path;
635 for (i=0; i<argc; i++)
636 elf_argv[i+1] = argv[i];
638 ExecPS2((void *)eh->entry, 0, argc+1, elf_argv);
640 return 0;
643 void sysApplyKernelPatches(void) {
645 u8 romver[16];
647 int fd = fioOpen("rom0:ROMVER", O_RDONLY);
648 if (fd >= 0) {
649 fioRead(fd, romver, sizeof(romver));
650 fioClose(fd);
652 // Check in rom0 for PS2 with Protokernel
653 if ((romver[0] == '0')
654 && (romver[1] == '1')
655 && (romver[2] == '0')
656 && (romver[9] == '0')) {
658 sbv_patch_protokernel();
663 int sysCheckMC(void) {
664 int dummy, ret;
666 mcGetInfo(0, 0, &dummy, &dummy, &dummy);
667 mcSync(0, NULL, &ret);
669 if( -1 == ret || 0 == ret) return 0;
671 mcGetInfo(1, 0, &dummy, &dummy, &dummy);
672 mcSync(0, NULL, &ret);
674 if( -1 == ret || 0 == ret ) return 1;
676 return -11;
679 #ifdef VMC
680 // createSize == -1 : delete, createSize == 0 : probing, createSize > 0 : creation
681 int sysCheckVMC(const char* prefix, const char* sep, char* name, int createSize, vmc_superblock_t* vmc_superblock) {
682 int size = -1;
683 char path[255];
684 snprintf(path, 255, "%sVMC%s%s.bin", prefix, sep, name);
686 if (createSize == -1)
687 fileXioRemove(path);
688 else {
689 int fd = fileXioOpen(path, O_RDONLY, FIO_S_IRUSR | FIO_S_IWUSR | FIO_S_IXUSR | FIO_S_IRGRP | FIO_S_IWGRP | FIO_S_IXGRP | FIO_S_IROTH | FIO_S_IWOTH | FIO_S_IXOTH);
690 if (fd >= 0) {
691 size = fileXioLseek(fd, 0, SEEK_END);
693 if (vmc_superblock) {
694 memset(vmc_superblock, 0, sizeof(vmc_superblock_t));
695 fileXioLseek(fd, 0, SEEK_SET);
696 fileXioRead(fd, (void*)vmc_superblock, sizeof(vmc_superblock_t));
698 LOG("SYSTEM File size : 0x%X\n", size);
699 LOG("SYSTEM Magic : %s\n", vmc_superblock->magic);
700 LOG("SYSTEM Card type : %d\n", vmc_superblock->mc_type);
701 LOG("SYSTEM Flags : 0x%X\n", (vmc_superblock->mc_flag & 0xFF) | 0x100);
702 LOG("SYSTEM Page_size : 0x%X\n", vmc_superblock->page_size);
703 LOG("SYSTEM Block_size : 0x%X\n", vmc_superblock->pages_per_block);
704 LOG("SYSTEM Card_size : 0x%X\n", vmc_superblock->pages_per_cluster * vmc_superblock->clusters_per_card);
706 if(!strncmp(vmc_superblock->magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock->mc_type == 0x2
707 && size == vmc_superblock->pages_per_cluster * vmc_superblock->clusters_per_card * vmc_superblock->page_size) {
708 LOG("SYSTEM VMC file structure valid: %s\n", path);
709 } else
710 size = 0;
713 if (size % 1048576) // invalid size, should be a an integer (8, 16, 32, 64, ...)
714 size = 0;
715 else
716 size /= 1048576;
718 fileXioClose(fd);
720 if (createSize && (createSize != size))
721 fileXioRemove(path);
724 if (createSize && (createSize != size)) {
725 createVMCparam_t createParam;
726 strcpy(createParam.VMC_filename, path);
727 createParam.VMC_size_mb = createSize;
728 createParam.VMC_blocksize = 16;
729 createParam.VMC_thread_priority = 0x0f;
730 createParam.VMC_card_slot = -1;
731 fileXioDevctl("genvmc:", 0xC0DE0001, (void*) &createParam, sizeof(createParam), NULL, 0);
734 return size;
736 #endif