Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / src / ethsupport.c
blob07fa17ff809e0debdd836c7a9e7c347d002bce32
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[40];
39 static char* ethBase;
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 void ethSMBConnect(void) {
50 smbLogOn_in_t logon;
51 smbEcho_in_t echo;
52 smbOpenShare_in_t openshare;
54 if (gETHPrefix[0] != '\0')
55 sprintf(ethPrefix, "%s%s\\", ethBase, gETHPrefix);
56 else
57 sprintf(ethPrefix, ethBase);
59 // open tcp connection with the server / logon to SMB server
60 sprintf(logon.serverIP, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
61 logon.serverPort = gPCPort;
63 if (strlen(gPCPassword) > 0) {
64 smbGetPasswordHashes_in_t passwd;
65 smbGetPasswordHashes_out_t passwdhashes;
67 // we'll try to generate hashed password first
68 strncpy(logon.User, gPCUserName, 32);
69 strncpy(passwd.password, gPCPassword, 32);
71 if (fileXioDevctl(ethBase, SMB_DEVCTL_GETPASSWORDHASHES, (void *)&passwd, sizeof(passwd), (void *)&passwdhashes, sizeof(passwdhashes)) == 0) {
72 // hash generated okay, can use
73 memcpy((void *)logon.Password, (void *)&passwdhashes, sizeof(passwdhashes));
74 logon.PasswordType = HASHED_PASSWORD;
75 memcpy((void *)openshare.Password, (void *)&passwdhashes, sizeof(passwdhashes));
76 openshare.PasswordType = HASHED_PASSWORD;
77 } else {
78 // failed hashing, failback to plaintext
79 strncpy(logon.Password, gPCPassword, 32);
80 logon.PasswordType = PLAINTEXT_PASSWORD;
81 strncpy(openshare.Password, gPCPassword, 32);
82 openshare.PasswordType = PLAINTEXT_PASSWORD;
84 } else {
85 strncpy(logon.User, gPCUserName, 32);
86 logon.PasswordType = NO_PASSWORD;
87 openshare.PasswordType = NO_PASSWORD;
90 gNetworkStartup = ERROR_ETH_SMB_LOGON;
91 if (fileXioDevctl(ethBase, SMB_DEVCTL_LOGON, (void *)&logon, sizeof(logon), NULL, 0) >= 0) {
92 gNetworkStartup = ERROR_ETH_SMB_ECHO;
94 // SMB server alive test
95 strcpy(echo.echo, "ALIVE ECHO TEST");
96 echo.len = strlen("ALIVE ECHO TEST");
98 if (fileXioDevctl(ethBase, SMB_DEVCTL_ECHO, (void *)&echo, sizeof(echo), NULL, 0) >= 0) {
99 gNetworkStartup = ERROR_ETH_SMB_OPENSHARE;
101 if (gPCShareName[0]) {
102 // connect to the share
103 strcpy(openshare.ShareName, gPCShareName);
105 if (fileXioDevctl(ethBase, SMB_DEVCTL_OPENSHARE, (void *)&openshare, sizeof(openshare), NULL, 0) >= 0) {
107 // everything is ok
108 gNetworkStartup = 0;
115 int ethSMBDisconnect(void) {
116 int ret;
118 // closing share
119 ret = fileXioDevctl(ethBase, SMB_DEVCTL_CLOSESHARE, NULL, 0, NULL, 0);
120 if (ret < 0)
121 return -1;
123 // logoff/close tcp connection from SMB server:
124 ret = fileXioDevctl(ethBase, SMB_DEVCTL_LOGOFF, NULL, 0, NULL, 0);
125 if (ret < 0)
126 return -2;
128 return 0;
131 static void ethInitSMB(void) {
132 // connect
133 ethSMBConnect();
135 if (gNetworkStartup == 0) {
136 // update Themes
137 char path[255];
138 sprintf(path, "%sTHM", ethPrefix);
139 thmAddElements(path, "\\", ethGameList.mode);
141 sprintf(path, "%sCFG", ethPrefix);
142 checkCreateDir(path);
144 #ifdef VMC
145 sprintf(path, "%sVMC", ethPrefix);
146 checkCreateDir(path);
147 #endif
148 } else if (gPCShareName[0] || !(gNetworkStartup >= ERROR_ETH_SMB_OPENSHARE))
149 setErrorMessage(_STR_NETWORK_STARTUP_ERROR, gNetworkStartup);
152 static void ethLoadModules(void) {
153 int ipconfiglen;
154 char ipconfig[IPCONFIG_MAX_LEN] __attribute__((aligned(64)));
156 LOG("ETHSUPPORT LoadModules\n");
158 ipconfiglen = sysSetIPConfig(ipconfig);
160 gNetworkStartup = ERROR_ETH_MODULE_PS2DEV9_FAILURE;
161 if (sysLoadModuleBuffer(&ps2dev9_irx, size_ps2dev9_irx, 0, NULL) >= 0) {
162 gNetworkStartup = ERROR_ETH_MODULE_SMSUTILS_FAILURE;
163 if (sysLoadModuleBuffer(&smsutils_irx, size_smsutils_irx, 0, NULL) >= 0) {
164 gNetworkStartup = ERROR_ETH_MODULE_SMSTCPIP_FAILURE;
165 if (sysLoadModuleBuffer(&smstcpip_irx, size_smstcpip_irx, 0, NULL) >= 0) {
166 gNetworkStartup = ERROR_ETH_MODULE_SMSMAP_FAILURE;
167 if (sysLoadModuleBuffer(&smsmap_irx, size_smsmap_irx, ipconfiglen, ipconfig) >= 0) {
168 gNetworkStartup = ERROR_ETH_MODULE_SMBMAN_FAILURE;
169 if (sysLoadModuleBuffer(&smbman_irx, size_smbman_irx, 0, NULL) >= 0) {
170 LOG("ETHSUPPORT Modules loaded\n");
171 ethInitSMB();
172 return;
179 setErrorMessage(_STR_NETWORK_STARTUP_ERROR, gNetworkStartup);
182 void ethInit(void) {
183 if (gNetworkStartup >= ERROR_ETH_SMB_LOGON) {
184 LOG("ETHSUPPORT Re-Init\n");
185 thmReinit(ethBase);
186 ethULSizePrev = -2;
187 ethGameCount = 0;
188 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethInitSMB);
189 } else {
190 LOG("ETHSUPPORT Init\n");
191 ethBase = "smb0:";
192 ethULSizePrev = -2;
193 memset(ethModifiedCDPrev, 0, 8);
194 memset(ethModifiedDVDPrev, 0, 8);
195 ethGameCount = 0;
196 ethGames = NULL;
197 configGetInt(configGetByType(CONFIG_OPL), "eth_frames_delay", &ethGameList.delay);
198 gNetworkStartup = ERROR_ETH_NOT_STARTED;
199 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethLoadModules);
200 ethGameList.enabled = 1;
204 item_list_t* ethGetObject(int initOnly) {
205 if (initOnly && !ethGameList.enabled)
206 return NULL;
207 return &ethGameList;
210 static int ethNeedsUpdate(void) {
211 if (ethULSizePrev == -2)
212 return 1;
214 if (gNetworkStartup == 0) {
215 fio_stat_t stat;
216 char path[255];
218 sprintf(path, "%sCD", ethPrefix);
219 if (fioGetstat(path, &stat) != 0)
220 memset(stat.mtime, 0, 8);
221 if (memcmp(ethModifiedCDPrev, stat.mtime, 8)) {
222 memcpy(ethModifiedCDPrev, stat.mtime, 8);
223 return 1;
226 sprintf(path, "%sDVD", ethPrefix);
227 if (fioGetstat(path, &stat) != 0)
228 memset(stat.mtime, 0, 8);
229 if (memcmp(ethModifiedDVDPrev, stat.mtime, 8)) {
230 memcpy(ethModifiedDVDPrev, stat.mtime, 8);
231 return 1;
234 if (!sbIsSameSize(ethPrefix, ethULSizePrev))
235 return 1;
238 return 0;
241 static int ethUpdateGameList(void) {
242 if (gPCShareName[0]) {
243 if (gNetworkStartup != 0)
244 return 0;
246 sbReadList(&ethGames, ethPrefix, &ethULSizePrev, &ethGameCount);
247 } else {
248 int i, count;
249 ShareEntry_t sharelist[128] __attribute__((aligned(64)));
250 smbGetShareList_in_t getsharelist;
251 getsharelist.EE_addr = (void *)&sharelist[0];
252 getsharelist.maxent = 128;
254 count = fileXioDevctl(ethBase, SMB_DEVCTL_GETSHARELIST, (void *)&getsharelist, sizeof(getsharelist), NULL, 0);
255 if (count > 0) {
256 free(ethGames);
257 ethGames = (base_game_info_t*)malloc(sizeof(base_game_info_t) * count);
258 for (i = 0; i < count; i++) {
259 LOG("ETHSUPPORT Share found: %s\n", sharelist[i].ShareName);
260 base_game_info_t *g = &ethGames[i];
261 memcpy(g->name, sharelist[i].ShareName, 32);
262 g->name[31] = '\0';
263 sprintf(g->startup, "SHARE");
264 g->extension[0] = '\0';
265 g->parts = 0x00;
266 g->media = 0x00;
267 g->isISO = 0;
268 g->sizeMB = 0;
270 ethGameCount = count;
273 return ethGameCount;
276 static int ethGetGameCount(void) {
277 return ethGameCount;
280 static void* ethGetGame(int id) {
281 return (void*) &ethGames[id];
284 static char* ethGetGameName(int id) {
285 return ethGames[id].name;
288 static int ethGetGameNameLength(int id) {
289 if (ethGames[id].isISO)
290 return ISO_GAME_NAME_MAX + 1;
291 else
292 return UL_GAME_NAME_MAX + 1;
295 static char* ethGetGameStartup(int id) {
296 return ethGames[id].startup;
299 #ifndef __CHILDPROOF
300 static void ethDeleteGame(int id) {
301 sbDelete(&ethGames, ethPrefix, "\\", ethGameCount, id);
302 ethULSizePrev = -2;
305 static void ethRenameGame(int id, char* newName) {
306 sbRename(&ethGames, ethPrefix, "\\", ethGameCount, id, newName);
307 ethULSizePrev = -2;
309 #endif
311 static void ethLaunchGame(int id, config_set_t* configSet) {
312 int i, compatmask, size_irx = 0;
313 void** irx = NULL;
314 char filename[32];
315 base_game_info_t* game = &ethGames[id];
317 if (!gPCShareName[0]) {
318 memcpy(gPCShareName, game->name, 32);
319 ethULSizePrev = -2;
320 ethGameCount = 0;
321 ioPutRequest(IO_MENU_UPDATE_DEFFERED, &ethGameList.mode); // clear the share list
322 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethInitSMB);
323 ioPutRequest(IO_MENU_UPDATE_DEFFERED, &ethGameList.mode); // reload the game list
324 return;
327 #ifdef VMC
328 char vmc_name[32];
329 int vmc_id, size_mcemu_irx = 0;
330 smb_vmc_infos_t smb_vmc_infos;
331 vmc_superblock_t vmc_superblock;
333 for (vmc_id = 0; vmc_id < 2; vmc_id++) {
334 memset(&smb_vmc_infos, 0, sizeof(smb_vmc_infos_t));
335 configGetVMC(configSet, vmc_name, vmc_id);
336 if (vmc_name[0]) {
337 if (sysCheckVMC(ethPrefix, "\\", vmc_name, 0, &vmc_superblock) > 0) {
338 smb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
339 smb_vmc_infos.flags |= 0x100;
340 smb_vmc_infos.specs.page_size = vmc_superblock.page_size;
341 smb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
342 smb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
343 smb_vmc_infos.active = 1;
344 smb_vmc_infos.fid = 0xFFFF;
345 if (gETHPrefix[0])
346 snprintf(smb_vmc_infos.fname, 64, "%s\\VMC\\%s.bin", gETHPrefix, vmc_name); // may still be too small size here ;) (should add 11 char !)
347 else
348 snprintf(smb_vmc_infos.fname, 64, "VMC\\%s.bin", vmc_name);
349 } else {
350 char error[255];
351 snprintf(error, 255, _l(_STR_ERR_VMC_CONTINUE), vmc_name, (vmc_id + 1));
352 if (!guiMsgBox(error, 1, NULL))
353 return;
357 for (i = 0; i < size_smb_mcemu_irx; i++) {
358 if (((u32*)&smb_mcemu_irx)[i] == (0xC0DEFAC0 + vmc_id)) {
359 if (smb_vmc_infos.active)
360 size_mcemu_irx = size_smb_mcemu_irx;
361 memcpy(&((u32*)&smb_mcemu_irx)[i], &smb_vmc_infos, sizeof(smb_vmc_infos_t));
362 break;
366 #endif
368 if (gRememberLastPlayed) {
369 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
370 saveConfig(CONFIG_LAST, 0);
373 if (sysPcmciaCheck()) {
374 size_irx = size_smb_pcmcia_cdvdman_irx;
375 irx = &smb_pcmcia_cdvdman_irx;
377 else {
378 size_irx = size_smb_cdvdman_irx;
379 irx = &smb_cdvdman_irx;
382 compatmask = sbPrepare(game, configSet, size_irx, irx, &i);
384 // For ISO we use the part table to store the "long" name (only for init)
385 if (game->isISO) {
386 memcpy((void*)((u32)irx + i), game->extension, 5);
387 strcpy((void*)((u32)irx + i + 5), game->startup);
388 memcpy((void*)((u32)irx + i + 44), game->name, strlen(game->name) + 1);
389 } else {
390 sprintf(filename, "ul.%08X.%s", USBA_crc32(game->name), game->startup);
391 memcpy((void*)((u32)irx + i), filename, strlen(filename) + 1);
394 for (i = 0; i < size_irx; i++) {
395 if (!strcmp((const char*)((u32)irx + i),"xxx.xxx.xxx.xxx")) {
396 break;
400 char config_str[255];
401 sprintf(config_str, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
402 memcpy((void*)((u32)irx + i), config_str, strlen(config_str) + 1);
403 memcpy((void*)((u32)irx + i + 16), &gPCPort, 4);
404 memcpy((void*)((u32)irx + i + 20), gPCShareName, 32);
405 memcpy((void*)((u32)irx + i + 52), gETHPrefix, 32);
406 memcpy((void*)((u32)irx + i + 84), gPCUserName, 16);
407 memcpy((void*)((u32)irx + i + 100), gPCPassword, 16);
409 // disconnect from the active SMB session
410 ethSMBDisconnect();
412 char *altStartup = NULL;
413 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
414 strncpy(filename, altStartup, 32);
415 else
416 sprintf(filename, "%s", game->startup);
417 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call ethCleanUp, so ethGames/game will be freed
418 FlushCache(0);
420 #ifdef VMC
421 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, size_mcemu_irx, &smb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
422 #else
423 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, compatmask, compatmask & COMPAT_MODE_1);
424 #endif
427 static config_set_t* ethGetConfig(int id) {
428 return sbPopulateConfig(&ethGames[id], ethPrefix, "\\");
431 static int ethGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
432 char path[255];
433 if (isRelative)
434 sprintf(path, "%s%s\\%s_%s", ethPrefix, folder, value, suffix);
435 else
436 sprintf(path, "%s%s_%s", folder, value, suffix);
437 return texDiscoverLoad(resultTex, path, -1, psm);
440 static void ethCleanUp(int exception) {
441 if (ethGameList.enabled) {
442 LOG("ETHSUPPORT CleanUp\n");
444 free(ethGames);
448 #ifdef VMC
449 static int ethCheckVMC(char* name, int createSize) {
450 return sysCheckVMC(ethPrefix, "\\", name, createSize, NULL);
452 #endif
454 static item_list_t ethGameList = {
455 ETH_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "ETH Games", _STR_NET_GAMES, &ethInit, &ethNeedsUpdate,
456 #ifdef __CHILDPROOF
457 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, NULL, NULL,
458 #else
459 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, &ethDeleteGame, &ethRenameGame,
460 #endif
461 #ifdef VMC
462 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, &ethCheckVMC, ETH_ICON
463 #else
464 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, ETH_ICON
465 #endif