about summary refs log tree commit diff stats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/main.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..afe3423 --- /dev/null +++ b/source/main.c
@@ -0,0 +1,400 @@
1/*
2 * Copyright (C) 2016 FIX94
3 *
4 * This software may be modified and distributed under the terms
5 * of the MIT license. See the LICENSE file for details.
6 */
7#include <gccore.h>
8#include <stdio.h>
9#include <malloc.h>
10#include <unistd.h>
11#include <string.h>
12#include <stdlib.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <fcntl.h>
16#include <dirent.h>
17#include <fat.h>
18
19extern u8 gba_mb_gba[];
20extern u32 gba_mb_gba_size;
21
22void printmain()
23{
24 printf("\x1b[2J");
25 printf("\x1b[37m");
26 printf("GBA Link Cable Dumper v1.0 by FIX94\n");
27}
28
29u8 *resbuf,*cmdbuf;
30volatile u16 pads = 0;
31volatile bool ctrlerr = false;
32void ctrlcb(s32 chan, u32 ret)
33{
34 if(ret)
35 {
36 ctrlerr = true;
37 return;
38 }
39 //just call us again
40 pads = (~((resbuf[1]<<8)|resbuf[0]))&0x3FF;
41 SI_Transfer(1,cmdbuf,1,resbuf,5,ctrlcb,350);
42}
43
44volatile u32 transval = 0;
45void transcb(s32 chan, u32 ret)
46{
47 transval = 1;
48}
49
50volatile u32 resval = 0;
51void acb(s32 res, u32 val)
52{
53 resval = val;
54}
55
56unsigned int docrc(u32 crc, u32 val)
57{
58 int i;
59 for(i = 0; i < 0x20; i++)
60 {
61 if((crc^val)&1)
62 {
63 crc>>=1;
64 crc^=0xa1c1;
65 }
66 else
67 crc>>=1;
68 val>>=1;
69 }
70 return crc;
71}
72
73static inline void wait_for_transfer()
74{
75 //350 is REALLY pushing it already, cant go further
76 do{ usleep(350); }while(transval == 0);
77}
78
79void endproc()
80{
81 printf("Start pressed, exit\n");
82 VIDEO_WaitVSync();
83 VIDEO_WaitVSync();
84 exit(0);
85}
86unsigned int calckey(unsigned int size)
87{
88 unsigned int ret = 0;
89 size=(size-0x200) >> 3;
90 int res1 = (size&0x3F80) << 1;
91 res1 |= (size&0x4000) << 2;
92 res1 |= (size&0x7F);
93 res1 |= 0x380000;
94 int res2 = res1;
95 res1 = res2 >> 0x10;
96 int res3 = res2 >> 8;
97 res3 += res1;
98 res3 += res2;
99 res3 <<= 24;
100 res3 |= res2;
101 res3 |= 0x80808080;
102
103 if((res3&0x200) == 0)
104 {
105 ret |= (((res3)&0xFF)^0x4B)<<24;
106 ret |= (((res3>>8)&0xFF)^0x61)<<16;
107 ret |= (((res3>>16)&0xFF)^0x77)<<8;
108 ret |= (((res3>>24)&0xFF)^0x61);
109 }
110 else
111 {
112 ret |= (((res3)&0xFF)^0x73)<<24;
113 ret |= (((res3>>8)&0xFF)^0x65)<<16;
114 ret |= (((res3>>16)&0xFF)^0x64)<<8;
115 ret |= (((res3>>24)&0xFF)^0x6F);
116 }
117 return ret;
118}
119void doreset()
120{
121 cmdbuf[0] = 0xFF; //reset
122 transval = 0;
123 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,0);
124 wait_for_transfer();
125}
126void getstatus()
127{
128 cmdbuf[0] = 0; //status
129 transval = 0;
130 SI_Transfer(1,cmdbuf,1,resbuf,3,transcb,0);
131 wait_for_transfer();
132}
133u32 recvsafe()
134{
135 memset(resbuf,0,32);
136 cmdbuf[0]=0x14; //read
137 transval = 0;
138 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,0);
139 wait_for_transfer();
140 return *(vu32*)resbuf;
141}
142void sendsafe(u32 msg)
143{
144 cmdbuf[0]=0x15;cmdbuf[1]=(msg>>0)&0xFF;cmdbuf[2]=(msg>>8)&0xFF;
145 cmdbuf[3]=(msg>>16)&0xFF;cmdbuf[4]=(msg>>24)&0xFF;
146 transval = 0;
147 resbuf[0] = 0;
148 SI_Transfer(1,cmdbuf,5,resbuf,1,transcb,0);
149 wait_for_transfer();
150}
151u32 recvfast()
152{
153 cmdbuf[0]=0x14; //read
154 transval = 0;
155 SI_Transfer(1,cmdbuf,1,resbuf,5,transcb,0);
156 usleep(275);
157 while(transval == 0) ;
158 return *(vu32*)resbuf;
159}
160bool dirExists(const char *path)
161{
162 DIR *dir;
163 dir = opendir(path);
164 if(dir)
165 {
166 closedir(dir);
167 return true;
168 }
169 return false;
170}
171int main(int argc, char *argv[])
172{
173 void *xfb = NULL;
174 GXRModeObj *rmode = NULL;
175 VIDEO_Init();
176 rmode = VIDEO_GetPreferredMode(NULL);
177 xfb = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
178 VIDEO_Configure(rmode);
179 VIDEO_SetNextFramebuffer(xfb);
180 VIDEO_SetBlack(FALSE);
181 VIDEO_Flush();
182 VIDEO_WaitVSync();
183 if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
184 int x = 24, y = 32, w, h;
185 w = rmode->fbWidth - (32);
186 h = rmode->xfbHeight - (48);
187 CON_InitEx(rmode, x, y, w, h);
188 VIDEO_ClearFrameBuffer(rmode, xfb, COLOR_BLACK);
189 PAD_Init();
190 cmdbuf = memalign(32,32);
191 resbuf = memalign(32,32);
192 u8 *testdump = memalign(32,0x400000);
193 if(!testdump) return 0;
194 if(!fatInitDefault())
195 {
196 printmain();
197 printf("ERROR: No usable device found to write dumped files to!\n");
198 VIDEO_WaitVSync();
199 VIDEO_WaitVSync();
200 sleep(5);
201 exit(0);
202 }
203 mkdir("/dumps", S_IREAD | S_IWRITE);
204 if(!dirExists("/dumps"))
205 {
206 printmain();
207 printf("ERROR: Could not create dumps folder, make sure you have a supported device connected!\n");
208 VIDEO_WaitVSync();
209 VIDEO_WaitVSync();
210 sleep(5);
211 exit(0);
212 }
213 int i;
214 while(1)
215 {
216 printmain();
217 printf("Waiting for a GBA in port 2...\n");
218 resval = 0;
219 ctrlerr = false;
220
221 SI_GetTypeAsync(1,acb);
222 while(1)
223 {
224 if(resval)
225 {
226 if(resval == 0x80 || resval & 8)
227 {
228 resval = 0;
229 SI_GetTypeAsync(1,acb);
230 }
231 else if(resval)
232 break;
233 }
234 PAD_ScanPads();
235 VIDEO_WaitVSync();
236 if(PAD_ButtonsHeld(0))
237 endproc();
238 }
239 if(resval & SI_GBA)
240 {
241 printf("GBA Found! Waiting on BIOS\n");
242 resbuf[2]=0;
243 while(!(resbuf[2]&0x10))
244 {
245 doreset();
246 getstatus();
247 }
248 printf("Ready, sending dumper\n");
249 unsigned int sendsize = ((gba_mb_gba_size+7)&~7);
250 unsigned int ourkey = calckey(sendsize);
251 //printf("Our Key: %08x\n", ourkey);
252 //get current sessionkey
253 u32 sessionkeyraw = recvsafe();
254 u32 sessionkey = __builtin_bswap32(sessionkeyraw^0x7365646F);
255 //send over our own key
256 sendsafe(__builtin_bswap32(ourkey));
257 unsigned int fcrc = 0x15a0;
258 //send over gba header
259 for(i = 0; i < 0xC0; i+=4)
260 {
261 sendsafe(__builtin_bswap32(*(vu32*)(gba_mb_gba+i)));
262 if(!(resbuf[0]&0x2)) printf("Possible error %02x\n",resbuf[0]);
263 }
264 //printf("Header done! Sending ROM...\n");
265 for(i = 0xC0; i < sendsize; i+=4)
266 {
267 u32 enc = ((gba_mb_gba[i+3]<<24)|(gba_mb_gba[i+2]<<16)|(gba_mb_gba[i+1]<<8)|(gba_mb_gba[i]));
268 fcrc=docrc(fcrc,enc);
269 sessionkey = (sessionkey*0x6177614B)+1;
270 enc^=sessionkey;
271 enc^=((~(i+(0x20<<20)))+1);
272 enc^=0x20796220;
273 sendsafe(enc);
274 if(!(resbuf[0]&0x2)) printf("Possible error %02x\n",resbuf[0]);
275 }
276 fcrc |= (sendsize<<16);
277 //printf("ROM done! CRC: %08x\n", fcrc);
278 //send over CRC
279 sessionkey = (sessionkey*0x6177614B)+1;
280 fcrc^=sessionkey;
281 fcrc^=((~(i+(0x20<<20)))+1);
282 fcrc^=0x20796220;
283 sendsafe(fcrc);
284 //get crc back (unused)
285 recvsafe();
286 printf("Done!\n");
287 sleep(2);
288 //hm
289 while(1)
290 {
291 printmain();
292 printf("Press A once you have a GBA Game inserted.\n \n");
293 PAD_ScanPads();
294 VIDEO_WaitVSync();
295 u32 btns = PAD_ButtonsDown(0);
296 if(btns&PAD_BUTTON_START)
297 endproc();
298 else if(btns&PAD_BUTTON_A)
299 {
300 if(recvsafe() == 0) //ready
301 {
302 sleep(1); //gba rom prepare
303 u32 gbasize = __builtin_bswap32(recvsafe());
304 if(gbasize == 0)
305 {
306 printf("ERROR: No (Valid) GBA Card inserted!\n");
307 VIDEO_WaitVSync();
308 VIDEO_WaitVSync();
309 sleep(2);
310 continue;
311 }
312 for(i = 0; i < 0xC0; i+=4)
313 *(vu32*)(testdump+i) = recvfast();
314 printf("Game Name: %.12s\n",(char*)(testdump+0xA0));
315 printf("Game ID: %.4s\n",(char*)(testdump+0xAC));
316 printf("Company ID: %.2s\n",(char*)(testdump+0xB0));
317 printf("ROM Size: %02.02f MB\n \n",((float)(gbasize/1024))/1024.f);
318 char gamename[64];
319 sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba",
320 (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0));
321 FILE *f = fopen(gamename,"rb");
322 if(f)
323 {
324 fclose(f);
325 sendsafe(0);
326 printf("ERROR: Game already dumped! Please insert another game.\n");
327 VIDEO_WaitVSync();
328 VIDEO_WaitVSync();
329 sleep(2);
330 continue;
331 }
332 printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2);
333 printf("Press B if you want to cancel dumping this game.\n\n");
334 int dumping = 0;
335 while(1)
336 {
337 PAD_ScanPads();
338 VIDEO_WaitVSync();
339 u32 btns = PAD_ButtonsDown(0);
340 if(btns&PAD_BUTTON_START)
341 endproc();
342 else if(btns&PAD_BUTTON_A)
343 {
344 dumping = 1;
345 break;
346 }
347 else if(btns&PAD_BUTTON_B)
348 break;
349 }
350 sendsafe(dumping);
351 if(dumping == 0)
352 continue;
353 //create base file with size
354 printf("Creating file...\n");
355 int fd = open(gamename, O_WRONLY|O_CREAT);
356 if(fd >= 0)
357 {
358 ftruncate(fd, gbasize);
359 close(fd);
360 }
361 f = fopen(gamename,"wb");
362 if(!f)
363 {
364 printf("ERROR: Could not create file! Exit...\n");
365 VIDEO_WaitVSync();
366 VIDEO_WaitVSync();
367 sleep(5);
368 exit(0);
369 }
370 printf("Dumping...\n");
371 u32 bytes_read = 0;
372 while(gbasize > 0)
373 {
374 int toread = (gbasize > 0x400000 ? 0x400000 : gbasize);
375 int j;
376 for(j = 0; j < toread; j+=4)
377 {
378 *(vu32*)(testdump+j) = recvfast();
379 bytes_read+=4;
380 if((bytes_read&0xFFFF) == 0)
381 {
382 printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f);
383 VIDEO_WaitVSync();
384 }
385 //printf("%02x%02x%02x%02x",resbuf[0],resbuf[1],resbuf[2],resbuf[3]);
386 }
387 fwrite(testdump,toread,1,f);
388 gbasize -= toread;
389 }
390 printf("\nClosing file\n");
391 fclose(f);
392 printf("Game dumped!\n");
393 sleep(5);
394 }
395 }
396 }
397 }
398 }
399 return 0;
400}