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