* Minor GUI changes (deferred error message display, small optim for main loop)
[open-ps2-loader.git] / src / ethsupport.c
blob4c9bdb01e1fadf622649bf408bccf42951527d63
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"
12 extern void *smb_cdvdman_irx;
13 extern int size_smb_cdvdman_irx;
15 extern void *smb_pcmcia_cdvdman_irx;
16 extern int size_smb_pcmcia_cdvdman_irx;
18 extern void *ps2dev9_irx;
19 extern int size_ps2dev9_irx;
21 extern void *smsutils_irx;
22 extern int size_smsutils_irx;
24 extern void *smstcpip_irx;
25 extern int size_smstcpip_irx;
27 extern void *smsmap_irx;
28 extern int size_smsmap_irx;
30 extern void *smbman_irx;
31 extern int size_smbman_irx;
33 #ifdef VMC
34 extern void *smb_mcemu_irx;
35 extern int size_smb_mcemu_irx;
36 #endif
38 static char *ethPrefix = NULL;
39 static int ethULSizePrev = -2;
40 static unsigned char ethModifiedCDPrev[8];
41 static unsigned char ethModifiedDVDPrev[8];
42 static int ethGameCount = 0;
43 static base_game_info_t *ethGames = NULL;
45 // forward declaration
46 static item_list_t ethGameList;
48 void ethSMBConnect(void) {
49 smbLogOn_in_t logon;
50 smbEcho_in_t echo;
51 smbOpenShare_in_t openshare;
53 // open tcp connection with the server / logon to SMB server
54 sprintf(logon.serverIP, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
55 logon.serverPort = gPCPort;
57 if (strlen(gPCPassword) > 0) {
58 smbGetPasswordHashes_in_t passwd;
59 smbGetPasswordHashes_out_t passwdhashes;
61 // we'll try to generate hashed password first
62 strncpy(logon.User, gPCUserName, 32);
63 strncpy(passwd.password, gPCPassword, 32);
65 if (fileXioDevctl(ethPrefix, SMB_DEVCTL_GETPASSWORDHASHES, (void *)&passwd, sizeof(passwd), (void *)&passwdhashes, sizeof(passwdhashes)) == 0) {
66 // hash generated okay, can use
67 memcpy((void *)logon.Password, (void *)&passwdhashes, sizeof(passwdhashes));
68 logon.PasswordType = HASHED_PASSWORD;
69 memcpy((void *)openshare.Password, (void *)&passwdhashes, sizeof(passwdhashes));
70 openshare.PasswordType = HASHED_PASSWORD;
71 } else {
72 // failed hashing, failback to plaintext
73 strncpy(logon.Password, gPCPassword, 32);
74 logon.PasswordType = PLAINTEXT_PASSWORD;
75 strncpy(openshare.Password, gPCPassword, 32);
76 openshare.PasswordType = PLAINTEXT_PASSWORD;
78 } else {
79 strncpy(logon.User, gPCUserName, 32);
80 logon.PasswordType = NO_PASSWORD;
81 openshare.PasswordType = NO_PASSWORD;
84 gNetworkStartup = ERROR_ETH_SMB_LOGON;
85 if (fileXioDevctl(ethPrefix, SMB_DEVCTL_LOGON, (void *)&logon, sizeof(logon), NULL, 0) >= 0) {
86 gNetworkStartup = ERROR_ETH_SMB_ECHO;
88 // SMB server alive test
89 strcpy(echo.echo, "ALIVE ECHO TEST");
90 echo.len = strlen("ALIVE ECHO TEST");
92 if (fileXioDevctl(ethPrefix, SMB_DEVCTL_ECHO, (void *)&echo, sizeof(echo), NULL, 0) >= 0) {
93 gNetworkStartup = ERROR_ETH_SMB_OPENSHARE;
95 // connect to the share
96 strcpy(openshare.ShareName, gPCShareName);
98 if (fileXioDevctl(ethPrefix, SMB_DEVCTL_OPENSHARE, (void *)&openshare, sizeof(openshare), NULL, 0) >= 0) {
100 // everything is ok
101 gNetworkStartup = 0;
107 int ethSMBDisconnect(void) {
108 int ret;
110 // closing share
111 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_CLOSESHARE, NULL, 0, NULL, 0);
112 if (ret < 0)
113 return -1;
115 // logoff/close tcp connection from SMB server:
116 ret = fileXioDevctl(ethPrefix, SMB_DEVCTL_LOGOFF, NULL, 0, NULL, 0);
117 if (ret < 0)
118 return -2;
120 return 0;
123 static void ethInitSMB(void) {
124 // connect
125 ethSMBConnect();
127 // update Themes
128 char path[255];
129 sprintf(path, "%sTHM", ethPrefix);
130 thmAddElements(path, "\\", ethGameList.mode);
132 sprintf(path, "%sCFG", ethPrefix);
133 checkCreateDir(path);
135 #ifdef VMC
136 sprintf(path, "%sVMC", ethPrefix);
137 checkCreateDir(path);
138 #endif
141 static void ethLoadModules(void) {
142 int ipconfiglen;
143 char ipconfig[IPCONFIG_MAX_LEN] __attribute__((aligned(64)));
145 LOG("ethLoadModules()\n");
147 ipconfiglen = sysSetIPConfig(ipconfig);
149 gNetworkStartup = ERROR_ETH_MODULE_PS2DEV9_FAILURE;
150 if (sysLoadModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx, 0, NULL) >= 0) {
151 gNetworkStartup = ERROR_ETH_MODULE_SMSUTILS_FAILURE;
152 if (sysLoadModuleBuffer(&smsutils_irx, size_smsutils_irx, 0, NULL) >= 0) {
153 gNetworkStartup = ERROR_ETH_MODULE_SMSTCPIP_FAILURE;
154 if (sysLoadModuleBuffer(&smstcpip_irx, size_smstcpip_irx, 0, NULL) >= 0) {
155 gNetworkStartup = ERROR_ETH_MODULE_SMSMAP_FAILURE;
156 if (sysLoadModuleBuffer(&smsmap_irx, size_smsmap_irx, ipconfiglen, ipconfig) >= 0) {
157 gNetworkStartup = ERROR_ETH_MODULE_SMBMAN_FAILURE;
158 if (sysLoadModuleBuffer(&smbman_irx, size_smbman_irx, 0, NULL) >= 0) {
159 LOG("ethLoadModules: modules loaded\n");
160 ethInitSMB();
167 if (gNetworkStartup != 0)
168 setErrorMessage(_STR_NETWORK_STARTUP_ERROR, gNetworkStartup);
171 void ethInit(void) {
172 LOG("ethInit()\n");
174 ethPrefix = "smb0:";
175 ethULSizePrev = -2;
176 memset(ethModifiedCDPrev, 0, 8);
177 memset(ethModifiedDVDPrev, 0, 8);
178 ethGameCount = 0;
179 ethGames = NULL;
180 gNetworkStartup = ERROR_ETH_NOT_STARTED;
182 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethLoadModules);
184 ethGameList.enabled = 1;
187 item_list_t* ethGetObject(int initOnly) {
188 if (initOnly && !ethGameList.enabled)
189 return NULL;
190 return &ethGameList;
193 static int ethNeedsUpdate(void) {
194 int result = 0;
196 if (gNetworkStartup >= ERROR_ETH_SMB_LOGON) {
197 ethInitSMB();
198 if (gNetworkStartup != 0)
199 setErrorMessage(_STR_NETWORK_STARTUP_ERROR, gNetworkStartup);
202 if (gNetworkStartup == 0) {
203 fio_stat_t stat;
204 char path[255];
206 sprintf(path, "%sCD", ethPrefix);
207 if (fioGetstat(path, &stat) != 0)
208 memset(stat.mtime, 0, 8);
209 if (memcmp(ethModifiedCDPrev, stat.mtime, 8)) {
210 memcpy(ethModifiedCDPrev, stat.mtime, 8);
211 result = 1;
214 sprintf(path, "%sDVD", ethPrefix);
215 if (fioGetstat(path, &stat) != 0)
216 memset(stat.mtime, 0, 8);
217 if (memcmp(ethModifiedDVDPrev, stat.mtime, 8)) {
218 memcpy(ethModifiedDVDPrev, stat.mtime, 8);
219 result = 1;
222 if (!sbIsSameSize(ethPrefix, ethULSizePrev))
223 result = 1;
225 return result;
228 static int ethUpdateGameList(void) {
229 if (gNetworkStartup != 0)
230 return 0;
232 sbReadList(&ethGames, ethPrefix, &ethULSizePrev, &ethGameCount);
233 return ethGameCount;
236 static int ethGetGameCount(void) {
237 return ethGameCount;
240 static void* ethGetGame(int id) {
241 return (void*) &ethGames[id];
244 static char* ethGetGameName(int id) {
245 return ethGames[id].name;
248 static int ethGetGameNameLength(int id) {
249 if (ethGames[id].isISO)
250 return ISO_GAME_NAME_MAX + 1;
251 else
252 return UL_GAME_NAME_MAX + 1;
255 static char* ethGetGameStartup(int id) {
256 return ethGames[id].startup;
259 #ifndef __CHILDPROOF
260 static void ethDeleteGame(int id) {
261 sbDelete(&ethGames, ethPrefix, "\\", ethGameCount, id);
262 ethULSizePrev = -2;
265 static void ethRenameGame(int id, char* newName) {
266 sbRename(&ethGames, ethPrefix, "\\", ethGameCount, id, newName);
267 ethULSizePrev = -2;
269 #endif
271 #ifdef VMC
272 static int ethPrepareMcemu(base_game_info_t* game, config_set_t* configSet) {
273 char vmc[2][32];
274 char vmc_path[255];
275 u32 vmc_size;
276 int i, j, fd, size_mcemu_irx = 0;
277 smb_vmc_infos_t smb_vmc_infos;
278 vmc_superblock_t vmc_superblock;
280 configGetVMC(configSet, vmc[0], 0);
281 configGetVMC(configSet, vmc[1], 1);
283 for(i=0; i<2; i++) {
284 if(!vmc[i][0]) // skip if empty
285 continue;
287 memset(&smb_vmc_infos, 0, sizeof(smb_vmc_infos_t));
288 memset(&vmc_superblock, 0, sizeof(vmc_superblock_t));
290 snprintf(vmc_path, 255, "%s\\VMC\\%s.bin", ethPrefix, vmc[i]);
292 fd = fileXioOpen(vmc_path, O_RDONLY, 0666);
293 if (fd >= 0) {
294 size_mcemu_irx = -1;
295 LOG("%s open\n", vmc_path);
297 vmc_size = fileXioLseek(fd, 0, SEEK_END);
298 fileXioLseek(fd, 0, SEEK_SET);
299 fileXioRead(fd, (void*)&vmc_superblock, sizeof(vmc_superblock_t));
301 LOG("File size : 0x%X\n", vmc_size);
302 LOG("Magic : %s\n", vmc_superblock.magic);
303 LOG("Card type : %d\n", vmc_superblock.mc_type);
305 if(!strncmp(vmc_superblock.magic, "Sony PS2 Memory Card Format", 27) && vmc_superblock.mc_type == 0x2) {
306 smb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
307 smb_vmc_infos.flags |= 0x100;
308 smb_vmc_infos.specs.page_size = vmc_superblock.page_size;
309 smb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
310 smb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
312 LOG("flags : 0x%X\n", smb_vmc_infos.flags );
313 LOG("specs.page_size : 0x%X\n", smb_vmc_infos.specs.page_size );
314 LOG("specs.block_size : 0x%X\n", smb_vmc_infos.specs.block_size);
315 LOG("specs.card_size : 0x%X\n", smb_vmc_infos.specs.card_size );
317 if(vmc_size == smb_vmc_infos.specs.card_size * smb_vmc_infos.specs.page_size) {
318 smb_vmc_infos.active = 1;
319 smb_vmc_infos.fid = 0xFFFF;
320 snprintf(vmc_path, 255, "VMC\\%s.bin", vmc[i]);
321 strncpy(smb_vmc_infos.fname, vmc_path, 32); // maybe a too small size here ...
323 LOG("%s is a valid Vmc file\n", smb_vmc_infos.fname );
326 fileXioClose(fd);
328 for (j=0; j<size_smb_mcemu_irx; j++) {
329 if (((u32*)&smb_mcemu_irx)[j] == (0xC0DEFAC0 + i)) {
330 if(smb_vmc_infos.active)
331 size_mcemu_irx = size_smb_mcemu_irx;
332 memcpy(&((u32*)&smb_mcemu_irx)[j], &smb_vmc_infos, sizeof(smb_vmc_infos_t));
333 break;
337 return size_mcemu_irx;
339 #endif
341 static void ethLaunchGame(int id, config_set_t* configSet) {
342 int i, compatmask, size_irx = 0;
343 void** irx = NULL;
344 char isoname[32], filename[32];
345 base_game_info_t* game = &ethGames[id];
347 if (gRememberLastPlayed) {
348 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
349 saveConfig(CONFIG_LAST, 0);
352 if (sysPcmciaCheck()) {
353 size_irx = size_smb_pcmcia_cdvdman_irx;
354 irx = &smb_pcmcia_cdvdman_irx;
356 else {
357 size_irx = size_smb_cdvdman_irx;
358 irx = &smb_cdvdman_irx;
361 compatmask = sbPrepare(game, configSet, isoname, size_irx, irx, &i);
363 // For ISO we use the part table to store the "long" name (only for init)
364 if (game->isISO)
365 memcpy((void*)((u32)irx + i + 44), game->name, strlen(game->name) + 1);
367 for (i = 0; i < size_irx; i++) {
368 if (!strcmp((const char*)((u32)irx + i),"xxx.xxx.xxx.xxx")) {
369 break;
373 #ifdef VMC
374 int size_mcemu_irx = ethPrepareMcemu(game, configSet);
375 if (size_mcemu_irx == -1) {
376 if (guiMsgBox(_l(_STR_ERR_VMC_CONTINUE), 1, NULL))
377 size_mcemu_irx = 0;
378 else
379 return;
381 #endif
383 char config_str[255];
384 sprintf(config_str, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
385 memcpy((void*)((u32)irx + i), config_str, strlen(config_str) + 1);
386 memcpy((void*)((u32)irx + i + 16), &gPCPort, 4);
387 memcpy((void*)((u32)irx + i + 20), gPCShareName, 32);
388 memcpy((void*)((u32)irx + i + 56), gPCUserName, 32);
389 memcpy((void*)((u32)irx + i + 92), gPCPassword, 32);
391 // disconnect from the active SMB session
392 ethSMBDisconnect();
394 char *altStartup = NULL;
395 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
396 strncpy(filename, altStartup, 32);
397 else
398 sprintf(filename, "%s", game->startup);
399 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call ethCleanUp, so ethGames/game will be freed
400 FlushCache(0);
402 #ifdef VMC
403 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, size_mcemu_irx, &smb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
404 #else
405 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, compatmask, compatmask & COMPAT_MODE_1);
406 #endif
409 static config_set_t* ethGetConfig(int id) {
410 return sbPopulateConfig(&ethGames[id], ethPrefix, "\\");
413 static int ethGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
414 char path[255];
415 if (isRelative)
416 sprintf(path, "%s%s\\%s_%s", ethPrefix, folder, value, suffix);
417 else
418 sprintf(path, "%s%s_%s", folder, value, suffix);
419 return texDiscoverLoad(resultTex, path, -1, psm);
422 static void ethCleanUp(int exception) {
423 if (ethGameList.enabled) {
424 LOG("ethCleanUp()\n");
426 free(ethGames);
430 #ifdef VMC
431 static int ethCheckVMC(char* name, int createSize) {
432 return sysCheckVMC(ethPrefix, "\\", name, createSize);
434 #endif
436 static item_list_t ethGameList = {
437 ETH_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "ETH Games", _STR_NET_GAMES, &ethInit, &ethNeedsUpdate,
438 #ifdef __CHILDPROOF
439 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, NULL, NULL,
440 #else
441 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, &ethDeleteGame, &ethRenameGame,
442 #endif
443 #ifdef VMC
444 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, &ethCheckVMC, ETH_ICON
445 #else
446 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, ETH_ICON
447 #endif