Added hidden options to be able to define your own device delay before loading ART...
[open-ps2-loader.git] / src / hddsupport.c
blobd8c2aff62dd03315633bc30e5774eed31cf596fb
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("HDDSUPPORT 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("HDDSUPPORT LoadModules\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("HDDSUPPORT 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("HDDSUPPORT Init\n");
182 hddForceUpdate = 1;
183 configGetInt(configGetByType(CONFIG_OPL), "hdd_frames_delay", &hddGameList.delay);
184 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &hddInitModules);
185 hddGameList.enabled = 1;
188 item_list_t* hddGetObject(int initOnly) {
189 if (initOnly && !hddGameList.enabled)
190 return NULL;
191 return &hddGameList;
194 static int hddNeedsUpdate(void) {
195 if (hddForceUpdate) {
196 hddForceUpdate = 0;
197 return 1;
200 return 0;
203 static int hddUpdateGameList(void) {
204 int ret = hddGetHDLGamelist(&hddGames);
205 if (ret != 0)
206 hddGameCount = 0;
207 else
208 hddGameCount = hddGames->count;
209 return hddGameCount;
212 static int hddGetGameCount(void) {
213 return hddGameCount;
216 static void* hddGetGame(int id) {
217 return (void*) &hddGames->games[id];
220 static char* hddGetGameName(int id) {
221 return hddGames->games[id].name;
224 static int hddGetGameNameLength(int id) {
225 return HDL_GAME_NAME_MAX + 1;
228 static char* hddGetGameStartup(int id) {
229 return hddGames->games[id].startup;
232 #ifndef __CHILDPROOF
233 static void hddDeleteGame(int id) {
234 hddDeleteHDLGame(&hddGames->games[id]);
235 hddForceUpdate = 1;
238 static void hddRenameGame(int id, char* newName) {
239 hdl_game_info_t* game = &hddGames->games[id];
240 strcpy(game->name, newName);
241 hddSetHDLGameInfo(&hddGames->games[id]);
242 hddForceUpdate = 1;
244 #endif
246 static void hddLaunchGame(int id, config_set_t* configSet) {
247 int i, size_irx = 0;
248 void** irx = NULL;
249 char filename[32];
250 hdl_game_info_t* game = &hddGames->games[id];
252 #ifdef VMC
253 apa_header part_hdr;
254 char vmc_name[2][32];
255 int fd, part_valid = 0, size_mcemu_irx = 0;
256 hdd_vmc_infos_t hdd_vmc_infos;
257 memset(&hdd_vmc_infos, 0, sizeof(hdd_vmc_infos_t));
259 configGetVMC(configSet, vmc_name[0], 0);
260 configGetVMC(configSet, vmc_name[1], 1);
262 if(vmc_name[0][0] || vmc_name[1][0]) {
263 fileXioUmount(hddPrefix);
264 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);
265 if (fd >= 0) {
266 if (fileXioIoctl2(fd, APA_IOCTL2_GETHEADER, NULL, 0, (void*)&part_hdr, sizeof(apa_header)) == sizeof(apa_header)) {
267 if (part_hdr.nsub <= 4) {
268 hdd_vmc_infos.parts[0].start = part_hdr.start;
269 hdd_vmc_infos.parts[0].length = part_hdr.length;
270 LOG("HDDSUPPORT hdd_vmc_infos.parts[0].start : 0x%X\n", hdd_vmc_infos.parts[0].start);
271 LOG("HDDSUPPORT hdd_vmc_infos.parts[0].length : 0x%X\n", hdd_vmc_infos.parts[0].length);
272 for (i = 0; i < part_hdr.nsub; i++) {
273 hdd_vmc_infos.parts[i+1].start = part_hdr.subs[i].start;
274 hdd_vmc_infos.parts[i+1].length = part_hdr.subs[i].length;
275 LOG("HDDSUPPORT hdd_vmc_infos.parts[%d].start : 0x%X\n", i+1, hdd_vmc_infos.parts[i+1].start);
276 LOG("HDDSUPPORT hdd_vmc_infos.parts[%d].length : 0x%X\n", i+1, hdd_vmc_infos.parts[i+1].length);
278 part_valid = 1;
282 fileXioClose(fd);
284 fileXioMount(hddPrefix, oplPart, FIO_MT_RDWR); // if this fails, something is really screwed up
287 if (part_valid) {
288 char vmc_path[255];
289 int vmc_id, have_error = 0;
290 vmc_superblock_t vmc_superblock;
291 pfs_inode_t pfs_inode;
293 for (vmc_id = 0; vmc_id < 2; vmc_id++) {
294 if (vmc_name[vmc_id][0]) {
295 have_error = 1;
296 hdd_vmc_infos.active = 0;
297 if (sysCheckVMC(hddPrefix, "/", vmc_name[vmc_id], 0, &vmc_superblock) > 0) {
298 hdd_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
299 hdd_vmc_infos.flags |= 0x100;
300 hdd_vmc_infos.specs.page_size = vmc_superblock.page_size;
301 hdd_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
302 hdd_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
304 // Check vmc inode block chain (write operation can cause damage)
305 snprintf(vmc_path, 255, "%sVMC/%s.bin", hddPrefix, vmc_name[vmc_id]);
306 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);
307 if (fileXioIoctl2(fd, PFS_IOCTL2_GET_INODE, NULL, 0, (void*)&pfs_inode, sizeof(pfs_inode_t)) == sizeof(pfs_inode_t)) {
308 if (pfs_inode.number_data <= 11) {
309 have_error = 0;
310 hdd_vmc_infos.active = 1;
311 for (i = 0; i < pfs_inode.number_data - 1; i++) {
312 hdd_vmc_infos.blocks[i].number = pfs_inode.data[i+1].number;
313 hdd_vmc_infos.blocks[i].subpart = pfs_inode.data[i+1].subpart;
314 hdd_vmc_infos.blocks[i].count = pfs_inode.data[i+1].count;
315 LOG("HDDSUPPORT hdd_vmc_infos.blocks[%d].number : 0x%X\n", i, hdd_vmc_infos.blocks[i].number);
316 LOG("HDDSUPPORT hdd_vmc_infos.blocks[%d].subpart : 0x%X\n", i, hdd_vmc_infos.blocks[i].subpart);
317 LOG("HDDSUPPORT hdd_vmc_infos.blocks[%d].count : 0x%X\n", i, hdd_vmc_infos.blocks[i].count);
319 } // else Vmc file too much fragmented
321 fileXioClose(fd);
325 if (have_error) {
326 char error[255];
327 snprintf(error, 255, _l(_STR_ERR_VMC_CONTINUE), vmc_name[vmc_id], (vmc_id + 1));
328 if (!guiMsgBox(error, 1, NULL))
329 return;
332 for (i = 0; i < size_hdd_mcemu_irx; i++) {
333 if (((u32*)&hdd_mcemu_irx)[i] == (0xC0DEFAC0 + vmc_id)) {
334 if (hdd_vmc_infos.active)
335 size_mcemu_irx = size_hdd_mcemu_irx;
336 memcpy(&((u32*)&hdd_mcemu_irx)[i], &hdd_vmc_infos, sizeof(hdd_vmc_infos_t));
337 break;
342 #endif
344 if (gRememberLastPlayed) {
345 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
346 saveConfig(CONFIG_LAST, 0);
349 char gid[5];
350 configGetDiscIDBinary(configSet, gid);
352 int dmaType = 0, dmaMode = 0, compatMode = 0;
353 configGetInt(configSet, CONFIG_ITEM_COMPAT, &compatMode);
354 configGetInt(configSet, CONFIG_ITEM_DMA, &dmaMode);
355 if(dmaMode < 3)
356 dmaType = 0x20;
357 else {
358 dmaType = 0x40;
359 dmaMode -= 3;
361 hddSetTransferMode(dmaType, dmaMode);
362 hddSetIdleTimeout(gHDDSpindown * 12);
364 if (hddHDProKitDetected) {
365 size_irx = size_hdd_hdpro_cdvdman_irx;
366 irx = &hdd_hdpro_cdvdman_irx;
368 else if (sysPcmciaCheck()) {
369 size_irx = size_hdd_pcmcia_cdvdman_irx;
370 irx = &hdd_pcmcia_cdvdman_irx;
372 else {
373 size_irx = size_hdd_cdvdman_irx;
374 irx = &hdd_cdvdman_irx;
377 for (i = 0; i < size_irx; i++) {
378 if(!strcmp((const char*)((u32)irx + i), "###### GAMESETTINGS ######")) {
379 break;
383 // patch 48bit flag
384 u8 flag_48bit = hddIs48bit() & 0xff;
385 memcpy((void*)((u32)irx + i + 34), &flag_48bit, 1);
387 if (compatMode & COMPAT_MODE_2) {
388 u32 alt_read_mode = 1;
389 memcpy((void*)((u32)irx + i + 35), &alt_read_mode, 1);
392 if (compatMode & COMPAT_MODE_5) {
393 u32 no_dvddl = 1;
394 memcpy((void*)((u32)irx + i + 36), &no_dvddl, 2);
397 if (compatMode & COMPAT_MODE_4) {
398 u32 no_pss = 1;
399 memcpy((void*)((u32)irx + i + 38), &no_pss, 2);
402 // patch cdvdman timer
403 int timer = 0;
404 if (configGetInt(configSet, CONFIG_ITEM_CDVDMAN_TIMER, &timer)) {
405 u32 cdvdmanTimer = timer * 250;
406 memcpy((void*)((u32)irx + i + 40), &cdvdmanTimer, 4);
409 // patch start_sector
410 memcpy((void*)((u32)irx + i + 44), &game->start_sector, 4);
412 for (i=0;i<size_irx;i++) {
413 if(!strcmp((const char*)((u32)irx + i), "B00BS")) {
414 break;
417 // game id
418 memcpy((void*)((u32)irx + i), &gid, 5);
420 // patches cdvdfsv
421 /*void *cdvdfsv_irx;
422 int size_cdvdfsv_irx;
424 sysGetCDVDFSV(&cdvdfsv_irx, &size_cdvdfsv_irx);
425 u32 *p = (u32 *)cdvdfsv_irx;
426 for (i = 0; i < (size_cdvdfsv_irx >> 2); i++) {
427 if (*p == 0xC0DEC0DE) {
428 if (compatMode & COMPAT_MODE_7)
429 *p = 1;
430 else
431 *p = 0;
432 break;
434 p++;
437 char *altStartup = NULL;
438 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
439 strncpy(filename, altStartup, 32);
440 else
441 sprintf(filename, "%s", game->startup);
442 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call hddCleanUp, so hddGames/game will be freed
443 FlushCache(0);
445 #ifdef VMC
446 sysLaunchLoaderElf(filename, "HDD_MODE", size_irx, irx, size_mcemu_irx, &hdd_mcemu_irx, compatMode, compatMode & COMPAT_MODE_1);
447 #else
448 sysLaunchLoaderElf(filename, "HDD_MODE", size_irx, irx, compatMode, compatMode & COMPAT_MODE_1);
449 #endif
452 static config_set_t* hddGetConfig(int id) {
453 char path[255];
454 hdl_game_info_t* game = &hddGames->games[id];
456 snprintf(path, 255, "%sCFG/%s.cfg", hddPrefix, game->startup);
457 config_set_t* config = configAlloc(0, NULL, path);
458 configRead(config);
460 configSetStr(config, CONFIG_ITEM_NAME, game->name);
461 configSetInt(config, CONFIG_ITEM_SIZE, game->total_size_in_kb >> 10);
462 configSetStr(config, CONFIG_ITEM_FORMAT, "HDL");
463 if (game->disctype == 0x12)
464 configSetStr(config, CONFIG_ITEM_MEDIA, "CD");
465 else
466 configSetStr(config, CONFIG_ITEM_MEDIA, "DVD");
467 configSetStr(config, CONFIG_ITEM_STARTUP, game->startup);
469 return config;
472 static int hddGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
473 char path[255];
474 if (isRelative)
475 sprintf(path, "%s%s/%s_%s", hddPrefix, folder, value, suffix);
476 else
477 sprintf(path, "%s%s_%s", folder, value, suffix);
478 return texDiscoverLoad(resultTex, path, -1, psm);
481 static void hddCleanUp(int exception) {
482 if (hddGameList.enabled) {
483 LOG("HDDSUPPORT CleanUp\n");
485 hddFreeHDLGamelist(hddGames);
487 if ((exception & UNMOUNT_EXCEPTION) == 0)
488 fileXioUmount(hddPrefix);
492 #ifdef VMC
493 static int hddCheckVMC(char* name, int createSize) {
494 return sysCheckVMC(hddPrefix, "/", name, createSize, NULL);
496 #endif
498 static item_list_t hddGameList = {
499 HDD_MODE, 0, COMPAT_FULL, 0, MENU_MIN_INACTIVE_FRAMES, "HDD Games", _STR_HDD_GAMES, &hddInit, &hddNeedsUpdate, &hddUpdateGameList,
500 #ifdef __CHILDPROOF
501 &hddGetGameCount, &hddGetGame, &hddGetGameName, &hddGetGameNameLength, &hddGetGameStartup, NULL, NULL,
502 #else
503 &hddGetGameCount, &hddGetGame, &hddGetGameName, &hddGetGameNameLength, &hddGetGameStartup, &hddDeleteGame, &hddRenameGame,
504 #endif
505 #ifdef VMC
506 &hddLaunchGame, &hddGetConfig, &hddGetImage, &hddCleanUp, &hddCheckVMC, HDD_ICON
507 #else
508 &hddLaunchGame, &hddGetConfig, &hddGetImage, &hddCleanUp, HDD_ICON
509 #endif