extracted code branching from ItemsList drawing and main drawing method
[open-ps2-loader.git] / src / usbsupport.c
blob4e02b9c3b760a04806daa2eca0c3035853233104
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 #ifdef VMC
84 sprintf(path, "%sVMC", usbPrefix);
85 checkCreateDir(path);
86 #endif
89 void usbLoadModules(void) {
90 LOG("usbLoadModules()\n");
91 //first it search for custom usbd in MC?
92 usbd_irx = readFile("mc?:BEDATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
93 if (!usbd_irx) {
94 usbd_irx = readFile("mc?:BADATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
95 if (!usbd_irx) {
96 usbd_irx = readFile("mc?:BIDATA-SYSTEM/USBD.IRX", -1, &size_usbd_irx);
97 if (!usbd_irx) { // If don't exist it uses embedded
98 if (sysPS3Detect() == 0) {
99 usbd_irx = (void *) &usbd_ps2_irx;
100 size_usbd_irx = size_usbd_ps2_irx;
101 } else {
102 usbd_irx = (void *) &usbd_ps3_irx;
103 size_usbd_irx = size_usbd_ps3_irx;
109 sysLoadModuleBuffer(usbd_irx, size_usbd_irx, 0, NULL);
110 sysLoadModuleBuffer(&usbhdfsd_irx, size_usbhdfsd_irx, 0, NULL);
112 delay(gUSBDelay);
114 LOG("usbLoadModules: modules loaded\n");
117 void usbInit(void) {
118 LOG("usbInit()\n");
119 usbULSizePrev = -2;
120 memset(usbModifiedCDPrev, 0, 8);
121 memset(usbModifiedDVDPrev, 0, 8);
122 usbGameCount = 0;
123 usbGames = NULL;
125 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &usbInitModules);
127 usbGameList.enabled = 1;
130 item_list_t* usbGetObject(int initOnly) {
131 if (initOnly && !usbGameList.enabled)
132 return NULL;
133 return &usbGameList;
136 static int usbNeedsUpdate(void) {
137 int result = 0;
138 fio_stat_t stat;
139 char path[255];
141 usbFindPartition(usbPrefix, "ul.cfg");
143 sprintf(path, "%sCD", usbPrefix);
144 if (fioGetstat(path, &stat) != 0)
145 memset(stat.mtime, 0, 8);
146 if (memcmp(usbModifiedCDPrev, stat.mtime, 8)) {
147 memcpy(usbModifiedCDPrev, stat.mtime, 8);
148 result = 1;
151 sprintf(path, "%sDVD", usbPrefix);
152 if (fioGetstat(path, &stat) != 0)
153 memset(stat.mtime, 0, 8);
154 if (memcmp(usbModifiedDVDPrev, stat.mtime, 8)) {
155 memcpy(usbModifiedDVDPrev, stat.mtime, 8);
156 result = 1;
159 if (!sbIsSameSize(usbPrefix, usbULSizePrev))
160 result = 1;
162 return result;
165 static int usbUpdateGameList(void) {
166 sbReadList(&usbGames, usbPrefix, &usbULSizePrev, &usbGameCount);
167 return usbGameCount;
170 static int usbGetGameCount(void) {
171 return usbGameCount;
174 static void* usbGetGame(int id) {
175 return (void*) &usbGames[id];
178 static char* usbGetGameName(int id) {
179 return usbGames[id].name;
182 static int usbGetGameNameLength(int id) {
183 if (usbGames[id].isISO)
184 return ISO_GAME_NAME_MAX + 1;
185 else
186 return UL_GAME_NAME_MAX + 1;
189 static char* usbGetGameStartup(int id) {
190 return usbGames[id].startup;
193 #ifndef __CHILDPROOF
194 static void usbDeleteGame(int id) {
195 sbDelete(&usbGames, usbPrefix, "/", usbGameCount, id);
196 usbULSizePrev = -2;
199 /*static void usbRenameGame(int id, char* newName) {
200 // TODO when/if Jimmi add rename functionnality to usbhdfs, then we should use the above method
201 //sbRename(&usbGames, usbPrefix, "/", usbGameCount, id, newName);
202 usbULSizePrev = -2;
204 #endif
206 static int usbGetGameCompatibility(int id, int *dmaMode) {
207 return configGetCompatibility(usbGames[id].startup, usbGameList.mode, NULL);
210 static void usbSetGameCompatibility(int id, int compatMode, int dmaMode) {
211 configSetCompatibility(usbGames[id].startup, usbGameList.mode, compatMode, -1);
214 #ifdef VMC
215 static int usbPrepareMcemu(base_game_info_t* game) {
216 char vmc[2][32];
217 char vmc_path[255];
218 u32 vmc_size;
219 int i, j, fd, size_mcemu_irx = 0;
220 usb_vmc_infos_t usb_vmc_infos;
221 vmc_superblock_t vmc_superblock;
223 configGetVMC(game->startup, vmc[0], USB_MODE, 0);
224 configGetVMC(game->startup, vmc[1], USB_MODE, 1);
226 for(i=0; i<2; i++) {
227 if(!vmc[i][0]) // skip if empty
228 continue;
230 memset(&usb_vmc_infos, 0, sizeof(usb_vmc_infos_t));
231 memset(&vmc_superblock, 0, sizeof(vmc_superblock_t));
233 sprintf(vmc_path, "%sVMC/%s.bin", usbPrefix, vmc[i]);
235 fd = fioOpen(vmc_path, O_RDWR);
236 if (fd >= 0) {
237 size_mcemu_irx = -1;
238 LOG("%s open\n", vmc_path);
240 vmc_size = fioLseek(fd, 0, SEEK_END);
241 fioLseek(fd, 0, SEEK_SET);
242 fioRead(fd, (void*)&vmc_superblock, sizeof(vmc_superblock_t));
244 LOG("File size : 0x%X\n", vmc_size);
245 LOG("Magic : %s\n", vmc_superblock.magic);
246 LOG("Card type : %d\n", vmc_superblock.mc_type);
248 if(!strncmp(vmc_superblock.magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock.mc_type == 0x2) {
249 usb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
250 usb_vmc_infos.flags |= 0x100;
251 usb_vmc_infos.specs.page_size = vmc_superblock.page_size;
252 usb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
253 usb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
255 LOG("flags : 0x%X\n", usb_vmc_infos.flags );
256 LOG("specs.page_size : 0x%X\n", usb_vmc_infos.specs.page_size );
257 LOG("specs.block_size : 0x%X\n", usb_vmc_infos.specs.block_size);
258 LOG("specs.card_size : 0x%X\n", usb_vmc_infos.specs.card_size );
260 if(vmc_size == usb_vmc_infos.specs.card_size * usb_vmc_infos.specs.page_size) {
261 int fd1 = fioDopen(usbPrefix);
263 if (fd1 >= 0) {
264 sprintf(vmc_path, "%s/VMC/%s.bin", gUSBPrefix, vmc[i]);
265 // Check vmc cluster chain (write operation can cause dammage)
266 if(fioIoctl(fd1, 0xCAFEC0DE, vmc_path)) {
267 LOG("Cluster Chain OK\n");
268 if((j = fioIoctl(fd1, 0xBEEFC0DE, vmc_path)) != 0) {
269 usb_vmc_infos.active = 1;
270 usb_vmc_infos.start_sector = j;
271 LOG("Start Sector: 0x%X\n", usb_vmc_infos.start_sector);
273 } // else Vmc file fragmented
275 fioDclose(fd1);
278 fioClose(fd);
280 for (j=0; j<size_usb_mcemu_irx; j++) {
281 if (((u32*)&usb_mcemu_irx)[j] == (0xC0DEFAC0 + i)) {
282 if(usb_vmc_infos.active)
283 size_mcemu_irx = size_usb_mcemu_irx;
284 memcpy(&((u32*)&usb_mcemu_irx)[j], &usb_vmc_infos, sizeof(usb_vmc_infos_t));
285 break;
289 return size_mcemu_irx;
291 #endif
293 static void usbLaunchGame(int id) {
294 int fd, r, index, i, compatmask;
295 char isoname[32], partname[255], filename[32];
296 base_game_info_t* game = &usbGames[id];
298 fd = fioDopen(usbPrefix);
299 if (fd < 0) {
300 guiMsgBox(_l(_STR_ERR_FILE_INVALID), 0, NULL);
301 return;
304 if (game->isISO)
305 sprintf(partname, "%s/%s/%s.%s.iso", gUSBPrefix, (game->media == 0x12) ? "CD" : "DVD", game->startup, game->name);
306 else
307 sprintf(partname, "%s/%s.00", gUSBPrefix, isoname);
308 r = fioIoctl(fd, 0xDEADC0DE, partname);
309 LOG("mass storage device sectorsize = %d\n", r);
311 void *irx = &usb_cdvdman_irx;
312 int irx_size = size_usb_cdvdman_irx;
313 if (r == 4096) {
314 irx = &usb_4Ksectors_cdvdman_irx;
315 irx_size = size_usb_4Ksectors_cdvdman_irx;
318 compatmask = sbPrepare(game, usbGameList.mode, isoname, irx_size, irx, &index);
320 if (gCheckUSBFragmentation)
321 for (i = 0; i < game->parts; i++) {
322 if (!game->isISO)
323 sprintf(partname, "%s/%s.%02x", gUSBPrefix, isoname, i);
325 if (fioIoctl(fd, 0xCAFEC0DE, partname) == 0) {
326 fioDclose(fd);
327 guiMsgBox(_l(_STR_ERR_FRAGMENTED), 0, NULL);
328 return;
332 if (gRememberLastPlayed) {
333 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
334 saveConfig(CONFIG_LAST, 0);
337 int offset = 44;
338 for (i = 0; i < game->parts; i++) {
339 if (!game->isISO)
340 sprintf(partname, "%s/%s.%02x", gUSBPrefix, isoname, i);
342 r = fioIoctl(fd, 0xBEEFC0DE, partname);
343 memcpy((void*)((u32)&usb_cdvdman_irx + index + offset), &r, 4);
344 offset += 4;
347 fioDclose(fd);
349 #ifdef VMC
350 int size_mcemu_irx = usbPrepareMcemu(game);
351 if (size_mcemu_irx == -1) {
352 if (guiMsgBox(_l(_STR_ERR_VMC_CONTINUE), 1, NULL))
353 size_mcemu_irx = 0;
354 else
355 return;
357 #endif
359 sprintf(filename,"%s",game->startup);
360 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call usbCleanUp, so usbGames/game will be freed
361 FlushCache(0);
363 #ifdef VMC
364 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, size_mcemu_irx, &usb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
365 #else
366 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, compatmask, compatmask & COMPAT_MODE_1);
367 #endif
370 static config_set_t* usbGetConfig(int id) {
371 return sbPopulateConfig(&usbGames[id], usbPrefix, "/");
374 static int usbGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
375 char path[255];
376 if (isRelative)
377 sprintf(path, "%s%s/%s_%s", usbPrefix, folder, value, suffix);
378 else
379 sprintf(path, "%s%s_%s", folder, value, suffix);
380 return texDiscoverLoad(resultTex, path, -1, psm);
383 static void usbCleanUp(int exception) {
384 if (usbGameList.enabled) {
385 LOG("usbCleanUp()\n");
387 free(usbGames);
391 #ifdef VMC
392 static int usbCheckVMC(char* name, int createSize) {
393 return sysCheckVMC(usbPrefix, "/", name, createSize);
395 #endif
397 static item_list_t usbGameList = {
398 USB_MODE, 0, 0, MENU_MIN_INACTIVE_FRAMES, "USB Games", _STR_USB_GAMES, &usbInit, &usbNeedsUpdate,
399 #ifdef __CHILDPROOF
400 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, NULL, NULL,
401 #else
402 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, &usbDeleteGame, NULL,
403 #endif
404 #ifdef VMC
405 &usbGetGameCompatibility, &usbSetGameCompatibility, &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, &usbCheckVMC, USB_ICON
406 #else
407 &usbGetGameCompatibility, &usbSetGameCompatibility, &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, USB_ICON
408 #endif