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