fix for wrapping artefact when display_mode=ALWAYS
[open-ps2-loader.git] / src / usbsupport.c
blob8b24d9b744a08fff8e5c6f203f1c8eebec822ae5
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("USBSUPPORT LoadModules\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("USBSUPPORT Modules loaded\n");
120 void usbInit(void) {
121 LOG("USBSUPPORT Init\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 static void usbLaunchGame(int id, config_set_t* configSet) {
210 int i, fd, val, index, compatmask = 0;
211 char partname[255], filename[32];
212 base_game_info_t* game = &usbGames[id];
214 fd = fioDopen(usbPrefix);
215 if (fd < 0) {
216 guiMsgBox(_l(_STR_ERR_FILE_INVALID), 0, NULL);
217 return;
220 #ifdef VMC
221 char vmc_name[32], vmc_path[255];
222 int vmc_id, have_error = 0, size_mcemu_irx = 0;
223 usb_vmc_infos_t usb_vmc_infos;
224 vmc_superblock_t vmc_superblock;
226 for (vmc_id = 0; vmc_id < 2; vmc_id++) {
227 memset(&usb_vmc_infos, 0, sizeof(usb_vmc_infos_t));
228 configGetVMC(configSet, vmc_name, vmc_id);
229 if (vmc_name[0]) {
230 have_error = 1;
231 if (sysCheckVMC(usbPrefix, "/", vmc_name, 0, &vmc_superblock) > 0) {
232 usb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
233 usb_vmc_infos.flags |= 0x100;
234 usb_vmc_infos.specs.page_size = vmc_superblock.page_size;
235 usb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
236 usb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
238 // Check vmc cluster chain (write operation can cause dammage)
239 sprintf(vmc_path, "%s/VMC/%s.bin", gUSBPrefix, vmc_name);
240 if (fioIoctl(fd, 0xCAFEC0DE, vmc_path)) {
241 LOG("USBSUPPORT Cluster Chain OK\n");
242 if ((i = fioIoctl(fd, 0xBEEFC0DE, vmc_path)) != 0) {
243 have_error = 0;
244 usb_vmc_infos.active = 1;
245 usb_vmc_infos.start_sector = i;
246 LOG("USBSUPPORT Start Sector: 0x%X\n", usb_vmc_infos.start_sector);
252 if (have_error) {
253 char error[255];
254 snprintf(error, 255, _l(_STR_ERR_VMC_CONTINUE), vmc_name, (vmc_id + 1));
255 if (!guiMsgBox(error, 1, NULL)) {
256 fioDclose(fd);
257 return;
261 for (i = 0; i < size_usb_mcemu_irx; i++) {
262 if (((u32*)&usb_mcemu_irx)[i] == (0xC0DEFAC0 + vmc_id)) {
263 if (usb_vmc_infos.active)
264 size_mcemu_irx = size_usb_mcemu_irx;
265 memcpy(&((u32*)&usb_mcemu_irx)[i], &usb_vmc_infos, sizeof(usb_vmc_infos_t));
266 break;
270 #endif
272 void** irx = &usb_cdvdman_irx;
273 int irx_size = size_usb_cdvdman_irx;
274 for (i = 0; i < game->parts; i++) {
275 if (game->isISO)
276 sprintf(partname, "%s/%s/%s.%s%s", gUSBPrefix, (game->media == 0x12) ? "CD" : "DVD", game->startup, game->name, game->extension);
277 else
278 sprintf(partname, "%s/ul.%08X.%s.%02x", gUSBPrefix, USBA_crc32(game->name), game->startup, i);
280 if (gCheckUSBFragmentation) {
281 if (fioIoctl(fd, 0xCAFEC0DE, partname) == 0) {
282 fioDclose(fd);
283 guiMsgBox(_l(_STR_ERR_FRAGMENTED), 0, NULL);
284 return;
288 if (i == 0) {
289 val = fioIoctl(fd, 0xDEADC0DE, partname);
290 LOG("USBSUPPORT Mass storage device sector size = %d\n", val);
291 if (val == 4096) {
292 irx = &usb_4Ksectors_cdvdman_irx;
293 irx_size = size_usb_4Ksectors_cdvdman_irx;
295 compatmask = sbPrepare(game, configSet, irx_size, irx, &index);
298 val = fioIoctl(fd, 0xBEEFC0DE, partname);
299 memcpy((void*)((u32)irx + index + 44 + 4 * i), &val, 4);
302 if (gRememberLastPlayed) {
303 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
304 saveConfig(CONFIG_LAST, 0);
307 fioDclose(fd);
309 char *altStartup = NULL;
310 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
311 strncpy(filename, altStartup, 32);
312 else
313 sprintf(filename, "%s", game->startup);
314 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call usbCleanUp, so usbGames/game will be freed
315 FlushCache(0);
317 #ifdef VMC
318 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, size_mcemu_irx, &usb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
319 #else
320 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, compatmask, compatmask & COMPAT_MODE_1);
321 #endif
324 static config_set_t* usbGetConfig(int id) {
325 return sbPopulateConfig(&usbGames[id], usbPrefix, "/");
328 static int usbGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
329 char path[255];
330 if (isRelative)
331 sprintf(path, "%s%s/%s_%s", usbPrefix, folder, value, suffix);
332 else
333 sprintf(path, "%s%s_%s", folder, value, suffix);
334 return texDiscoverLoad(resultTex, path, -1, psm);
337 static void usbCleanUp(int exception) {
338 if (usbGameList.enabled) {
339 LOG("USBSUPPORT CleanUp\n");
341 free(usbGames);
345 #ifdef VMC
346 static int usbCheckVMC(char* name, int createSize) {
347 return sysCheckVMC(usbPrefix, "/", name, createSize, NULL);
349 #endif
351 static item_list_t usbGameList = {
352 USB_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "USB Games", _STR_USB_GAMES, &usbInit, &usbNeedsUpdate,
353 #ifdef __CHILDPROOF
354 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, NULL, NULL,
355 #else
356 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, &usbDeleteGame, NULL,
357 #endif
358 #ifdef VMC
359 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, &usbCheckVMC, USB_ICON
360 #else
361 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, USB_ICON
362 #endif