Suggestion from "mgh".
[open-ps2-loader.git] / src / usbsupport.c
blob27c9eb68599d228aae8fed5326978aeb054ca6a9
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;
127 configGetInt(configGetByType(CONFIG_OPL), "usb_frames_delay", &usbGameList.delay);
128 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &usbInitModules);
129 usbGameList.enabled = 1;
132 item_list_t* usbGetObject(int initOnly) {
133 if (initOnly && !usbGameList.enabled)
134 return NULL;
135 return &usbGameList;
138 static int usbNeedsUpdate(void) {
139 int result = 0;
140 fio_stat_t stat;
141 char path[255];
143 usbFindPartition(usbPrefix, "ul.cfg");
145 sprintf(path, "%sCD", usbPrefix);
146 if (fioGetstat(path, &stat) != 0)
147 memset(stat.mtime, 0, 8);
148 if (memcmp(usbModifiedCDPrev, stat.mtime, 8)) {
149 memcpy(usbModifiedCDPrev, stat.mtime, 8);
150 result = 1;
153 sprintf(path, "%sDVD", usbPrefix);
154 if (fioGetstat(path, &stat) != 0)
155 memset(stat.mtime, 0, 8);
156 if (memcmp(usbModifiedDVDPrev, stat.mtime, 8)) {
157 memcpy(usbModifiedDVDPrev, stat.mtime, 8);
158 result = 1;
161 if (!sbIsSameSize(usbPrefix, usbULSizePrev))
162 result = 1;
164 return result;
167 static int usbUpdateGameList(void) {
168 sbReadList(&usbGames, usbPrefix, &usbULSizePrev, &usbGameCount);
169 return usbGameCount;
172 static int usbGetGameCount(void) {
173 return usbGameCount;
176 static void* usbGetGame(int id) {
177 return (void*) &usbGames[id];
180 static char* usbGetGameName(int id) {
181 return usbGames[id].name;
184 static int usbGetGameNameLength(int id) {
185 if (usbGames[id].isISO)
186 return ISO_GAME_NAME_MAX + 1;
187 else
188 return UL_GAME_NAME_MAX + 1;
191 static char* usbGetGameStartup(int id) {
192 return usbGames[id].startup;
195 #ifndef __CHILDPROOF
196 static void usbDeleteGame(int id) {
197 sbDelete(&usbGames, usbPrefix, "/", usbGameCount, id);
198 usbULSizePrev = -2;
201 /*static void usbRenameGame(int id, char* newName) {
202 // TODO when/if Jimmi add rename functionnality to usbhdfs, then we should use the above method
203 //sbRename(&usbGames, usbPrefix, "/", usbGameCount, id, newName);
204 usbULSizePrev = -2;
206 #endif
208 static void usbLaunchGame(int id, config_set_t* configSet) {
209 int i, fd, val, index, compatmask = 0;
210 char partname[255], filename[32];
211 base_game_info_t* game = &usbGames[id];
213 fd = fioDopen(usbPrefix);
214 if (fd < 0) {
215 guiMsgBox(_l(_STR_ERR_FILE_INVALID), 0, NULL);
216 return;
219 #ifdef VMC
220 char vmc_name[32], vmc_path[255];
221 int vmc_id, have_error = 0, size_mcemu_irx = 0;
222 usb_vmc_infos_t usb_vmc_infos;
223 vmc_superblock_t vmc_superblock;
225 for (vmc_id = 0; vmc_id < 2; vmc_id++) {
226 memset(&usb_vmc_infos, 0, sizeof(usb_vmc_infos_t));
227 configGetVMC(configSet, vmc_name, vmc_id);
228 if (vmc_name[0]) {
229 have_error = 1;
230 if (sysCheckVMC(usbPrefix, "/", vmc_name, 0, &vmc_superblock) > 0) {
231 usb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
232 usb_vmc_infos.flags |= 0x100;
233 usb_vmc_infos.specs.page_size = vmc_superblock.page_size;
234 usb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
235 usb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
237 // Check vmc cluster chain (write operation can cause dammage)
238 sprintf(vmc_path, "%s/VMC/%s.bin", gUSBPrefix, vmc_name);
239 if (fioIoctl(fd, 0xCAFEC0DE, vmc_path)) {
240 LOG("USBSUPPORT Cluster Chain OK\n");
241 if ((i = fioIoctl(fd, 0xBEEFC0DE, vmc_path)) != 0) {
242 have_error = 0;
243 usb_vmc_infos.active = 1;
244 usb_vmc_infos.start_sector = i;
245 LOG("USBSUPPORT Start Sector: 0x%X\n", usb_vmc_infos.start_sector);
251 if (have_error) {
252 char error[255];
253 snprintf(error, 255, _l(_STR_ERR_VMC_CONTINUE), vmc_name, (vmc_id + 1));
254 if (!guiMsgBox(error, 1, NULL)) {
255 fioDclose(fd);
256 return;
260 for (i = 0; i < size_usb_mcemu_irx; i++) {
261 if (((u32*)&usb_mcemu_irx)[i] == (0xC0DEFAC0 + vmc_id)) {
262 if (usb_vmc_infos.active)
263 size_mcemu_irx = size_usb_mcemu_irx;
264 memcpy(&((u32*)&usb_mcemu_irx)[i], &usb_vmc_infos, sizeof(usb_vmc_infos_t));
265 break;
269 #endif
271 void** irx = &usb_cdvdman_irx;
272 int irx_size = size_usb_cdvdman_irx;
273 for (i = 0; i < game->parts; i++) {
274 if (game->isISO)
275 sprintf(partname, "%s/%s/%s.%s%s", gUSBPrefix, (game->media == 0x12) ? "CD" : "DVD", game->startup, game->name, game->extension);
276 else
277 sprintf(partname, "%s/ul.%08X.%s.%02x", gUSBPrefix, USBA_crc32(game->name), game->startup, i);
279 if (gCheckUSBFragmentation) {
280 if (fioIoctl(fd, 0xCAFEC0DE, partname) == 0) {
281 fioDclose(fd);
282 guiMsgBox(_l(_STR_ERR_FRAGMENTED), 0, NULL);
283 return;
287 if (i == 0) {
288 val = fioIoctl(fd, 0xDEADC0DE, partname);
289 LOG("USBSUPPORT Mass storage device sector size = %d\n", val);
290 if (val == 4096) {
291 irx = &usb_4Ksectors_cdvdman_irx;
292 irx_size = size_usb_4Ksectors_cdvdman_irx;
294 compatmask = sbPrepare(game, configSet, irx_size, irx, &index);
297 val = fioIoctl(fd, 0xBEEFC0DE, partname);
298 memcpy((void*)((u32)irx + index + 44 + 4 * i), &val, 4);
301 if (gRememberLastPlayed) {
302 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
303 saveConfig(CONFIG_LAST, 0);
306 fioDclose(fd);
308 char *altStartup = NULL;
309 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
310 strncpy(filename, altStartup, 32);
311 else
312 sprintf(filename, "%s", game->startup);
313 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call usbCleanUp, so usbGames/game will be freed
314 FlushCache(0);
316 #ifdef VMC
317 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, size_mcemu_irx, &usb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
318 #else
319 sysLaunchLoaderElf(filename, "USB_MODE", irx_size, irx, compatmask, compatmask & COMPAT_MODE_1);
320 #endif
323 static config_set_t* usbGetConfig(int id) {
324 return sbPopulateConfig(&usbGames[id], usbPrefix, "/");
327 static int usbGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
328 char path[255];
329 if (isRelative)
330 sprintf(path, "%s%s/%s_%s", usbPrefix, folder, value, suffix);
331 else
332 sprintf(path, "%s%s_%s", folder, value, suffix);
333 return texDiscoverLoad(resultTex, path, -1, psm);
336 static void usbCleanUp(int exception) {
337 if (usbGameList.enabled) {
338 LOG("USBSUPPORT CleanUp\n");
340 free(usbGames);
344 #ifdef VMC
345 static int usbCheckVMC(char* name, int createSize) {
346 return sysCheckVMC(usbPrefix, "/", name, createSize, NULL);
348 #endif
350 static item_list_t usbGameList = {
351 USB_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "USB Games", _STR_USB_GAMES, &usbInit, &usbNeedsUpdate,
352 #ifdef __CHILDPROOF
353 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, NULL, NULL,
354 #else
355 &usbUpdateGameList, &usbGetGameCount, &usbGetGame, &usbGetGameName, &usbGetGameNameLength, &usbGetGameStartup, &usbDeleteGame, NULL,
356 #endif
357 #ifdef VMC
358 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, &usbCheckVMC, USB_ICON
359 #else
360 &usbLaunchGame, &usbGetConfig, &usbGetImage, &usbCleanUp, USB_ICON
361 #endif