mode thing affects not only saves
[megadrive.git] / mx / linux / main.c
CommitLineData
baaf865c 1/* FIXME: RAM odd */
8c8e818c 2#include <stdio.h>
726b85c8 3#include <string.h>
8c8e818c 4#include <usb.h>
5
6
7typedef unsigned char u8;
8typedef unsigned short u16;
9typedef unsigned int u32;
10#define array_size(x) (sizeof(x) / sizeof(x[0]))
11
12static const struct {
13 unsigned short vendor;
14 unsigned short product;
15 const char *name;
16} g_devices[] = {
17 { 0x03eb, 0x202a, "16MX+U Game Device" },
18 { 0x03eb, 0x202b, "32MX+U Game Device" },
19 { 0x03eb, 0x202c, "16MX+US Game Device" },
20 { 0x03eb, 0x202d, "32MX+UF Game Device" },
21};
22
ed354cee 23#define VERSION "0.8"
24
25#define IO_BLK_SIZE 0x2000 /* 8K */
c9d375d5 26#define IO_RAM_BLK_SIZE 256
8c8e818c 27
fb4ee110 28#define CMD_ATM_READY 0x22
a35471cd 29#define CMD_SEC_GET_NAME 'G' /* filename r/w */
30#define CMD_SEC_PUT_NAME 'P'
31#define CMD_SEC_DEVID 'L' /* read flash device ID */
32#define CMD_SEC_ERASE 'E'
33#define CMD_SEC_READY 'C' /* is flash ready? */
6ddaf67a 34#define CMD_SEC_READ 'R'
ed354cee 35#define CMD_SEC_WRITE 'W'
baaf865c 36#define CMD_SEC_RAM_READ 'D' /* not implemented? */
c9d375d5 37#define CMD_SEC_RAM_WRITE 'U'
baaf865c 38#define CMD_SEC_COMPAT '$' /* set RAM mode */
726b85c8 39
fb4ee110 40/* bus controllers */
41#define CTL_DATA_BUS 0x55
42#define CTL_ADDR_BUS 0xAA
43
a35471cd 44#define W_COUNTER 0xA0
45#define W_CNT_WRITE 0x01
46#define W_CNT_READ 0x00
47
fb4ee110 48#define FILENAME_ROM0 0
49#define FILENAME_ROM1 1
50#define FILENAME_RAM 2
726b85c8 51
baaf865c 52/* windows app sets to 0x80 on init
53 * checkboxes use 0x41 0x42 0x43 (?)
54 * r,w Ram/ROM uses 0x23/0x21
55 */
95122097 56#define C_MODE_4M_NORAM 0x41 /* RAM always off */
57#define C_MODE_4M_RAM 0x42 /* RAM switched by game */
58#define C_MODE_2M_RAM 0x43
92cfb386 59#define C_RAM_TMP_OFF 0x21
60#define C_RAM_TMP_ON 0x23
baaf865c 61
726b85c8 62typedef struct {
8c8e818c 63 u8 magic[4];
a35471cd 64 u8 reserved[8];
65 u8 write_flag;
66 u8 reserved2[2];
8c8e818c 67 u8 magic2;
68 u8 mx_cmd;
6ddaf67a 69 union { /* 0x11 */
8c8e818c 70 struct {
71 u8 which_device;
8c8e818c 72 } dev_info;
73 struct {
ed354cee 74 u8 addrb2; /* most significant (BE) */
8c8e818c 75 u8 addrb1;
76 u8 addrb0;
ed354cee 77 u8 param; /* 64 byte usb packets for i/o */
78 u8 param2;
8c8e818c 79 } rom_rw;
80 struct {
fb4ee110 81 u8 which;
baaf865c 82 } filename, mode;
8c8e818c 83 struct {
a35471cd 84 u8 cmd;
8c8e818c 85 u8 action;
ed354cee 86 u8 b0; /* LE */
a35471cd 87 u8 b1;
88 u8 b2;
89 u8 b3;
90 } write_cnt;
91 struct {
92 u8 which;
93 u8 dev_id;
94 } rom_id;
8c8e818c 95 };
96 u8 pad[8];
726b85c8 97} dev_cmd_t;
98
99typedef struct {
100 u8 firmware_ver[4];
101 u8 bootloader_ver[4];
102 char names[56];
103} dev_info_t;
104
a35471cd 105typedef struct {
106 u32 start_addr;
107 u32 end_addr;
108 u32 page_size;
109} page_table_t;
110
111static const page_table_t p_AM29LV320DB[] =
112{
113 { 0x000000, 0x00ffff, 0x002000 },
114 { 0x010000, 0x3fffff, 0x010000 },
115 { 0x000000, 0x000000, 0x000000 },
116};
117
118static const page_table_t p_AM29LV320DT[] =
119{
120 { 0x000000, 0x3effff, 0x010000 },
121 { 0x3f0000, 0x3fffff, 0x002000 },
122 { 0x000000, 0x000000, 0x000000 },
123};
124
6ddaf67a 125static const page_table_t p_2x_16[] =
126{
127 { 0x000000, 0x003fff, 0x004000 },
128 { 0x004000, 0x007fff, 0x002000 },
129 { 0x008000, 0x00ffff, 0x008000 },
130 { 0x010000, 0x1fffff, 0x010000 },
131 { 0x200000, 0x203fff, 0x004000 },
132 { 0x204000, 0x207fff, 0x002000 },
133 { 0x208000, 0x20ffff, 0x008000 },
134 { 0x210000, 0x3fffff, 0x010000 },
135 { 0x000000, 0x000000, 0x000000 },
136};
137
a35471cd 138/*****************************************************************************/
139
726b85c8 140static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd)
141{
142 memset(dev_cmd, 0, sizeof(*dev_cmd));
143
144 memcpy(dev_cmd->magic, "USBC", 4);
fb4ee110 145 dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
726b85c8 146 dev_cmd->mx_cmd = cmd;
147}
148
a35471cd 149static int write_data(struct usb_dev_handle *dev, void *data, int len)
726b85c8 150{
a35471cd 151 int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
726b85c8 152 if (ret < 0) {
153 fprintf(stderr, "failed to write:\n");
154 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
a35471cd 155 } else if (ret != len)
156 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
726b85c8 157
158 return ret;
159}
160
a35471cd 161static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
162{
163 return write_data(dev, cmd, sizeof(*cmd));
164}
165
166static int read_data(struct usb_dev_handle *dev, void *buff, int size)
726b85c8 167{
168 int ret = usb_bulk_read(dev, 0x82, buff, size, 2000);
169 if (ret < 0) {
170 fprintf(stderr, "failed to read:\n");
171 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
ed354cee 172 }
173/*
174 else if (ret != size)
a35471cd 175 printf("read_data: read only %d of %d bytes\n", ret, size);
ed354cee 176*/
726b85c8 177 return ret;
178}
8c8e818c 179
6ddaf67a 180static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info)
fb4ee110 181{
182 dev_cmd_t cmd;
fb4ee110 183 int ret;
184
185 prepare_cmd(&cmd, CMD_ATM_READY);
186 cmd.dev_info.which_device = ctl_id;
6ddaf67a 187 memset(info, 0, sizeof(*info));
fb4ee110 188
189 ret = write_cmd(device, &cmd);
190 if (ret < 0)
191 return ret;
192
6ddaf67a 193 ret = read_data(device, info, sizeof(*info));
fb4ee110 194 if (ret < 0)
195 return ret;
196
fb4ee110 197 return 0;
198}
199
6ddaf67a 200static void printf_info(dev_info_t *info)
201{
202 printf(" firmware version: %X.%X.%X%c\n", info->firmware_ver[0],
203 info->firmware_ver[1], info->firmware_ver[2], info->firmware_ver[3]);
204 printf(" bootloader version: %X.%X.%X%c\n", info->bootloader_ver[0],
205 info->bootloader_ver[1], info->bootloader_ver[2], info->bootloader_ver[3]);
206 info->names[sizeof(info->names) - 1] = 0;
207 printf(" device name: %s\n", info->names);
208}
209
210static void print_progress(u32 done, u32 total)
211{
212 int i, step;
213
214 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
215 printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */
216 printf("\b\b\b\b\b\b");
217 printf("%06x/%06x |", done, total);
218
219 step = total / 20;
220 for (i = step; i <= total; i += step)
221 printf("%c", done >= i ? '=' : '-');
222 printf("| %3d%%", done * 100 / total);
223 fflush(stdout);
224}
225
a35471cd 226static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
fb4ee110 227{
228 char buff[65];
229 dev_cmd_t cmd;
230 int ret;
231
232 prepare_cmd(&cmd, CMD_SEC_GET_NAME);
233 cmd.filename.which = which;
234 memset(buff, 0, sizeof(buff));
235
236 ret = write_cmd(dev, &cmd);
237 if (ret < 0)
238 return ret;
239
a35471cd 240 ret = read_data(dev, buff, 64);
fb4ee110 241 if (ret < 0)
242 return ret;
243
244 strncpy(dst, buff, len);
245 dst[len - 1] = 0;
246
247 return 0;
248}
249
a35471cd 250static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which)
251{
252 dev_cmd_t cmd;
253 char buff[64];
254 int ret, len;
255
256 len = strlen(fname);
257 if (len > 63)
258 len = 63;
259 strncpy(buff, fname, len);
260 buff[len] = 0;
261
262 prepare_cmd(&cmd, CMD_SEC_PUT_NAME);
263 cmd.filename.which = which;
264
265 ret = write_cmd(dev, &cmd);
266 if (ret < 0)
267 return ret;
268
269 return write_data(dev, buff, len + 1);
270}
271
ed354cee 272static int read_erase_counter(struct usb_dev_handle *dev, u32 *val)
a35471cd 273{
6ddaf67a 274 dev_info_t dummy_info;
a35471cd 275 dev_cmd_t cmd;
6ddaf67a 276 u8 buff[4];
a35471cd 277 int ret;
278
6ddaf67a 279 /* must perform dummy info read here,
280 * or else device hangs after close (firmware bug?) */
281 ret = read_info(dev, CTL_DATA_BUS, &dummy_info);
282 if (ret < 0)
283 return ret;
284
a35471cd 285 prepare_cmd(&cmd, CMD_ATM_READY);
286 cmd.write_cnt.cmd = W_COUNTER;
287 cmd.write_cnt.action = W_CNT_READ;
288
289 ret = write_cmd(dev, &cmd);
290 if (ret < 0)
291 return ret;
292
293 ret = read_data(dev, buff, sizeof(buff));
294 if (ret < 0)
295 return ret;
6ddaf67a 296
a35471cd 297 *val = *(u32 *)buff;
298 return 0;
299}
300
6ddaf67a 301static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val)
a35471cd 302{
303 dev_cmd_t cmd;
304 u8 buff[2];
305 int ret;
306
307 prepare_cmd(&cmd, CMD_SEC_DEVID);
6ddaf67a 308 cmd.rom_id.which = is_second ? 0x10 : 0;
309 cmd.rom_id.dev_id = 0;
a35471cd 310
311 ret = write_cmd(dev, &cmd);
312 if (ret < 0)
313 return ret;
314
315 ret = read_data(dev, buff, sizeof(buff));
316 if (ret < 0)
317 return ret;
318
319 *val = *(u16 *)buff << 16;
320
6ddaf67a 321 cmd.rom_id.dev_id = 1;
a35471cd 322 ret = write_cmd(dev, &cmd);
323 if (ret < 0)
324 return ret;
325
326 ret = read_data(dev, buff, sizeof(buff));
327 if (ret < 0)
328 return ret;
329
330 *val |= *(u16 *)buff;
331 return 0;
332}
333
334static const page_table_t *get_page_table(u32 rom_id)
335{
336 switch (rom_id) {
337 case 0x0100F922:
338 return p_AM29LV320DB;
339 case 0x0100F422:
340 return p_AM29LV320DT;
6ddaf67a 341 case 0x01004922:
342 case 0xC2004922:
343 return p_2x_16;
a35471cd 344 default:
345 fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
346 }
347
348 return NULL;
349}
350
351static int get_page_size(const page_table_t *table, u32 addr, u32 *size)
352{
353 const page_table_t *t;
354
355 for (t = table; t->end_addr != 0; t++) {
356 if (addr >= t->start_addr && addr <= t->end_addr) {
357 *size = t->page_size;
358 return 0;
359 }
360 }
361
362 if (addr == t[-1].end_addr + 1)
ed354cee 363 return 1; /* no more */
a35471cd 364
365 fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
366 return -1;
367}
368
baaf865c 369static int set_ram_mode(struct usb_dev_handle *dev, u8 mode)
370{
371 dev_cmd_t cmd;
372 u8 buff[2];
373 int ret;
374
375 prepare_cmd(&cmd, CMD_SEC_COMPAT);
376 cmd.write_flag = 1;
377 cmd.mode.which = mode;
378
379 ret = write_cmd(dev, &cmd);
380 if (ret < 0)
381 goto end;
382
383 ret = read_data(dev, buff, sizeof(buff));
384
385end:
386 if (ret < 0)
387 fprintf(stderr, "warning: failed to set RAM mode\n");
388 return ret;
389}
390
ed354cee 391/* limitations:
392 * - bytes must be multiple of 64
393 * - bytes must be less than 16k
394 * - must perform even number of reads, or dev hangs on exit (firmware bug?) */
c9d375d5 395static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd)
ed354cee 396{
397 dev_cmd_t cmd;
398 int ret;
399
c9d375d5 400 prepare_cmd(&cmd, mx_cmd);
401 if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
402 cmd.write_flag = 1;
ed354cee 403 cmd.rom_rw.addrb2 = addr >> (16 + 1);
404 cmd.rom_rw.addrb1 = addr >> (8 + 1);
405 cmd.rom_rw.addrb0 = addr >> 1;
406 cmd.rom_rw.param = bytes / 64;
c9d375d5 407 if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
408 cmd.rom_rw.param2 = 1; /* ? */
ed354cee 409
410 ret = write_cmd(dev, &cmd);
411 if (ret < 0)
412 return ret;
413
414 bytes &= ~63;
415
c9d375d5 416 if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
ed354cee 417 ret = write_data(dev, buffer, bytes);
418 else
419 ret = read_data(dev, buffer, bytes);
420 if (ret < 0)
421 return ret;
422
423 if (ret != bytes)
c9d375d5 424 fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes);
ed354cee 425
426 return ret;
427}
428
429static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write)
430{
c9d375d5 431 int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ;
ed354cee 432 int total_bytes = bytes;
433 u8 *buff = buffer;
434 u8 dummy[64 * 4];
435 int count, ret;
436
437 if (addr & 1)
438 fprintf(stderr, "read_write_rom: can't handle odd address %06x, "
439 "LSb will be ignored\n", addr);
440 if (bytes & 63)
441 fprintf(stderr, "read_write_rom: byte count must be multiple of 64, "
442 "last %d bytes will not be handled\n", bytes & 63);
443
92cfb386 444 set_ram_mode(dev, C_RAM_TMP_OFF);
baaf865c 445
ed354cee 446 printf("%s flash ROM...\n", is_write ? "writing to" : "reading");
447
448 /* do i/o in blocks */
449 for (count = 0; bytes >= IO_BLK_SIZE; count++) {
450 print_progress(buff - (u8 *)buffer, total_bytes);
451
c9d375d5 452 ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd);
ed354cee 453 if (ret < 0)
454 return ret;
455 buff += IO_BLK_SIZE;
456 addr += IO_BLK_SIZE;
457 bytes -= IO_BLK_SIZE;
458 }
459 print_progress(buff - (u8 *)buffer, total_bytes);
460
461 ret = 0;
462 if (bytes != 0) {
c9d375d5 463 ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd);
ed354cee 464 count++;
465 print_progress(total_bytes, total_bytes);
466 }
467
468 if (count & 1)
c9d375d5 469 /* work around rw_dev_block() limitation 3 (works for reads only?) */
470 rw_dev_block(dev, 0, dummy, sizeof(dummy), 0);
ed354cee 471
472 printf("\n");
473 return ret;
474}
475
c9d375d5 476static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write)
477{
baaf865c 478 int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ;
c9d375d5 479 int total_bytes = bytes;
480 u8 *buff = buffer;
481 u32 addr = 0x200000;
92cfb386 482 int i, ret = 0;
c9d375d5 483
484 if (bytes % IO_RAM_BLK_SIZE)
485 fprintf(stderr, "read_write_ram: byte count must be multiple of %d, "
486 "last %d bytes will not be handled\n", IO_RAM_BLK_SIZE,
487 bytes % IO_RAM_BLK_SIZE);
488
92cfb386 489 set_ram_mode(dev, C_RAM_TMP_ON);
baaf865c 490
c9d375d5 491 printf("%s RAM...\n", is_write ? "writing to" : "reading");
492
493 /* do i/o in blocks */
494 while (bytes >= IO_RAM_BLK_SIZE) {
495 print_progress(buff - (u8 *)buffer, total_bytes);
496
497 ret = rw_dev_block(dev, addr, buff, IO_RAM_BLK_SIZE, mx_cmd);
498 if (ret < 0)
499 return ret;
500 buff += IO_RAM_BLK_SIZE;
501 addr += IO_RAM_BLK_SIZE;
502 bytes -= IO_RAM_BLK_SIZE;
503 }
504 print_progress(buff - (u8 *)buffer, total_bytes);
505
92cfb386 506 /* only D0-D7 connected.. */
507 for (i = 0; i < total_bytes; i += 2)
508 ((u8 *)buffer)[i] = 0;
509
c9d375d5 510 printf("\n");
511 return ret;
512
513}
514
ed354cee 515static int increment_erase_cnt(struct usb_dev_handle *dev)
516{
517 dev_cmd_t cmd;
518 u8 buff[4];
519 u32 cnt;
520 int ret;
521
522 ret = read_erase_counter(dev, &cnt);
523 if (ret != 0)
524 return ret;
525
526 if (cnt == (u32)-1) {
527 fprintf(stderr, "flash erase counter maxed out!\n");
528 fprintf(stderr, "(wow, did you really erase so many times?)\n");
529 return -1;
530 }
531
532 cnt++;
533
534 prepare_cmd(&cmd, CMD_ATM_READY);
535 cmd.write_cnt.cmd = W_COUNTER;
536 cmd.write_cnt.action = W_CNT_WRITE;
537 cmd.write_cnt.b3 = cnt >> 24;
538 cmd.write_cnt.b2 = cnt >> 16;
539 cmd.write_cnt.b1 = cnt >> 8;
540 cmd.write_cnt.b0 = cnt;
541
542 ret = write_cmd(dev, &cmd);
543 if (ret < 0)
544 return ret;
545
546 ret = read_data(dev, buff, sizeof(buff));
547 if (ret < 0)
548 return ret;
549
92cfb386 550 return cnt;
ed354cee 551}
552
553static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole)
a35471cd 554{
555 dev_cmd_t cmd;
ed354cee 556 u8 buff[5];
a35471cd 557 int i, ret;
558
559 prepare_cmd(&cmd, CMD_SEC_ERASE);
560 cmd.write_flag = 1;
ed354cee 561 cmd.rom_rw.addrb2 = addr >> (16 + 1);
562 cmd.rom_rw.addrb1 = addr >> (8 + 1);
563 cmd.rom_rw.addrb0 = addr >> 1;
564 cmd.rom_rw.param = whole ? 0x10 : 0;
a35471cd 565
566 ret = write_cmd(dev, &cmd);
567 if (ret < 0)
568 return ret;
569
570 ret = read_data(dev, buff, sizeof(buff));
571 if (ret < 0)
572 return ret;
573
574 prepare_cmd(&cmd, CMD_SEC_READY);
ed354cee 575 cmd.rom_rw.addrb2 = addr >> (16 + 1);
576 cmd.rom_rw.addrb1 = addr >> (8 + 1);
577 cmd.rom_rw.addrb0 = addr >> 1;
a35471cd 578
579 for (i = 0; i < 100; i++) {
580 ret = write_cmd(dev, &cmd);
581 if (ret < 0)
582 return ret;
583
584 ret = read_data(dev, buff, sizeof(buff));
585 if (ret < 0)
586 return ret;
587
588 if (ret > 4 && buff[4] == 1)
589 break;
590
ed354cee 591 usleep((whole ? 600 : 20) * 1000);
592 }
593
594 if (i == 100) {
595 fprintf(stderr, "\ntimeout waiting for erase to complete\n");
596 return -1;
a35471cd 597 }
598
a35471cd 599 return 0;
600}
601
ed354cee 602static int erase_seq(struct usb_dev_handle *dev, u32 size)
6ddaf67a 603{
ed354cee 604 const page_table_t *table;
605 u32 addr, page_size = 0;
606 u32 rom0_id, rom1_id;
607 int count, ret;
6ddaf67a 608
ed354cee 609 ret = read_flash_rom_id(dev, 0, &rom0_id);
6ddaf67a 610 if (ret < 0)
611 return ret;
612
ed354cee 613 ret = read_flash_rom_id(dev, 1, &rom1_id);
6ddaf67a 614 if (ret < 0)
615 return ret;
6ddaf67a 616
ed354cee 617 if (rom0_id != rom1_id)
618 fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n",
619 rom0_id, rom1_id);
6ddaf67a 620
ed354cee 621 table = get_page_table(rom0_id);
622 if (table == NULL)
623 return -1;
6ddaf67a 624
ed354cee 625 ret = increment_erase_cnt(dev);
92cfb386 626 if (ret < 0)
ed354cee 627 fprintf(stderr, "warning: coun't increase erase counter\n");
6ddaf67a 628
92cfb386 629 printf("erasing flash... (erase count=%u)\n", ret);
630
ed354cee 631 for (addr = 0, count = 0; addr < size; addr += page_size, count++) {
632 print_progress(addr, size);
6ddaf67a 633
ed354cee 634 ret = erase_page(dev, addr, 0);
6ddaf67a 635 if (ret < 0)
636 return ret;
6ddaf67a 637
ed354cee 638 ret = get_page_size(table, addr, &page_size);
639 if (ret != 0)
640 break;
6ddaf67a 641 }
642
643 if (count & 1)
ed354cee 644 /* ??? */
645 /* must submit even number of erase commands (fw bug?) */
646 erase_page(dev, 0, 0);
6ddaf67a 647
ed354cee 648 print_progress(addr, size);
6ddaf67a 649 printf("\n");
ed354cee 650
651 return ret;
652}
653
654static int erase_all(struct usb_dev_handle *dev, u32 size)
655{
656 int ret;
657
ed354cee 658 ret = increment_erase_cnt(dev);
92cfb386 659 if (ret < 0)
ed354cee 660 fprintf(stderr, "warning: couldn't increase erase counter\n");
661
92cfb386 662 printf("erasing flash0, count=%u ...", ret);
663 fflush(stdout);
664
ed354cee 665 ret = erase_page(dev, 0xaaa, 1);
666 if (ret != 0)
667 return ret;
668
669 if (size > 0x200000) {
670 printf(" done.\n");
671 printf("erasing flash1...");
672 fflush(stdout);
673
674 ret = erase_page(dev, 0x200aaa, 1);
675 }
676
677 printf(" done.\n");
6ddaf67a 678 return ret;
679}
680
ed354cee 681static int print_device_info(struct usb_dev_handle *dev)
682{
683 u32 counter, rom0_id, rom1_id;
684 dev_info_t info;
685 int ret;
686
687 printf("data bus controller:\n");
688 ret = read_info(dev, CTL_DATA_BUS, &info);
689 if (ret < 0)
690 return ret;
691 printf_info(&info);
692
693 printf("address bus controller:\n");
694 ret = read_info(dev, CTL_ADDR_BUS, &info);
695 if (ret < 0)
696 return ret;
697 printf_info(&info);
698
699 ret = read_erase_counter(dev, &counter);
700 if (ret < 0)
701 return ret;
702 printf("flash erase count: %u\n", counter);
703
704 ret = read_flash_rom_id(dev, 0, &rom0_id);
705 if (ret < 0)
706 return ret;
707 printf("flash rom0 id: %08x\n", rom0_id);
708
709 ret = read_flash_rom_id(dev, 1, &rom1_id);
710 if (ret < 0)
711 return ret;
712 printf("flash rom1 id: %08x\n", rom1_id);
713
714 return 0;
715}
716
717static int print_game_info(struct usb_dev_handle *dev)
718{
719 char fname[65];
720 int ret;
721
722 ret = read_filename(dev, fname, sizeof(fname), FILENAME_ROM0);
723 if (ret < 0)
724 return ret;
725 printf("ROM filename: %s\n", fname);
726
727 ret = read_filename(dev, fname, sizeof(fname), FILENAME_RAM);
728 if (ret < 0)
729 return ret;
730 printf("SRAM filename: %s\n", fname);
731
732 return 0;
733}
734
c9d375d5 735static int read_file(const char *fname, void **buff_out, int *size, int limit)
736{
737 int file_size, ret;
738 void *data;
739 FILE *file;
740
741 file = fopen(fname, "rb");
742 if (file == NULL) {
743 fprintf(stderr, "can't open file: %s\n", fname);
744 return -1;
745 }
746
747 fseek(file, 0, SEEK_END);
748 file_size = ftell(file);
749 fseek(file, 0, SEEK_SET);
750 if (file_size > limit)
751 fprintf(stderr, "warning: input file \"%s\" too large\n", fname);
752 if (file_size < 0) {
753 fprintf(stderr, "bad/empty file: %s\n", fname);
754 goto fail;
755 }
756
757 data = malloc(file_size);
758 if (data == NULL) {
759 fprintf(stderr, "low memory\n");
760 goto fail;
761 }
762
763 ret = fread(data, 1, file_size, file);
764 if (ret != file_size) {
baaf865c 765 fprintf(stderr, "failed to read file: %s", fname);
766 perror("");
c9d375d5 767 goto fail;
768 }
769
770 *buff_out = data;
771 *size = file_size;
772 fclose(file);
773 return 0;
774
775fail:
776 fclose(file);
777 return -1;
778}
779
780static int write_file(const char *fname, void *buff, int size)
781{
782 FILE *file;
783 int ret;
784
785 file = fopen(fname, "wb");
786 if (file == NULL) {
787 fprintf(stderr, "can't open for writing: %s\n", fname);
788 return -1;
789 }
790
baaf865c 791 ret = fwrite(buff, 1, size, file);
792 if (ret != size) {
793 fprintf(stderr, "write failed to %s", fname);
794 perror("");
795 } else
92cfb386 796 printf("saved to \"%s\".\n", fname);
baaf865c 797 fclose(file);
c9d375d5 798
799 return 0;
800}
801
8c8e818c 802static usb_dev_handle *get_device(void)
803{
804 struct usb_dev_handle *handle;
805 struct usb_device *dev;
806 struct usb_bus *bus;
807 int i, ret;
808
809 ret = usb_find_busses();
810 if (ret <= 0) {
811 fprintf(stderr, "Can't find USB busses\n");
812 return NULL;
813 }
814
815 ret = usb_find_devices();
816 if (ret <= 0) {
817 fprintf(stderr, "Can't find USB devices\n");
818 return NULL;
819 }
820
821 bus = usb_get_busses();
822 for (; bus; bus = bus->next)
823 {
824 for (dev = bus->devices; dev; dev = dev->next)
825 {
826 for (i = 0; i < array_size(g_devices); i++)
827 {
828 if (dev->descriptor.idVendor == g_devices[i].vendor &&
829 dev->descriptor.idProduct == g_devices[i].product)
830 goto found;
831 }
832 }
833 }
834
835 fprintf(stderr, "device not found.\n");
836 return NULL;
837
838found:
839 printf("found %s.\n", g_devices[i].name);
840
841 handle = usb_open(dev);
842 if (handle == NULL) {
843 fprintf(stderr, "failed to open device:\n");
844 fprintf(stderr, "%s\n", usb_strerror());
845 return NULL;
846 }
847
848 ret = usb_set_configuration(handle, 1);
849 if (ret != 0) {
850 fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n",
851 bus->dirname, dev->filename);
726b85c8 852 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
8c8e818c 853 return NULL;
854 }
855
856 ret = usb_claim_interface(handle, 0);
857 if (ret != 0) {
858 fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n",
859 bus->dirname, dev->filename);
860 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
861 return NULL;
862 }
863
864 return handle;
865}
866
867static void release_device(struct usb_dev_handle *device)
868{
869 usb_release_interface(device, 0);
870 usb_close(device);
871}
872
ed354cee 873static void usage(const char *app_name)
874{
875 printf("Flasher tool for MX game devices\n"
876 "written by Grazvydas \"notaz\" Ignotas\n");
877 printf("v" VERSION " (" __DATE__ ")\n\n");
878 printf("Usage:\n"
c9d375d5 879 "%s [-i] [-g] [-e] [-r [file]] [-w <file>] ...\n"
ed354cee 880 " -i print some info about connected device\n"
881 " -g print some info about game ROM inside device\n"
c9d375d5 882 " -e[1] erase whole flash ROM in device, '1' uses different erase method\n"
95122097 883 " -m[1-3] set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n"
c9d375d5 884 " -f skip file check\n"
ed354cee 885 " -r [file] copy game image from device to file; can autodetect filename\n"
c9d375d5 886 " -w <file> write file to device; also does erase\n"
887 " -sr [file] read save RAM to file\n"
888 " -sw <file> write save RAM file to device\n"
889 " -sc clear save RAM\n"
890 " -v with -w or -sw: verify written file\n",
ed354cee 891 app_name);
892}
893
8c8e818c 894int main(int argc, char *argv[])
895{
c9d375d5 896 char *r_fname = NULL, *w_fname = NULL, *sr_fname = NULL, *sw_fname = NULL;
897 void *r_fdata = NULL, *w_fdata = NULL, *sr_fdata = NULL, *sw_fdata = NULL;
898 int do_read_ram = 0, do_clear_ram = 0, do_verify = 0, do_check = 1;
95122097 899 int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0;
c9d375d5 900 int erase_method = 0, do_erase_size = 0;
901 int w_fsize = 0, sw_fsize = 0;
8c8e818c 902 struct usb_dev_handle *device;
c9d375d5 903 char fname_buff[65];
ed354cee 904 int i, ret = 0;
905
906 for (i = 1; i < argc; i++)
907 {
908 if (argv[i][0] != '-')
909 break;
910
911 switch (argv[i][1]) {
912 case 'i':
913 pr_dev_info = 1;
914 break;
915 case 'g':
916 pr_rom_info = 1;
917 break;
918 case 'e':
919 do_erase_size = 0x400000;
c9d375d5 920 if (argv[i][2] == '1')
921 erase_method = 1;
ed354cee 922 break;
923 case 'f':
c9d375d5 924 do_check = 0;
ed354cee 925 break;
926 case 'v':
927 do_verify = 1;
928 break;
95122097 929 case 'm':
930 mx_mode = argv[i][2];
931 break;
ed354cee 932 case 'r':
933 do_read = 1;
c9d375d5 934 if (argv[i+1] && argv[i+1][0] != '-')
ed354cee 935 r_fname = argv[++i];
936 break;
937 case 'w':
c9d375d5 938 if (argv[i+1] && argv[i+1][0] != '-')
ed354cee 939 w_fname = argv[++i];
940 else
941 goto breakloop;
942 break;
c9d375d5 943 case 's':
944 switch (argv[i][2]) {
945 case 'r':
946 do_read_ram = 1;
947 if (argv[i+1] && argv[i+1][0] != '-')
948 sr_fname = argv[++i];
949 break;
950 case 'w':
951 if (argv[i+1] && argv[i+1][0] != '-')
952 sw_fname = argv[++i];
953 else
954 goto breakloop;
955 break;
956 case 'c':
957 do_clear_ram = 1;
958 break;
959 default:
baaf865c 960 goto breakloop;
c9d375d5 961 }
baaf865c 962 break;
ed354cee 963 default:
964 goto breakloop;
965 }
966 }
967
968breakloop:
969 if (i <= 1 || i < argc) {
970 usage(argv[0]);
971 return 1;
972 }
973
c9d375d5 974 /* preparations */
ed354cee 975 if (w_fname != NULL) {
c9d375d5 976 /* check extension */
977 ret = strlen(w_fname);
978 if (do_check && (w_fname[ret - 4] == '.' || w_fname[ret - 3] == '.' ||
979 w_fname[ret - 2] == '.') &&
980 strcasecmp(&w_fname[ret - 4], ".gen") != 0 &&
981 strcasecmp(&w_fname[ret - 4], ".bin") != 0) {
982 fprintf(stderr, "\"%s\" doesn't look like a game ROM, aborting "
983 "(use -f to disable this check)\n", w_fname);
ed354cee 984 return 1;
985 }
986
c9d375d5 987 ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000);
988 if (ret < 0)
ed354cee 989 return 1;
ed354cee 990
c9d375d5 991 if (do_erase_size < w_fsize)
992 do_erase_size = w_fsize;
993 }
994 if (sw_fname != NULL) {
92cfb386 995 ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2);
c9d375d5 996 if (ret < 0)
ed354cee 997 return 1;
c9d375d5 998 }
999 if (sw_fdata != NULL || do_clear_ram) {
92cfb386 1000 if (sw_fsize < 0x8000*2) {
1001 sw_fdata = realloc(sw_fdata, 0x8000*2);
c9d375d5 1002 if (sw_fdata == NULL) {
1003 fprintf(stderr, "low mem\n");
1004 return 1;
1005 }
92cfb386 1006 memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize);
ed354cee 1007 }
92cfb386 1008 sw_fsize = 0x8000*2;
c9d375d5 1009 }
1010 if (w_fname == NULL && sw_fname == NULL && do_verify) {
1011 fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n");
ed354cee 1012 do_verify = 0;
1013 }
8c8e818c 1014
c9d375d5 1015 /* init */
8c8e818c 1016 usb_init();
1017
1018 device = get_device();
1019 if (device == NULL)
1020 return 1;
1021
c9d375d5 1022 /* info */
ed354cee 1023 if (pr_dev_info) {
1024 ret = print_device_info(device);
1025 if (ret < 0)
1026 goto end;
1027 }
726b85c8 1028
ed354cee 1029 if (pr_rom_info) {
1030 ret = print_game_info(device);
1031 if (ret < 0)
1032 goto end;
1033 }
8c8e818c 1034
95122097 1035 /* set mode */
1036 if (mx_mode || w_fsize > 0x200000) {
1037 if (mx_mode == 0)
1038 mx_mode = '3';
1039 printf("MX mode set to ");
1040 switch (mx_mode) {
1041 case '1':
1042 printf("2M with RAM.\n");
1043 mx_mode = C_MODE_2M_RAM;
1044 break;
1045 case '2':
1046 printf("4M, no RAM.\n");
1047 mx_mode = C_MODE_4M_NORAM;
1048 break;
1049 default:
1050 printf("4M with RAM.\n");
1051 mx_mode = C_MODE_4M_RAM;
1052 break;
1053 }
1054 set_ram_mode(device, mx_mode);
1055 }
1056
ed354cee 1057 /* erase */
1058 if (do_erase_size != 0) {
1059 if (erase_method)
1060 ret = erase_all(device, do_erase_size);
1061 else
1062 ret = erase_seq(device, do_erase_size);
1063 if (ret < 0)
1064 goto end;
1065 }
fb4ee110 1066
c9d375d5 1067 /* write flash */
ed354cee 1068 if (w_fdata != NULL) {
1069 char *p;
fb4ee110 1070
c9d375d5 1071 ret = read_write_rom(device, 0, w_fdata, w_fsize, 1);
ed354cee 1072 if (ret < 0)
1073 goto end;
fb4ee110 1074
ed354cee 1075 p = strrchr(w_fname, '/');
c9d375d5 1076 p = (p == NULL) ? w_fname : p + 1;
6ddaf67a 1077
ed354cee 1078 ret = write_filename(device, p, FILENAME_ROM0);
1079 if (ret < 0)
1080 fprintf(stderr, "warning: failed to save ROM filename\n");
1081 }
6ddaf67a 1082
c9d375d5 1083 /* write ram */
1084 if (sw_fdata != NULL) {
1085 char *p, *t;
1086
1087 ret = read_write_ram(device, sw_fdata, sw_fsize, 1);
1088 if (ret < 0)
1089 goto end;
1090
1091 memset(fname_buff, 0, sizeof(fname_buff));
1092 p = fname_buff;
1093 if (sw_fname != NULL) {
1094 p = strrchr(sw_fname, '/');
1095 p = (p == NULL) ? sw_fname : p + 1;
1096 } else if (w_fname != NULL) {
1097 t = strrchr(w_fname, '/');
1098 t = (t == NULL) ? w_fname : t + 1;
1099
1100 strncpy(fname_buff, t, sizeof(fname_buff));
1101 fname_buff[sizeof(fname_buff) - 1] = 0;
1102 ret = strlen(fname_buff);
1103 if (ret > 4 && fname_buff[ret - 4] == '.')
1104 strcpy(&fname_buff[ret - 4], ".srm");
1105 }
1106
1107 ret = write_filename(device, p, FILENAME_RAM);
1108 if (ret < 0)
1109 fprintf(stderr, "warning: failed to save RAM filename\n");
1110 }
1111
1112 /* read flash */
ed354cee 1113 if (do_read && r_fname == NULL) {
c9d375d5 1114 ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0);
ed354cee 1115 if (ret < 0)
1116 return ret;
c9d375d5 1117 r_fname = fname_buff;
ed354cee 1118 if (r_fname[0] == 0)
1119 r_fname = "rom.gen";
6ddaf67a 1120 }
1121
ed354cee 1122 if (r_fname != NULL || do_verify) {
1123 r_fdata = malloc(0x400000);
1124 if (r_fdata == NULL) {
1125 fprintf(stderr, "low mem\n");
1126 goto end;
1127 }
1128
1129 ret = read_write_rom(device, 0, r_fdata, 0x400000, 0);
1130 if (ret < 0)
1131 goto end;
1132 }
1133
c9d375d5 1134 if (r_fname != NULL)
1135 write_file(r_fname, r_fdata, 0x400000);
1136
1137 /* read ram */
1138 if (do_read_ram && sr_fname == NULL) {
1139 ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_RAM);
1140 if (ret < 0)
1141 return ret;
1142 sr_fname = fname_buff;
1143 if (sr_fname[0] == 0)
1144 sr_fname = "rom.srm";
ed354cee 1145 }
1146
c9d375d5 1147 if (sr_fname != NULL || do_verify) {
92cfb386 1148 sr_fdata = malloc(0x8000*2);
c9d375d5 1149 if (sr_fdata == NULL) {
1150 fprintf(stderr, "low mem\n");
ed354cee 1151 goto end;
1152 }
c9d375d5 1153
92cfb386 1154 ret = read_write_ram(device, sr_fdata, 0x8000*2, 0);
c9d375d5 1155 if (ret < 0)
1156 goto end;
1157 }
1158
1159 if (sr_fname != NULL)
92cfb386 1160 write_file(sr_fname, sr_fdata, 0x8000*2);
c9d375d5 1161
1162 /* verify */
1163 if (do_verify && w_fdata != NULL && r_fdata != NULL) {
1164 ret = memcmp(w_fdata, r_fdata, w_fsize);
1165 if (ret == 0)
1166 printf("flash verification passed.\n");
1167 else
1168 printf("flash verification FAILED!\n");
1169 }
1170
1171 if (do_verify && sw_fdata != NULL && sr_fdata != NULL) {
92cfb386 1172 ret = memcmp(sw_fdata, sr_fdata, 0x8000*2);
c9d375d5 1173 if (ret == 0)
1174 printf("RAM verification passed.\n");
ed354cee 1175 else
c9d375d5 1176 printf("RAM verification FAILED!\n");
ed354cee 1177 }
8c8e818c 1178
c9d375d5 1179 printf("all done.\n");
1180 ret = 0;
1181
726b85c8 1182end:
ed354cee 1183 if (w_fdata != NULL)
1184 free(w_fdata);
1185 if (r_fdata != NULL)
1186 free(r_fdata);
1187
8c8e818c 1188 release_device(device);
1189
726b85c8 1190 return ret;
8c8e818c 1191}
1192