automatically create the CFG folder
[open-ps2-loader.git] / src / usbsupport.c
blobc844e39ea997dfe9732166a1c23b7a620c3306a8
1 #include "include/usbld.h"
2 #include "include/lang.h"
3 #include "include/gui.h"
4 #include "include/supportbase.h"
5 #include "include/usbsupport.h"
6 #include "include/util.h"
7 #include "include/themes.h"
8 #include "include/textures.h"
9 #include "include/ioman.h"
10 #include "include/system.h"
12 extern void *usb_cdvdman_irx;
13 extern int size_usb_cdvdman_irx;
15 extern void *usb_4Ksectors_cdvdman_irx;
16 extern int size_usb_4Ksectors_cdvdman_irx;
18 extern void *usbd_ps2_irx;
19 extern int size_usbd_ps2_irx;
21 extern void *usbd_ps3_irx;
22 extern int size_usbd_ps3_irx;
24 extern void *usbhdfsd_irx;
25 extern int size_usbhdfsd_irx;
27 #ifdef VMC
28 extern void *usb_mcemu_irx;
29 extern int size_usb_mcemu_irx;
30 #endif
32 void *usbd_irx;
33 int size_usbd_irx;
35 static char usbPrefix[40];
36 static int usbULSizePrev = -2;
37 static unsigned char usbModifiedCDPrev[8];
38 static unsigned char usbModifiedDVDPrev[8];
39 static int usbGameCount = 0;
40 static base_game_info_t *usbGames;
42 // forward declaration
43 static item_list_t usbGameList;
45 int usbFindPartition(char *target, char *name) {
46 int i, fd;
47 char path[255];
49 for(i=0; i<5; i++) {
50 if (gUSBPrefix[0] != '\0')
51 sprintf(path, "mass%d:%s/%s", i, gUSBPrefix, name);
52 else
53 sprintf(path, "mass%d:%s", i, name);
54 fd = fioOpen(path, O_RDONLY);
56 if(fd >= 0) {
57 if (gUSBPrefix[0] != '\0')
58 sprintf(target, "mass%d:%s/", i, gUSBPrefix);
59 else
60 sprintf(target, "mass%d:", i);
61 fioClose(fd);
62 return 1;
66 // default to first partition (for themes, ...)
67 if (gUSBPrefix[0] != '\0')
68 sprintf(target, "mass0:%s/", gUSBPrefix);
69 else
70 sprintf(target, "mass0:");
71 return 0;
74 static void usbInitModules(void) {
75 usbLoadModules();
77 // update Themes
78 usbFindPartition(usbPrefix, "ul.cfg");
79 char path[255];
80 sprintf(path, "%sTHM", usbPrefix);
81 thmAddElements(path, "/", usbGameList.mode);
83 sprintf(path, "%sCFG", usbPrefix);
84 checkCreateDir(path);
86 #ifdef VMC
87 sprintf(path, "%sVMC", usbPrefix);
88 checkCreateDir(path);
89 #endif
92 void usbLoadModules(void) {
93 LOG("usbLoadModules()\n");
94 //first it search for custom usbd in MC?
95 usbd_irx = readFile("mc?:BEDATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
96 if (!usbd_irx) {
97 usbd_irx = readFile("mc?:BADATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
98 if (!usbd_irx) {
99 usbd_irx = readFile("mc?:BIDATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
100 if (!usbd_irx) { // If don't exist it uses embedded
101 if (sysPS3Detect() == 0) {
102 usbd_irx = (void *) &usbd_ps2_irx;
103 size_usbd_irx = size_usbd_ps2_irx;
104 } else {
105 usbd_irx = (void *) &usbd_ps3_irx;
106 size_usbd_irx = size_usbd_ps3_irx;
112 sysLoadModuleBuffer(usbd_irx, size_usbd_irx, 0, NULL);
113 sysLoadModuleBuffer(&usbhdfsd_irx, size_usbhdfsd_irx, 0, NULL);
115 delay(gUSBDelay);
117 LOG("usbLoadModules: modules loaded\n");
120 void usbInit(void) {
121 LOG("usbInit()\n");
122 usbULSizePrev = -2;
123 memset(usbModifiedCDPrev, 0, 8);
124 memset(usbModifiedDVDPrev, 0, 8);
125 usbGameCount = 0;
126 usbGames = NULL;
128 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &usbInitModules);
130 usbGameList.enabled = 1;
133 item_list_t* usbGetObject(int initOnly) {
134 if (initOnly && !usbGameList.enabled)
135 return NULL;
136 return &usbGameList;
139 static int usbNeedsUpdate(void) {
140 int result = 0;
141 fio_stat_t stat;
142 char path[255];
144 usbFindPartition(usbPrefix, "ul.cfg");
146 sprintf(path, "%sCD", usbPrefix);
147 if (fioGetstat(path, &stat) != 0)
148 memset(stat.mtime, 0, 8);
149 if (memcmp(usbModifiedCDPrev, stat.mtime, 8)) {
150 memcpy(usbModifiedCDPrev, stat.mtime, 8);
151 result = 1;
154 sprintf(path, "%sDVD", usbPrefix);
155 if (fioGetstat(path, &stat) != 0)
156 memset(stat.mtime, 0, 8);
157 if (memcmp(usbModifiedDVDPrev, stat.mtime, 8)) {
158 memcpy(usbModifiedDVDPrev, stat.mtime, 8);
159 result = 1;
162 if (!sbIsSameSize(usbPrefix, usbULSizePrev))
163 result = 1;
165 return result;
168 static int usbUpdateGameList(void) {
169 sbReadList(&usbGames, usbPrefix, &usbULSizePrev, &usbGameCount);
170 return usbGameCount;
173 static int usbGetGameCount(void) {
174 return usbGameCount;
177 static void* usbGetGame(int id) {
178 return (void*) &usbGames[id];
181 static char* usbGetGameName(int id) {
182 return usbGames[id].name;
185 static int usbGetGameNameLength(int id) {
186 if (usbGames[id].isISO)
187 return ISO_GAME_NAME_MAX + 1;
188 else
189 return UL_GAME_NAME_MAX + 1;
192 static char* usbGetGameStartup(int id) {
193 return usbGames[id].startup;
196 #ifndef __CHILDPROOF
197 static void usbDeleteGame(int id) {
198 sbDelete(&usbGames, usbPrefix, "/", usbGameCount, id);
199 usbULSizePrev = -2;
202 /*static void usbRenameGame(int id, char* newName) {
203 // TODO when/if Jimmi add rename functionnality to usbhdfs, then we should use the above method
204 //sbRename(&usbGames, usbPrefix, "/", usbGameCount, id, newName);
205 usbULSizePrev = -2;
207 #endif
209 #ifdef VMC
210 static int usbPrepareMcemu(base_game_info_t* game, config_set_t* configSet) {
211 char vmc[2][32];
212 char vmc_path[255];
213 u32 vmc_size;
214 int i, j, fd, size_mcemu_irx = 0;
215 usb_vmc_infos_t usb_vmc_infos;
216 vmc_superblock_t vmc_superblock;
218 configGetVMC(configSet, vmc[0], 0);
219 configGetVMC(configSet, vmc[1], 1);
221 for(i=0; i<2; i++) {
222 if(!vmc[i][0]) // skip if empty
223 continue;
225 memset(&usb_vmc_infos, 0, sizeof(usb_vmc_infos_t));
226 memset(&vmc_superblock, 0, sizeof(vmc_superblock_t));
228 sprintf(vmc_path, "%sVMC/%s.bin", usbPrefix, vmc[i]);
230 fd = fioOpen(vmc_path, O_RDWR);
231 if (fd >= 0) {
232 size_mcemu_irx = -1;
233 LOG("%s open\n", vmc_path);
235 vmc_size = fioLseek(fd, 0, SEEK_END);
236 fioLseek(fd, 0, SEEK_SET);
237 fioRead(fd, (void*)&vmc_superblock, sizeof(vmc_superblock_t));
239 LOG("File size : 0x%X\n", vmc_size);
240 LOG("Magic : %s\n", vmc_superblock.magic);
241 LOG("Card type : %d\n", vmc_superblock.mc_type);
243 if(!strncmp(vmc_superblock.magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock.mc_type == 0x2) {
244 usb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
245 usb_vmc_infos.flags |= 0x100;
246 usb_vmc_infos.specs.page_size = vmc_superblock.page_size;
247 usb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
248 usb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
250 LOG("flags : 0x%X\n", usb_vmc_infos.flags );
251 LOG("specs.page_size : 0x%X\n", usb_vmc_infos.specs.page_size );
252 LOG("specs.block_size : 0x%X\n", usb_vmc_infos.specs.block_size);
253 LOG("specs.card_size : 0x%X\n", usb_vmc_infos.specs.card_size );
255 if(vmc_size == usb_vmc_infos.specs.card_size * usb_vmc_infos.specs.page_size) {
256 int fd1 = fioDopen(usbPrefix);
258 if (fd1 >= 0) {
259 sprintf(vmc_path, "%s/VMC/%s.bin", gUSBPrefix, vmc[i]);
260 // Check vmc cluster chain (write operation can cause dammage)
261 if(fioIoctl(fd1, 0xCAFEC0DE, vmc_path)) {
262 LOG("Cluster Chain OK\n");
263 if((j = fioIoctl(fd1, 0xBEEFC0DE, vmc_path)) != 0) {
264 usb_vmc_infos.active = 1;
265 usb_vmc_infos.start_sector = j;
266 LOG("Start Sector: 0x%X\n", usb_vmc_infos.start_sector);
268 } // else Vmc file fragmented
270 fioDclose(fd1);
273 fioClose(fd);
275 for (j=0; j<size_usb_mcemu_irx; j++) {
276 if (((u32*)&usb_mcemu_irx)[j] == (0xC0DEFAC0 + i)) {
277 if(usb_vmc_infos.active)
278 size_mcemu_irx = size_usb_mcemu_irx;
279 memcpy(&((u32*)&usb_mcemu_irx)[j], &usb_vmc_infos, sizeof(usb_vmc_infos_t));
280 break;
284 return size_mcemu_irx;
286 #endif
288 static void usbLaunchGame(int id, config_set_t* configSet) {
289 int fd, r, index, i, compatmask;
290 char isoname[32], partname[255], filename[32];
291 base_game_info_t* game = &usbGames[id];
293 fd = fioDopen(usbPrefix);
294 if (fd < 0) {
295 guiMsgBox(_l(_STR_ERR_FILE_INVALID), 0, NULL);
296 return;
299 if (game->isISO)
300 sprintf(partname, "%s/%s/%s.%s.iso", gUSBPrefix, (game->media == 0x12) ? "CD" : "DVD", game->startup, game->name);
301 else
302 sprintf(partname, "%s/%s.00", gUSBPrefix, isoname);
303 r = fioIoctl(fd, 0xDEADC0DE, partname);
304 LOG("mass storage device sectorsize = %d\n", r);
306 void *irx = &usb_cdvdman_irx;
307 int irx_size = size_usb_cdvdman_irx;
308 if (r == 4096) {
309 irx = &usb_4Ksectors_cdvdman_irx;
310 irx_size = size_usb_4Ksectors_cdvdman_irx;
313 compatmask = sbPrepare(game, configSet, isoname, irx_size, irx, &index);
315 if (gCheckUSBFragmentation)
316 for (i = 0; i < game->parts; i++) {
317 if (!game->isISO)
318 sprintf(partname, "%s/%s.%02x", gUSBPrefix, isoname, i);
320 if (fioIoctl(fd, 0xCAFEC0DE, partname) == 0) {
321 fioDclose(fd);
322 guiMsgBox(_l(_STR_ERR_FRAGMENTED), 0, NULL);
323 return;
327 if (gRememberLastPlayed) {
328 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
329 saveConfig(CONFIG_LAST, 0);
332 int offset = 44;
333 for (i = 0; i < game->parts; i++) {
334 if (!game->isISO)
335 sprintf(partname, "%s/%s.%02x", gUSBPrefix, isoname, i);
337 r = fioIoctl(fd, 0xBEEFC0DE, partname);
338 memcpy((void*)((u32)&usb_cdvdman_irx + index + offset), &r, 4);
339 offset += 4;
342 fioDclose(fd);
344 #ifdef VMC
345 int size_mcemu_irx = usbPrepareMcemu(game, configSet);
346 if (size_mcemu_irx == -1) {
347 if (guiMsgBox(_l(_STR_ERR_VMC_CONTINUE), 1, NULL))
348 size_mcemu_irx = 0;
349 else
350 return;
352 #endif
354 char *altStartup = NULL;
355 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
356 strncpy(filename, altStartup, 32);
357 else
358 sprintf(filename, "%s", game->startup);
359 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call usbCleanUp, so usbGames/game will be freed
360 FlushCache(0);
362 #ifdef VMC
363 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, size_mcemu_irx, &usb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
364 #else
365 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, compatmask, compatmask & COMPAT_MODE_1);
366 #endif
369 static config_set_t* usbGetConfig(int id) {
370 return sbPopulateConfig(&usbGames[id], usbPrefix, "/");
373 static int usbGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
374 char path[255];
375 if (isRelative)
376 sprintf(path, "%s%s/%s_%s", usbPrefix, folder, value, suffix);
377 else
378 sprintf(path, "%s%s_%s", folder, value, suffix);
379 return texDiscoverLoad(resultTex, path, -1, psm);
382 static void usbCleanUp(int exception) {
383 if (usbGameList.enabled) {
384 LOG("usbCleanUp()\n");
386 free(usbGames);
390 #ifdef VMC
391 static int usbCheckVMC(char* name, int createSize) {
392 return sysCheckVMC(usbPrefix, "/", name, createSize);
394 #endif
396 static item_list_t usbGameList = {
397 USB_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "USB Games", _STR_USB_GAMES, &usbInit, &usbNeedsUpdate,
398 #ifdef __CHILDPROOF
399 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, NULL, NULL,
400 #else
401 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, &usbDeleteGame, NULL,
402 #endif
403 #ifdef VMC
404 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, &usbCheckVMC, USB_ICON
405 #else
406 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, USB_ICON
407 #endif