fix for wrapping artefact when display_mode=ALWAYS
[open-ps2-loader.git] / src / ethsupport.c
blobbae87e911abd64a1c75c03ef5a8c6ea5ee9f0e85
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 gNetworkStartup = ERROR_ETH_NOT_STARTED;
198 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethLoadModules);
199 ethGameList.enabled = 1;
203 item_list_t* ethGetObject(int initOnly) {
204 if (initOnly && !ethGameList.enabled)
205 return NULL;
206 return &ethGameList;
209 static int ethNeedsUpdate(void) {
210 if (ethULSizePrev == -2)
211 return 1;
213 if (gNetworkStartup == 0) {
214 fio_stat_t stat;
215 char path[255];
217 sprintf(path, "%sCD", ethPrefix);
218 if (fioGetstat(path, &stat) != 0)
219 memset(stat.mtime, 0, 8);
220 if (memcmp(ethModifiedCDPrev, stat.mtime, 8)) {
221 memcpy(ethModifiedCDPrev, stat.mtime, 8);
222 return 1;
225 sprintf(path, "%sDVD", ethPrefix);
226 if (fioGetstat(path, &stat) != 0)
227 memset(stat.mtime, 0, 8);
228 if (memcmp(ethModifiedDVDPrev, stat.mtime, 8)) {
229 memcpy(ethModifiedDVDPrev, stat.mtime, 8);
230 return 1;
233 if (!sbIsSameSize(ethPrefix, ethULSizePrev))
234 return 1;
237 return 0;
240 static int ethUpdateGameList(void) {
241 if (gPCShareName[0]) {
242 if (gNetworkStartup != 0)
243 return 0;
245 sbReadList(&ethGames, ethPrefix, &ethULSizePrev, &ethGameCount);
246 } else {
247 int i, count;
248 ShareEntry_t sharelist[128] __attribute__((aligned(64)));
249 smbGetShareList_in_t getsharelist;
250 getsharelist.EE_addr = (void *)&sharelist[0];
251 getsharelist.maxent = 128;
253 count = fileXioDevctl(ethBase, SMB_DEVCTL_GETSHARELIST, (void *)&getsharelist, sizeof(getsharelist), NULL, 0);
254 if (count > 0) {
255 free(ethGames);
256 ethGames = (base_game_info_t*)malloc(sizeof(base_game_info_t) * count);
257 for (i = 0; i < count; i++) {
258 LOG("ETHSUPPORT Share found: %s\n", sharelist[i].ShareName);
259 base_game_info_t *g = &ethGames[i];
260 memcpy(g->name, sharelist[i].ShareName, 32);
261 g->name[31] = '\0';
262 sprintf(g->startup, "SHARE");
263 g->extension[0] = '\0';
264 g->parts = 0x00;
265 g->media = 0x00;
266 g->isISO = 0;
267 g->sizeMB = 0;
269 ethGameCount = count;
272 return ethGameCount;
275 static int ethGetGameCount(void) {
276 return ethGameCount;
279 static void* ethGetGame(int id) {
280 return (void*) &ethGames[id];
283 static char* ethGetGameName(int id) {
284 return ethGames[id].name;
287 static int ethGetGameNameLength(int id) {
288 if (ethGames[id].isISO)
289 return ISO_GAME_NAME_MAX + 1;
290 else
291 return UL_GAME_NAME_MAX + 1;
294 static char* ethGetGameStartup(int id) {
295 return ethGames[id].startup;
298 #ifndef __CHILDPROOF
299 static void ethDeleteGame(int id) {
300 sbDelete(&ethGames, ethPrefix, "\\", ethGameCount, id);
301 ethULSizePrev = -2;
304 static void ethRenameGame(int id, char* newName) {
305 sbRename(&ethGames, ethPrefix, "\\", ethGameCount, id, newName);
306 ethULSizePrev = -2;
308 #endif
310 static void ethLaunchGame(int id, config_set_t* configSet) {
311 int i, compatmask, size_irx = 0;
312 void** irx = NULL;
313 char filename[32];
314 base_game_info_t* game = &ethGames[id];
316 if (!gPCShareName[0]) {
317 memcpy(gPCShareName, game->name, 32);
318 ethULSizePrev = -2;
319 ethGameCount = 0;
320 ioPutRequest(IO_MENU_UPDATE_DEFFERED, &ethGameList.mode); // clear the share list
321 ioPutRequest(IO_CUSTOM_SIMPLEACTION, &ethInitSMB);
322 ioPutRequest(IO_MENU_UPDATE_DEFFERED, &ethGameList.mode); // reload the game list
323 return;
326 #ifdef VMC
327 char vmc_name[32];
328 int vmc_id, size_mcemu_irx = 0;
329 smb_vmc_infos_t smb_vmc_infos;
330 vmc_superblock_t vmc_superblock;
332 for (vmc_id = 0; vmc_id < 2; vmc_id++) {
333 memset(&smb_vmc_infos, 0, sizeof(smb_vmc_infos_t));
334 configGetVMC(configSet, vmc_name, vmc_id);
335 if (vmc_name[0]) {
336 if (sysCheckVMC(ethPrefix, "\\", vmc_name, 0, &vmc_superblock) > 0) {
337 smb_vmc_infos.flags = vmc_superblock.mc_flag & 0xFF;
338 smb_vmc_infos.flags |= 0x100;
339 smb_vmc_infos.specs.page_size = vmc_superblock.page_size;
340 smb_vmc_infos.specs.block_size = vmc_superblock.pages_per_block;
341 smb_vmc_infos.specs.card_size = vmc_superblock.pages_per_cluster * vmc_superblock.clusters_per_card;
342 smb_vmc_infos.active = 1;
343 smb_vmc_infos.fid = 0xFFFF;
344 if (gETHPrefix[0])
345 snprintf(smb_vmc_infos.fname, 64, "%s\\VMC\\%s.bin", gETHPrefix, vmc_name); // may still be too small size here ;) (should add 11 char !)
346 else
347 snprintf(smb_vmc_infos.fname, 64, "VMC\\%s.bin", vmc_name);
348 } else {
349 char error[255];
350 snprintf(error, 255, _l(_STR_ERR_VMC_CONTINUE), vmc_name, (vmc_id + 1));
351 if (!guiMsgBox(error, 1, NULL))
352 return;
356 for (i = 0; i < size_smb_mcemu_irx; i++) {
357 if (((u32*)&smb_mcemu_irx)[i] == (0xC0DEFAC0 + vmc_id)) {
358 if (smb_vmc_infos.active)
359 size_mcemu_irx = size_smb_mcemu_irx;
360 memcpy(&((u32*)&smb_mcemu_irx)[i], &smb_vmc_infos, sizeof(smb_vmc_infos_t));
361 break;
365 #endif
367 if (gRememberLastPlayed) {
368 configSetStr(configGetByType(CONFIG_LAST), "last_played", game->startup);
369 saveConfig(CONFIG_LAST, 0);
372 if (sysPcmciaCheck()) {
373 size_irx = size_smb_pcmcia_cdvdman_irx;
374 irx = &smb_pcmcia_cdvdman_irx;
376 else {
377 size_irx = size_smb_cdvdman_irx;
378 irx = &smb_cdvdman_irx;
381 compatmask = sbPrepare(game, configSet, size_irx, irx, &i);
383 // For ISO we use the part table to store the "long" name (only for init)
384 if (game->isISO) {
385 memcpy((void*)((u32)irx + i), game->extension, 5);
386 strcpy((void*)((u32)irx + i + 5), game->startup);
387 memcpy((void*)((u32)irx + i + 44), game->name, strlen(game->name) + 1);
388 } else {
389 sprintf(filename, "ul.%08X.%s", USBA_crc32(game->name), game->startup);
390 memcpy((void*)((u32)irx + i), filename, strlen(filename) + 1);
393 for (i = 0; i < size_irx; i++) {
394 if (!strcmp((const char*)((u32)irx + i),"xxx.xxx.xxx.xxx")) {
395 break;
399 char config_str[255];
400 sprintf(config_str, "%d.%d.%d.%d", pc_ip[0], pc_ip[1], pc_ip[2], pc_ip[3]);
401 memcpy((void*)((u32)irx + i), config_str, strlen(config_str) + 1);
402 memcpy((void*)((u32)irx + i + 16), &gPCPort, 4);
403 memcpy((void*)((u32)irx + i + 20), gPCShareName, 32);
404 memcpy((void*)((u32)irx + i + 52), gETHPrefix, 32);
405 memcpy((void*)((u32)irx + i + 84), gPCUserName, 16);
406 memcpy((void*)((u32)irx + i + 100), gPCPassword, 16);
408 // disconnect from the active SMB session
409 ethSMBDisconnect();
411 char *altStartup = NULL;
412 if (configGetStr(configSet, CONFIG_ITEM_ALTSTARTUP, &altStartup))
413 strncpy(filename, altStartup, 32);
414 else
415 sprintf(filename, "%s", game->startup);
416 shutdown(NO_EXCEPTION); // CAREFUL: shutdown will call ethCleanUp, so ethGames/game will be freed
417 FlushCache(0);
419 #ifdef VMC
420 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, size_mcemu_irx, &smb_mcemu_irx, compatmask, compatmask & COMPAT_MODE_1);
421 #else
422 sysLaunchLoaderElf(filename, "ETH_MODE", size_irx, irx, compatmask, compatmask & COMPAT_MODE_1);
423 #endif
426 static config_set_t* ethGetConfig(int id) {
427 return sbPopulateConfig(&ethGames[id], ethPrefix, "\\");
430 static int ethGetImage(char* folder, int isRelative, char* value, char* suffix, GSTEXTURE* resultTex, short psm) {
431 char path[255];
432 if (isRelative)
433 sprintf(path, "%s%s\\%s_%s", ethPrefix, folder, value, suffix);
434 else
435 sprintf(path, "%s%s_%s", folder, value, suffix);
436 return texDiscoverLoad(resultTex, path, -1, psm);
439 static void ethCleanUp(int exception) {
440 if (ethGameList.enabled) {
441 LOG("ETHSUPPORT CleanUp\n");
443 free(ethGames);
447 #ifdef VMC
448 static int ethCheckVMC(char* name, int createSize) {
449 return sysCheckVMC(ethPrefix, "\\", name, createSize, NULL);
451 #endif
453 static item_list_t ethGameList = {
454 ETH_MODE, 0, COMPAT, 0, MENU_MIN_INACTIVE_FRAMES, "ETH Games", _STR_NET_GAMES, &ethInit, &ethNeedsUpdate,
455 #ifdef __CHILDPROOF
456 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, NULL, NULL,
457 #else
458 &ethUpdateGameList, &ethGetGameCount, &ethGetGame, &ethGetGameName, &ethGetGameNameLength, &ethGetGameStartup, &ethDeleteGame, &ethRenameGame,
459 #endif
460 #ifdef VMC
461 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, &ethCheckVMC, ETH_ICON
462 #else
463 &ethLaunchGame, &ethGetConfig, &ethGetImage, &ethCleanUp, ETH_ICON
464 #endif