clarify the gui
[open-ps2-loader.git] / src / hddsupport.c
blob8948efa2a4de787eeb1b2f651b7b532f05d3c6f5
1 #include "sys/fcntl.h"
2 #include "include/usbld.h"
3 #include "include/lang.h"
4 #include "include/gui.h"
5 #include "include/supportbase.h"
6 #include "include/hddsupport.h"
7 #include "include/util.h"
8 #include "include/themes.h"
9 #include "include/textures.h"
10 #include "include/ioman.h"
11 #include "include/system.h"
13 extern void *hdd_cdvdman_irx;
14 extern int size_hdd_cdvdman_irx;
16 extern void *hdd_pcmcia_cdvdman_irx;
17 extern int size_hdd_pcmcia_cdvdman_irx;
19 extern void *hdd_hdpro_cdvdman_irx;
20 extern int size_hdd_hdpro_cdvdman_irx;
22 extern void *ps2dev9_irx;
23 extern int size_ps2dev9_irx;
25 extern void *ps2atad_irx;
26 extern int size_ps2atad_irx;
28 extern void *hdpro_atad_irx;
29 extern int size_hdpro_atad_irx;
31 extern void *ps2hdd_irx;
32 extern int size_ps2hdd_irx;
34 extern void *ps2fs_irx;
35 extern int size_ps2fs_irx;
37 #ifdef VMC
38 extern void *hdd_mcemu_irx;
39 extern int size_hdd_mcemu_irx;
40 #endif
42 static int hddForceUpdate = 1;
43 static char *hddPrefix = "pfs0:";
44 static int hddGameCount = 0;
45 static hdl_games_list_t* hddGames;
47 const char *oplPart = "hdd0:+OPL";
49 static int hddHDProKitDetected = 0;
51 // forward declaration
52 static item_list_t hddGameList;
54 static void hddInitModules(void) {
56 hddLoadModules();
58 // update Themes
59 char path[255];
60 sprintf(path, "%sTHM", hddPrefix);
61 thmAddElements(path, "/", hddGameList.mode);
63 sprintf(path, "%sCFG", hddPrefix);
64 checkCreateDir(path);
66 #ifdef VMC
67 sprintf(path, "%sVMC", hddPrefix);
68 checkCreateDir(path);
69 #endif
72 // HD Pro Kit is mapping the 1st word in ROM0 seg as a main ATA controller,
73 // The pseudo ATA controller registers are accessed (input/ouput) by writing
74 // an id to the main ATA controller
75 #define HDPROreg_IO8 (*(volatile unsigned char *)0xBFC00000)
76 #define CDVDreg_STATUS (*(volatile unsigned char *)0xBF40200A)
78 static int hddCheckHDProKit(void)
80 int ret = 0;
82 DIntr();
83 ee_kmode_enter();
84 // HD Pro IO start commands sequence
85 HDPROreg_IO8 = 0x72;
86 CDVDreg_STATUS = 0;
87 HDPROreg_IO8 = 0x34;
88 CDVDreg_STATUS = 0;
89 HDPROreg_IO8 = 0x61;
90 CDVDreg_STATUS = 0;
91 u32 res = HDPROreg_IO8;
92 CDVDreg_STATUS = 0;
93 ee_kmode_exit();
94 EIntr();
96 FlushCache(0);
97 FlushCache(2);
99 DIntr();
100 ee_kmode_enter();
102 // check result
103 if ((res & 0xff) == 0xe7) {
104 HDPROreg_IO8 = 0xe3;
105 CDVDreg_STATUS = 0;
106 // HD Pro IO finish commands sequence
107 HDPROreg_IO8 = 0xf3;
108 CDVDreg_STATUS = 0;
109 ret = 1;
111 ee_kmode_exit();
112 EIntr();
114 FlushCache(0);
115 FlushCache(2);
117 if (ret)
118 LOG("hddCheckHDPro() HD Pro Kit detected!\n");
120 return ret;
123 void hddLoadModules(void) {
124 int ret;
125 static char hddarg[] = "-o" "\0" "4" "\0" "-n" "\0" "20";
127 LOG("hddLoadModules()\n");
129 gHddStartup = 4;
131 ret = sysLoadModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx, 0, NULL);
132 if (ret < 0) {
133 gHddStartup = -1;
134 return;
137 gHddStartup = 3;
139 // try to detect HD Pro Kit (not the connected HDD),
140 // if detected it loads the specific ATAD module
141 hddHDProKitDetected = hddCheckHDProKit();
142 if (hddHDProKitDetected)
143 ret = sysLoadModuleBuffer(&hdpro_atad_irx, size_hdpro_atad_irx, 0, NULL);
144 else
145 ret = sysLoadModuleBuffer(&ps2atad_irx, size_ps2atad_irx, 0, NULL);
146 if (ret < 0) {
147 gHddStartup = -1;
148 return;
151 gHddStartup = 2;
153 ret = sysLoadModuleBuffer(&ps2hdd_irx, size_ps2hdd_irx, sizeof(hddarg), hddarg);
154 if (ret < 0) {
155 gHddStartup = -1;
156 return;
159 gHddStartup = 1;
161 ret = sysLoadModuleBuffer(&ps2fs_irx, size_ps2fs_irx, 0, NULL);
162 if (ret < 0) {
163 gHddStartup = -1;
164 return;
167 LOG("hddLoadModules: modules loaded\n");
169 hddSetIdleTimeout(gHDDSpindown * 12); // gHDDSpindown [0..20] -> spindown [0..240] -> seconds [0..1200]
171 ret = fileXioMount(hddPrefix, oplPart, FIO_MT_RDWR);
172 if (ret < 0) {
173 fileXioUmount(hddPrefix);
174 fileXioMount(hddPrefix, oplPart, FIO_MT_RDWR);
177 gHddStartup = 0;
180 void hddInit(void) {
181 LOG("hddInit()\n");
182 hddForceUpdate = 1;
184 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &hddInitModules);
186 hddGameList.enabled = 1;
189 item_list_t* hddGetObject(int initOnly) {
190 if (initOnly && !hddGameList.enabled)
191 return NULL;
192 return &hddGameList;
195 static int hddNeedsUpdate(void) {
196 if (hddForceUpdate) {
197 hddForceUpdate = 0;
198 return 1;
201 return 0;
204 static int hddUpdateGameList(void) {
205 int ret = hddGetHDLGamelist(&hddGames);
206 if (ret != 0)
207 hddGameCount = 0;
208 else
209 hddGameCount = hddGames->count;
210 return hddGameCount;
213 static int hddGetGameCount(void) {
214 return hddGameCount;
217 static void* hddGetGame(int id) {
218 return (void*) &hddGames->games[id];
221 static char* hddGetGameName(int id) {
222 return hddGames->games[id].name;
225 static int hddGetGameNameLength(int id) {
226 return HDL_GAME_NAME_MAX + 1;
229 static char* hddGetGameStartup(int id) {
230 return hddGames->games[id].startup;
233 #ifndef __CHILDPROOF
234 static void hddDeleteGame(int id) {
235 hddDeleteHDLGame(&hddGames->games[id]);
236 hddForceUpdate = 1;
239 static void hddRenameGame(int id, char* newName) {
240 hdl_game_info_t* game = &hddGames->games[id];
241 strcpy(game->name, newName);
242 hddSetHDLGameInfo(&hddGames->games[id]);
243 hddForceUpdate = 1;
245 #endif
247 #ifdef VMC
248 static int hddPrepareMcemu(hdl_game_info_t* game, config_set_t* configSet) {
249 char vmc[2][32];
250 char vmc_path[255];
251 u32 vmc_size;
252 pfs_inode_t pfs_inode;
253 apa_header part_hdr;
254 hdd_vmc_infos_t hdd_vmc_infos;
255 vmc_superblock_t vmc_superblock;
256 int i, j, fd, part_valid = 0, size_mcemu_irx = 0;
258 configGetVMC(configSet, vmc[0], 0);
259 configGetVMC(configSet, vmc[1], 1);
261 if(!vmc[0][0] && !vmc[1][0]) return 0; // skip if both empty
263 // virtual mc informations
264 memset(&hdd_vmc_infos, 0, sizeof(hdd_vmc_infos_t));
266 fileXioUmount(hddPrefix);
267 fd = fileXioOpen(oplPart, 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);
268 if(fd >= 0) {
269 if(fileXioIoctl2(fd, APA_IOCTL2_GETHEADER, NULL, 0, (void*)&part_hdr, sizeof(apa_header)) == sizeof(apa_header)) {
270 if(part_hdr.nsub <= 4) {
271 hdd_vmc_infos.parts[0].start = part_hdr.start;
272 hdd_vmc_infos.parts[0].length = part_hdr.length;
273 LOG("hdd_vmc_infos.parts[0].start : 0x%X\n", hdd_vmc_infos.parts[0].start);
274 LOG("hdd_vmc_infos.parts[0].length : 0x%X\n", hdd_vmc_infos.parts[0].length);
275 for(i = 0; i < part_hdr.nsub; i++) {
276 hdd_vmc_infos.parts[i+1].start = part_hdr.subs[i].start;
277 hdd_vmc_infos.parts[i+1].length = part_hdr.subs[i].length;
278 LOG("hdd_vmc_infos.parts[%d].start : 0x%X\n", i+1, hdd_vmc_infos.parts[i+1].start);
279 LOG("hdd_vmc_infos.parts[%d].length : 0x%X\n", i+1, hdd_vmc_infos.parts[i+1].length);
281 part_valid = 1;
285 fileXioClose(fd);
288 if(!part_valid) return -1;
290 fileXioMount(hddPrefix, oplPart, FIO_MT_RDWR); // if this fails, something is really screwed up
291 for(i=0; i<2; i++) {
292 if(!vmc[i][0]) // skip if empty
293 continue;
295 memset(&vmc_superblock, 0, sizeof(vmc_superblock_t));
296 hdd_vmc_infos.active = 0;
298 snprintf(vmc_path, 255, "%sVMC/%s.bin", hddPrefix, vmc[i]);
300 fd = fileXioOpen(vmc_path, O_RDWR, 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);
302 if (fd >= 0) {
303 size_mcemu_irx = -1;
304 LOG("%s open\n", vmc_path);
306 vmc_size = fileXioLseek(fd, 0, SEEK_END);
307 fileXioLseek(fd, 0, SEEK_SET);
308 fileXioRead(fd, (void*)&vmc_superblock, sizeof(vmc_superblock_t));
309 fileXioLseek(fd, 0, SEEK_SET);
311 LOG("File size : 0x%X\n", vmc_size);
312 LOG("Magic : %s\n", vmc_superblock.magic);
313 LOG("Card type : %d\n", vmc_superblock.mc_type);
315 if(!strncmp(vmc_superblock.magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock.mc_type == 0x2) {
316 hdd_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
317 hdd_vmc_infos.flags |= 0x100;
318 hdd_vmc_infos.specs.page_size = vmc_superblock.page_size;
319 hdd_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
320 hdd_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
322 LOG("hdd_vmc_infos.flags : 0x%X\n", hdd_vmc_infos.flags );
323 LOG("hdd_vmc_infos.specs.page_size : 0x%X\n", hdd_vmc_infos.specs.page_size );
324 LOG("hdd_vmc_infos.specs.block_size : 0x%X\n", hdd_vmc_infos.specs.block_size);
325 LOG("hdd_vmc_infos.specs.card_size : 0x%X\n", hdd_vmc_infos.specs.card_size );
327 if(vmc_size == hdd_vmc_infos.specs.card_size * hdd_vmc_infos.specs.page_size) {
328 // Check vmc inode block chain (write operation can cause damage)
329 if(fileXioIoctl2(fd, PFS_IOCTL2_GET_INODE, NULL, 0, (void*)&pfs_inode, sizeof(pfs_inode_t)) == sizeof(pfs_inode_t)) {
330 if(pfs_inode.number_data <= 11) {
331 for(j = 0; j < pfs_inode.number_data-1; j++) {
332 hdd_vmc_infos.active = 1;
333 hdd_vmc_infos.blocks[j].number = pfs_inode.data[j+1].number;
334 hdd_vmc_infos.blocks[j].subpart = pfs_inode.data[j+1].subpart;
335 hdd_vmc_infos.blocks[j].count = pfs_inode.data[j+1].count;
336 LOG("hdd_vmc_infos.blocks[%d].number : 0x%X\n", j, hdd_vmc_infos.blocks[j].number );
337 LOG("hdd_vmc_infos.blocks[%d].subpart : 0x%X\n", j, hdd_vmc_infos.blocks[j].subpart);
338 LOG("hdd_vmc_infos.blocks[%d].count : 0x%X\n", j, hdd_vmc_infos.blocks[j].count );
340 } // else Vmc file too much fragmented
344 fileXioClose(fd);
346 for (j=0; j<size_hdd_mcemu_irx; j++) {
347 if (((u32*)&hdd_mcemu_irx)[j] == (0xC0DEFAC0 + i)) {
348 if(hdd_vmc_infos.active)
349 size_mcemu_irx = size_hdd_mcemu_irx;
350 memcpy(&((u32*)&hdd_mcemu_irx)[j], &hdd_vmc_infos, sizeof(hdd_vmc_infos_t));
351 break;
355 return size_mcemu_irx;
357 #endif
359 static void hddLaunchGame(int id, config_set_t* configSet) {
360 int i, size_irx = 0;
361 void** irx = NULL;
362 char filename[32];
364 hdl_game_info_t* game = &hddGames->games[id];
366 if (gRememberLastPlayed) {
367 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
368 saveConfig(CONFIG_LAST, 0);
371 char gid[5];
372 configGetDiscIDBinary(configSet, gid);
374 int dmaType = 0, dmaMode = 0, compatMode = 0;
375 configGetInt(configSet, CONFIG_ITEM_DMA, &dmaMode);
376 configGetInt(configSet, CONFIG_ITEM_COMPAT, &compatMode);
377 if(dmaMode < 3)
378 dmaType = 0x20;
379 else {
380 dmaType = 0x40;
381 dmaMode -= 3;
383 hddSetTransferMode(dmaType, dmaMode);
384 hddSetIdleTimeout(gHDDSpindown * 12);
386 if (hddHDProKitDetected) {
387 size_irx = size_hdd_hdpro_cdvdman_irx;
388 irx = &hdd_hdpro_cdvdman_irx;
390 else if (sysPcmciaCheck()) {
391 size_irx = size_hdd_pcmcia_cdvdman_irx;
392 irx = &hdd_pcmcia_cdvdman_irx;
394 else {
395 size_irx = size_hdd_cdvdman_irx;
396 irx = &hdd_cdvdman_irx;
399 for (i=0;i<size_irx;i++){
400 if(!strcmp((const char*)((u32)irx+i),"###### GAMESETTINGS ######")){
401 break;
405 if (compatMode & COMPAT_MODE_2) {
406 u32 alt_read_mode = 1;
407 memcpy((void*)((u32)irx+i+35),&alt_read_mode,1);
409 if (compatMode & COMPAT_MODE_5) {
410 u32 no_dvddl = 1;
411 memcpy((void*)((u32)irx+i+36),&no_dvddl,4);
413 if (compatMode & COMPAT_MODE_4) {
414 u32 no_pss = 1;
415 memcpy((void*)((u32)irx+i+40),&no_pss,4);
418 // patch 48bit flag
419 u8 flag_48bit = hddIs48bit() & 0xff;
420 memcpy((void*)((u32)irx+i+34), &flag_48bit, 1);
422 // patch start_sector
423 memcpy((void*)((u32)irx+i+44), &game->start_sector, 4);
425 for (i=0;i<size_irx;i++){
426 if(!strcmp((const char*)((u32)irx+i),"B00BS")){
427 break;
430 // game id
431 memcpy((void*)((u32)irx+i), &gid, 5);
433 // patches cdvdfsv
434 void *cdvdfsv_irx;
435 int size_cdvdfsv_irx;
437 sysGetCDVDFSV(&cdvdfsv_irx, &size_cdvdfsv_irx);
438 u32 *p = (u32 *)cdvdfsv_irx;
439 for (i = 0; i < (size_cdvdfsv_irx >> 2); i++) {
440 if (*p == 0xC0DEC0DE) {
441 if (compatMode & COMPAT_MODE_7)
442 *p = 1;
443 else
444 *p = 0;
445 break;
447 p++;
450 #ifdef VMC
451 int size_mcemu_irx = hddPrepareMcemu(game, configSet);
452 if (size_mcemu_irx == -1) {
453 if (guiMsgBox(_l(_STR_ERR_VMC_CONTINUE), 1, NULL))
454 size_mcemu_irx = 0;
455 else
456 return;
458 #endif
460 char *altStartup = NULL;
461 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
462 strncpy(filename, altStartup, 32);
463 else
464 sprintf(filename, "%s", game->startup);
465 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call hddCleanUp, so hddGames/game will be freed
466 FlushCache(0);
468 #ifdef VMC
469 sysLaunchLoaderElf(filename, "HDD_MODE", size_irx, irx, size_mcemu_irx, &hdd_mcemu_irx, compatMode, compatMode & COMPAT_MODE_1);
470 #else
471 sysLaunchLoaderElf(filename, "HDD_MODE", size_irx, irx, compatMode, compatMode & COMPAT_MODE_1);
472 #endif
475 static config_set_t* hddGetConfig(int id) {
476 char path[255];
477 hdl_game_info_t* game = &hddGames->games[id];
479 snprintf(path, 255, "%sCFG/%s.cfg", hddPrefix, game->startup);
480 config_set_t* config = configAlloc(0, NULL, path);
481 configRead(config);
483 configSetStr(config, CONFIG_ITEM_NAME, game->name);
484 configSetInt(config, CONFIG_ITEM_SIZE, game->total_size_in_kb >> 10);
485 configSetStr(config, CONFIG_ITEM_FORMAT, "HDL");
486 if (game->disctype == 0x12)
487 configSetStr(config, CONFIG_ITEM_MEDIA, "CD");
488 else
489 configSetStr(config, CONFIG_ITEM_MEDIA, "DVD");
490 configSetStr(config, CONFIG_ITEM_STARTUP, game->startup);
492 return config;
495 static int hddGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
496 char path[255];
497 if (isRelative)
498 sprintf(path, "%s%s/%s_%s", hddPrefix, folder, value, suffix);
499 else
500 sprintf(path, "%s%s_%s", folder, value, suffix);
501 return texDiscoverLoad(resultTex, path, -1, psm);
504 static void hddCleanUp(int exception) {
505 if (hddGameList.enabled) {
506 LOG("hddCleanUp()\n");
508 hddFreeHDLGamelist(hddGames);
510 if ((exception & UNMOUNT_EXCEPTION) == 0)
511 fileXioUmount(hddPrefix);
515 #ifdef VMC
516 static int hddCheckVMC(char* name, int createSize) {
517 return sysCheckVMC(hddPrefix, "/", name, createSize);
519 #endif
521 static item_list_t hddGameList = {
522 HDD_MODE, 0, COMPAT_FULL, 0, MENU_MIN_INACTIVE_FRAMES, "HDD Games", _STR_HDD_GAMES, &hddInit, &hddNeedsUpdate, &hddUpdateGameList,
523 #ifdef __CHILDPROOF
524 &hddGetGameCount, &hddGetGame, &hddGetGameName, &hddGetGameNameLength, &hddGetGameStartup, NULL, NULL,
525 #else
526 &hddGetGameCount, &hddGetGame, &hddGetGameName, &hddGetGameNameLength, &hddGetGameStartup, &hddDeleteGame, &hddRenameGame,
527 #endif
528 #ifdef VMC
529 &hddLaunchGame, &hddGetConfig, &hddGetImage, &hddCleanUp, &hddCheckVMC, HDD_ICON
530 #else
531 &hddLaunchGame, &hddGetConfig, &hddGetImage, &hddCleanUp, HDD_ICON
532 #endif