extracted code branching from ItemsList drawing and main drawing method
[open-ps2-loader.git] / src / ethsupport.c
blobc1f96127b062e3d226bb5b5c9cd91546550679b7
1 #include "include/usbld.h"
2 #include "include/lang.h"
3 #include "include/gui.h"
4 #include "include/supportbase.h"
5 #include "include/ethsupport.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"
11 #include "include/smbman.h"
13 extern void *smb_cdvdman_irx;
14 extern int size_smb_cdvdman_irx;
16 extern void *smb_pcmcia_cdvdman_irx;
17 extern int size_smb_pcmcia_cdvdman_irx;
19 extern void *ps2dev9_irx;
20 extern int size_ps2dev9_irx;
22 extern void *smsutils_irx;
23 extern int size_smsutils_irx;
25 extern void *smstcpip_irx;
26 extern int size_smstcpip_irx;
28 extern void *smsmap_irx;
29 extern int size_smsmap_irx;
31 extern void *smbman_irx;
32 extern int size_smbman_irx;
34 #ifdef VMC
35 extern void *smb_mcemu_irx;
36 extern int size_smb_mcemu_irx;
37 #endif
39 static char *ethPrefix = NULL;
40 static int ethULSizePrev = -2;
41 static unsigned char ethModifiedCDPrev[8];
42 static unsigned char ethModifiedDVDPrev[8];
43 static int ethGameCount = 0;
44 static base_game_info_t *ethGames = NULL;
46 // forward declaration
47 static item_list_t ethGameList;
49 static void ethLoadModules(void) {
50 int ret, ipconfiglen;
51 char ipconfig[IPCONFIG_MAX_LEN] __attribute__((aligned(64)));
53 LOG("ethLoadModules()\n");
55 ipconfiglen = sysSetIPConfig(ipconfig);
57 gNetworkStartup = 5;
59 ret = sysLoadModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx, 0, NULL);
60 if (ret < 0) {
61 gNetworkStartup = -1;
62 return;
65 gNetworkStartup = 4;
67 ret = sysLoadModuleBuffer(&smsutils_irx, size_smsutils_irx, 0, NULL);
68 if (ret < 0) {
69 gNetworkStartup = -1;
70 return;
72 gNetworkStartup = 3;
74 ret = sysLoadModuleBuffer(&smstcpip_irx, size_smstcpip_irx, 0, NULL);
75 if (ret < 0) {
76 gNetworkStartup = -1;
77 return;
80 gNetworkStartup = 2;
82 ret = sysLoadModuleBuffer(&smsmap_irx, size_smsmap_irx, ipconfiglen, ipconfig);
83 if (ret < 0) {
84 gNetworkStartup = -1;
85 return;
88 gNetworkStartup = 1;
90 ret = sysLoadModuleBuffer(&smbman_irx, size_smbman_irx, 0, NULL);
91 if (ret < 0) {
92 gNetworkStartup = -1;
93 return;
96 gNetworkStartup = 0; // ok, all loaded
98 LOG("ethLoadModules: modules loaded\n");
100 // connect
101 ethSMBConnect();
103 // update Themes
104 char path[255];
105 sprintf(path, "%sTHM", ethPrefix);
106 thmAddElements(path, "\\", ethGameList.mode);
108 #ifdef VMC
109 sprintf(path, "%sVMC", ethPrefix);
110 checkCreateDir(path);
111 #endif
114 void ethInit(void) {
115 LOG("ethInit()\n");
117 ethPrefix = "smb0:";
118 ethULSizePrev = -2;
119 memset(ethModifiedCDPrev, 0, 8);
120 memset(ethModifiedDVDPrev, 0, 8);
121 ethGameCount = 0;
122 ethGames = NULL;
123 gNetworkStartup = 6;
125 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethLoadModules);
127 ethGameList.enabled = 1;
130 item_list_t* ethGetObject(int initOnly) {
131 if (initOnly && !ethGameList.enabled)
132 return NULL;
133 return &ethGameList;
136 static int ethNeedsUpdate(void) {
137 int result = 0;
139 if (gNetworkStartup == 0) {
140 fio_stat_t stat;
141 char path[255];
143 sprintf(path, "%sCD", ethPrefix);
144 if (fioGetstat(path, &stat) != 0)
145 memset(stat.mtime, 0, 8);
146 if (memcmp(ethModifiedCDPrev, stat.mtime, 8)) {
147 memcpy(ethModifiedCDPrev, stat.mtime, 8);
148 result = 1;
151 sprintf(path, "%sDVD", ethPrefix);
152 if (fioGetstat(path, &stat) != 0)
153 memset(stat.mtime, 0, 8);
154 if (memcmp(ethModifiedDVDPrev, stat.mtime, 8)) {
155 memcpy(ethModifiedDVDPrev, stat.mtime, 8);
156 result = 1;
159 if (!sbIsSameSize(ethPrefix, ethULSizePrev))
160 result = 1;
162 return result;
165 static int ethUpdateGameList(void) {
166 if (gNetworkStartup != 0)
167 return 0;
169 sbReadList(&ethGames, ethPrefix, &ethULSizePrev, &ethGameCount);
170 return ethGameCount;
173 static int ethGetGameCount(void) {
174 return ethGameCount;
177 static void* ethGetGame(int id) {
178 return (void*) &ethGames[id];
181 static char* ethGetGameName(int id) {
182 return ethGames[id].name;
185 static int ethGetGameNameLength(int id) {
186 if (ethGames[id].isISO)
187 return ISO_GAME_NAME_MAX + 1;
188 else
189 return UL_GAME_NAME_MAX + 1;
192 static char* ethGetGameStartup(int id) {
193 return ethGames[id].startup;
196 #ifndef __CHILDPROOF
197 static void ethDeleteGame(int id) {
198 sbDelete(&ethGames, ethPrefix, "\\", ethGameCount, id);
199 ethULSizePrev = -2;
202 static void ethRenameGame(int id, char* newName) {
203 sbRename(&ethGames, ethPrefix, "\\", ethGameCount, id, newName);
204 ethULSizePrev = -2;
206 #endif
208 static int ethGetGameCompatibility(int id, int *dmaMode) {
209 return configGetCompatibility(ethGames[id].startup, ethGameList.mode, NULL);
212 static void ethSetGameCompatibility(int id, int compatMode, int dmaMode) {
213 configSetCompatibility(ethGames[id].startup, ethGameList.mode, compatMode, -1);
216 #ifdef VMC
217 static int ethPrepareMcemu(base_game_info_t* game) {
218 char vmc[2][32];
219 char vmc_path[255];
220 u32 vmc_size;
221 int i, j, fd, size_mcemu_irx = 0;
222 smb_vmc_infos_t smb_vmc_infos;
223 vmc_superblock_t vmc_superblock;
225 configGetVMC(game->startup, vmc[0], ETH_MODE, 0);
226 configGetVMC(game->startup, vmc[1], ETH_MODE, 1);
228 for(i=0; i<2; i++) {
229 if(!vmc[i][0]) // skip if empty
230 continue;
232 memset(&smb_vmc_infos, 0, sizeof(smb_vmc_infos_t));
233 memset(&vmc_superblock, 0, sizeof(vmc_superblock_t));
235 snprintf(vmc_path, 255, "%s\\VMC\\%s.bin", ethPrefix, vmc[i]);
237 fd = fileXioOpen(vmc_path, O_RDONLY, 0666);
238 if (fd >= 0) {
239 size_mcemu_irx = -1;
240 LOG("%s open\n", vmc_path);
242 vmc_size = fileXioLseek(fd, 0, SEEK_END);
243 fileXioLseek(fd, 0, SEEK_SET);
244 fileXioRead(fd, (void*)&vmc_superblock, sizeof(vmc_superblock_t));
246 LOG("File size : 0x%X\n", vmc_size);
247 LOG("Magic : %s\n", vmc_superblock.magic);
248 LOG("Card type : %d\n", vmc_superblock.mc_type);
250 if(!strncmp(vmc_superblock.magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock.mc_type == 0x2) {
251 smb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
252 smb_vmc_infos.flags |= 0x100;
253 smb_vmc_infos.specs.page_size = vmc_superblock.page_size;
254 smb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
255 smb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
257 LOG("flags : 0x%X\n", smb_vmc_infos.flags );
258 LOG("specs.page_size : 0x%X\n", smb_vmc_infos.specs.page_size );
259 LOG("specs.block_size : 0x%X\n", smb_vmc_infos.specs.block_size);
260 LOG("specs.card_size : 0x%X\n", smb_vmc_infos.specs.card_size );
262 if(vmc_size == smb_vmc_infos.specs.card_size * smb_vmc_infos.specs.page_size) {
263 smb_vmc_infos.active = 1;
264 smb_vmc_infos.fid = 0xFFFF;
265 snprintf(vmc_path, 255, "VMC\\%s.bin", vmc[i]);
266 strncpy(smb_vmc_infos.fname, vmc_path, 32); // maybe a too small size here ...
268 LOG("%s is a valid Vmc file\n", smb_vmc_infos.fname );
271 fileXioClose(fd);
273 for (j=0; j<size_smb_mcemu_irx; j++) {
274 if (((u32*)&smb_mcemu_irx)[j] == (0xC0DEFAC0 + i)) {
275 if(smb_vmc_infos.active)
276 size_mcemu_irx = size_smb_mcemu_irx;
277 memcpy(&((u32*)&smb_mcemu_irx)[j], &smb_vmc_infos, sizeof(smb_vmc_infos_t));
278 break;
282 return size_mcemu_irx;
284 #endif
286 static void ethLaunchGame(int id) {
287 if (gNetworkStartup != 0) {
288 guiMsgBox(_l(_STR_NETWORK_STARTUP_ERROR), 0, NULL);
289 return;
292 int i, compatmask, size_irx = 0;
293 void** irx = NULL;
294 char isoname[32], filename[32];
295 base_game_info_t* game = &ethGames[id];
297 if (gRememberLastPlayed) {
298 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
299 saveConfig(CONFIG_LAST, 0);
302 if (sysPcmciaCheck()) {
303 size_irx = size_smb_pcmcia_cdvdman_irx;
304 irx = &smb_pcmcia_cdvdman_irx;
306 else {
307 size_irx = size_smb_cdvdman_irx;
308 irx = &smb_cdvdman_irx;
311 compatmask = sbPrepare(game, ethGameList.mode, isoname, size_irx, irx, &i);
313 // For ISO we use the part table to store the "long" name (only for init)
314 if (game->isISO)
315 memcpy((void*)((u32)irx + i + 44), game->name, strlen(game->name) + 1);
317 for (i = 0; i < size_irx; i++) {
318 if (!strcmp((const char*)((u32)irx + i),"xxx.xxx.xxx.xxx")) {
319 break;
323 #ifdef VMC
324 int size_mcemu_irx = ethPrepareMcemu(game);
325 if (size_mcemu_irx == -1) {
326 if (guiMsgBox(_l(_STR_ERR_VMC_CONTINUE), 1, NULL))
327 size_mcemu_irx = 0;
328 else
329 return;
331 #endif
332 // disconnect from the active SMB session
333 ethSMBDisconnect();
335 char config_str[255];
336 sprintf(config_str, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
337 memcpy((void*)((u32)irx + i), config_str, strlen(config_str) + 1);
338 memcpy((void*)((u32)irx + i + 16), &gPCPort, 4);
339 memcpy((void*)((u32)irx + i + 20), gPCShareName, 32);
340 memcpy((void*)((u32)irx + i + 56), gPCUserName, 32);
341 memcpy((void*)((u32)irx + i + 92), gPCPassword, 32);
343 sprintf(filename,"%s",game->startup);
344 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call ethCleanUp, so ethGames/game will be freed
345 // disconnect from the active SMB session
346 ethSMBDisconnect();
347 FlushCache(0);
349 #ifdef VMC
350 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, size_mcemu_irx, &smb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
351 #else
352 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, compatmask, compatmask & COMPAT_MODE_1);
353 #endif
356 static config_set_t* ethGetConfig(int id) {
357 return sbPopulateConfig(&ethGames[id], ethPrefix, "\\");
360 static int ethGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
361 char path[255];
362 if (isRelative)
363 sprintf(path, "%s%s\\%s_%s", ethPrefix, folder, value, suffix);
364 else
365 sprintf(path, "%s%s_%s", folder, value, suffix);
366 return texDiscoverLoad(resultTex, path, -1, psm);
369 static void ethCleanUp(int exception) {
370 if (ethGameList.enabled) {
371 LOG("ethCleanUp()\n");
373 free(ethGames);
377 #ifdef VMC
378 static int ethCheckVMC(char* name, int createSize) {
379 return sysCheckVMC(ethPrefix, "\\", name, createSize);
381 #endif
383 int ethSMBConnect(void) {
384 int ret;
385 smbLogOn_in_t logon;
386 smbEcho_in_t echo;
387 smbOpenShare_in_t openshare;
389 // open tcp connection with the server / logon to SMB server
390 sprintf(logon.serverIP, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
391 logon.serverPort = gPCPort;
393 if (strlen(gPCPassword) > 0) {
394 smbGetPasswordHashes_in_t passwd;
395 smbGetPasswordHashes_out_t passwdhashes;
397 // we'll try to generate hashed password first
398 strncpy(logon.User, gPCUserName, 32);
399 strncpy(passwd.password, gPCPassword, 32);
401 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_GETPASSWORDHASHES, (void *)&passwd, sizeof(passwd), (void *)&passwdhashes, sizeof(passwdhashes));
403 if (ret == 0) {
404 // hash generated okay, can use
405 memcpy((void *)logon.Password, (void *)&passwdhashes, sizeof(passwdhashes));
406 logon.PasswordType = HASHED_PASSWORD;
407 memcpy((void *)openshare.Password, (void *)&passwdhashes, sizeof(passwdhashes));
408 openshare.PasswordType = HASHED_PASSWORD;
409 } else {
410 // failed hashing, failback to plaintext
411 strncpy(logon.Password, gPCPassword, 32);
412 logon.PasswordType = PLAINTEXT_PASSWORD;
413 strncpy(openshare.Password, gPCPassword, 32);
414 openshare.PasswordType = PLAINTEXT_PASSWORD;
416 } else {
417 strncpy(logon.User, gPCUserName, 32);
418 logon.PasswordType = NO_PASSWORD;
419 openshare.PasswordType = NO_PASSWORD;
422 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_LOGON, (void *)&logon, sizeof(logon), NULL, 0);
423 if (ret < 0)
424 return -2;
426 // SMB server alive test
427 strcpy(echo.echo, "ALIVE ECHO TEST");
428 echo.len = strlen("ALIVE ECHO TEST");
430 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_ECHO, (void *)&echo, sizeof(echo), NULL, 0);
431 if (ret < 0)
432 return -3;
434 // connect to the share
435 strcpy(openshare.ShareName, gPCShareName);
437 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_OPENSHARE, (void *)&openshare, sizeof(openshare), NULL, 0);
438 if (ret < 0)
439 return -4;
441 return 0;
444 int ethSMBDisconnect(void) {
445 int ret;
447 // closing share
448 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_CLOSESHARE, NULL, 0, NULL, 0);
449 if (ret < 0)
450 return -1;
452 // logoff/close tcp connection from SMB server:
453 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_LOGOFF, NULL, 0, NULL, 0);
454 if (ret < 0)
455 return -2;
457 return 0;
460 static item_list_t ethGameList = {
461 ETH_MODE, 0, 0, MENU_MIN_INACTIVE_FRAMES, "ETH Games", _STR_NET_GAMES, &ethInit, &ethNeedsUpdate,
462 #ifdef __CHILDPROOF
463 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, NULL, NULL,
464 #else
465 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, &ethDeleteGame, &ethRenameGame,
466 #endif
467 #ifdef VMC
468 &ethGetGameCompatibility, &ethSetGameCompatibility, &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, &ethCheckVMC, ETH_ICON
469 #else
470 &ethGetGameCompatibility, &ethSetGameCompatibility, &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, ETH_ICON
471 #endif