mx_flasher: minor updates
[megadrive.git] / mx / linux / mx_flasher.c
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  *
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.
26  */
27 #include <stdio.h>
28 #include <string.h>
29 #include <usb.h>
30
31
32 typedef unsigned char  u8;
33 typedef unsigned short u16;
34 typedef unsigned int   u32;
35 #define array_size(x) (sizeof(x) / sizeof(x[0]))
36
37 static 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
48 #define VERSION                 "0.91"
49
50 //#define IO_BLK_SIZE           0x2000  /* 8K - unreliable? */
51 #define IO_BLK_SIZE             0x800
52 #define IO_RAM_BLK_SIZE         256
53
54 #define CMD_ATM_READY           0x22
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? */
60 #define CMD_SEC_READ            'R'
61 #define CMD_SEC_WRITE           'W'
62 #define CMD_SEC_RAM_READ        'D'     /* not implemented? */
63 #define CMD_SEC_RAM_WRITE       'U'
64 #define CMD_SEC_COMPAT          '$'     /* set RAM mode */
65
66 /* bus controllers */
67 #define CTL_DATA_BUS    0x55
68 #define CTL_ADDR_BUS    0xAA
69
70 #define W_COUNTER       0xA0
71 #define W_CNT_WRITE     0x01
72 #define W_CNT_READ      0x00
73
74 #define FILENAME_ROM0   0
75 #define FILENAME_ROM1   1
76 #define FILENAME_RAM    2
77
78 /* windows app sets to 0x80 on init
79  * checkboxes use 0x41 0x42 0x43 (?)
80  * r,w Ram/ROM uses 0x23/0x21
81  */
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
85 #define C_RAM_TMP_OFF   0x21
86 #define C_RAM_TMP_ON    0x23
87
88 typedef struct {
89         u8 magic[4];
90         u8 reserved[8];
91         u8 write_flag;
92         u8 reserved2[2];
93         u8 magic2;
94         u8 mx_cmd;
95         union {                         /* 0x11 */
96                 struct {
97                         u8 which_device;
98                 } dev_info;
99                 struct {
100                         u8 addrb2;      /* most significant (BE) */
101                         u8 addrb1;
102                         u8 addrb0;
103                         u8 param;       /* 64 byte usb packets for i/o */
104                         u8 param2;
105                 } rom_rw;
106                 struct {
107                         u8 which;
108                 } filename, mode;
109                 struct {
110                         u8 cmd;
111                         u8 action;
112                         u8 b0;          /* LE */
113                         u8 b1;
114                         u8 b2;
115                         u8 b3;
116                 } write_cnt;
117                 struct {
118                         u8 which;
119                         u8 dev_id;
120                 } rom_id;
121         };
122         u8 pad[8];
123 } dev_cmd_t;
124
125 typedef struct {
126         u8 firmware_ver[4];
127         u8 bootloader_ver[4];
128         char names[56];
129 } dev_info_t;
130
131 typedef struct {
132         u32 start_addr;
133         u32 end_addr;
134         u32 page_size;
135 } page_table_t;
136
137 static const page_table_t p_AM29LV320DB[] =
138 {
139         { 0x000000, 0x00ffff, 0x002000 },
140         { 0x010000, 0x3fffff, 0x010000 },
141         { 0x000000, 0x000000, 0x000000 },
142 };
143
144 static const page_table_t p_AM29LV320DT[] =
145 {
146         { 0x000000, 0x3effff, 0x010000 },
147         { 0x3f0000, 0x3fffff, 0x002000 },
148         { 0x000000, 0x000000, 0x000000 },
149 };
150
151 static 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
164 /*****************************************************************************/
165
166 static 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);
171         dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
172         dev_cmd->mx_cmd = cmd;
173 }
174
175 static int write_data(struct usb_dev_handle *dev, void *data, int len)
176 {
177         int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
178         if (ret < 0) {
179                 fprintf(stderr, "failed to write:\n");
180                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
181         } else if (ret != len)
182                 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
183         
184         return ret;
185 }
186
187 static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
188 {
189         return write_data(dev, cmd, sizeof(*cmd));
190 }
191
192 static int read_data(struct usb_dev_handle *dev, void *buff, int size)
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);
198         }
199 /*
200         else if (ret != size)
201                 printf("read_data: read only %d of %d bytes\n", ret, size);
202 */
203         return ret;
204 }
205
206 static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info)
207 {
208         dev_cmd_t cmd;
209         int ret;
210
211         prepare_cmd(&cmd, CMD_ATM_READY);
212         cmd.dev_info.which_device = ctl_id;
213         memset(info, 0, sizeof(*info));
214
215         ret = write_cmd(device, &cmd);
216         if (ret < 0)
217                 return ret;
218
219         ret = read_data(device, info, sizeof(*info));
220         if (ret < 0)
221                 return ret;
222         
223         return 0;
224 }
225
226 static 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
236 static 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
252 static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
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
266         ret = read_data(dev, buff, 64);
267         if (ret < 0)
268                 return ret;
269
270         strncpy(dst, buff, len);
271         dst[len - 1] = 0;
272
273         return 0;
274 }
275
276 static 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
298 static int read_erase_counter(struct usb_dev_handle *dev, u32 *val)
299 {
300         dev_info_t dummy_info;
301         dev_cmd_t cmd;
302         u8 buff[4];
303         int ret;
304
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
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;
322
323         *val = *(u32 *)buff;
324         return 0;
325 }
326
327 static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val)
328 {
329         dev_cmd_t cmd;
330         u8 buff[2];
331         int ret;
332
333         prepare_cmd(&cmd, CMD_SEC_DEVID);
334         cmd.rom_id.which = is_second ? 0x10 : 0;
335         cmd.rom_id.dev_id = 0;
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
347         cmd.rom_id.dev_id = 1;
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
360 static 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;
367         case 0x01004922:
368         case 0xC2004922:
369                 return p_2x_16;
370         default:
371                 fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
372         }
373
374         return NULL;
375 }
376
377 static 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)
389                 return 1;       /* no more */
390         
391         fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
392         return -1;
393 }
394
395 static 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
411 end:
412         if (ret < 0)
413                 fprintf(stderr, "warning: failed to set RAM mode\n");
414         return ret;
415 }
416
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?) */
421 static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd)
422 {
423         dev_cmd_t cmd;
424         int ret;
425
426         prepare_cmd(&cmd, mx_cmd);
427         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
428                 cmd.write_flag = 1;
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;
433         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
434                 cmd.rom_rw.param2 = 1; /* ? */
435
436         ret = write_cmd(dev, &cmd);
437         if (ret < 0)
438                 return ret;
439
440         bytes &= ~63;
441
442         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
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)
450                 fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes);
451
452         return ret;
453 }
454
455 static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write)
456 {
457         int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ;
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
470         set_ram_mode(dev, C_RAM_TMP_OFF);
471
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
478                 ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd);
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) {
489                 ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd);
490                 count++;
491                 print_progress(total_bytes, total_bytes);
492         }
493
494         if ((count & 1) && !is_write)
495                 /* work around rw_dev_block() limitation 3 (works for reads only?) */
496                 rw_dev_block(dev, 0, dummy, sizeof(dummy), 0);
497
498         printf("\n");
499         return ret;
500 }
501
502 static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write)
503 {
504         int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ;
505         int total_bytes = bytes;
506         u8 *buff = buffer;
507         u32 addr = 0x200000;
508         int i, ret = 0;
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
515         set_ram_mode(dev, C_RAM_TMP_ON);
516
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
532         /* only D0-D7 connected.. */
533         for (i = 0; i < total_bytes; i += 2)
534                 ((u8 *)buffer)[i] = 0;
535
536         printf("\n");
537         return ret;
538
539 }
540
541 static 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
576         return cnt;
577 }
578
579 static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole)
580 {
581         dev_cmd_t cmd;
582         u8 buff[5];
583         int i, ret;
584
585         prepare_cmd(&cmd, CMD_SEC_ERASE);
586         cmd.write_flag = 1;
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;
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);
601         cmd.rom_rw.addrb2 = addr >> (16 + 1);
602         cmd.rom_rw.addrb1 = addr >> (8 + 1);
603         cmd.rom_rw.addrb0 = addr >> 1;
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
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;
623         }
624
625         return 0;
626 }
627
628 static int erase_seq(struct usb_dev_handle *dev, u32 size)
629 {
630         const page_table_t *table;
631         u32 addr, page_size = 0;
632         u32 rom0_id, rom1_id;
633         int count, ret;
634
635         ret = read_flash_rom_id(dev, 0, &rom0_id);
636         if (ret < 0)
637                 return ret;
638
639         ret = read_flash_rom_id(dev, 1, &rom1_id);
640         if (ret < 0)
641                 return ret;
642
643         if (rom0_id != rom1_id)
644                 fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n",
645                         rom0_id, rom1_id);
646
647         table = get_page_table(rom0_id);
648         if (table == NULL)
649                 return -1;
650
651         ret = increment_erase_cnt(dev);
652         if (ret < 0)
653                 fprintf(stderr, "warning: coun't increase erase counter\n");
654
655         printf("erasing flash... (erase count=%u)\n", ret);
656
657         for (addr = 0, count = 0; addr < size; addr += page_size, count++) {
658                 print_progress(addr, size);
659
660                 ret = erase_page(dev, addr, 0);
661                 if (ret < 0)
662                         return ret;
663
664                 ret = get_page_size(table, addr, &page_size);
665                 if (ret != 0)
666                         break;
667         }
668
669         if (count & 1)
670                 /* ??? */
671                 /* must submit even number of erase commands (fw bug?) */
672                 erase_page(dev, 0, 0);
673
674         print_progress(addr, size);
675         printf("\n");
676
677         return ret;
678 }
679
680 static int erase_all(struct usb_dev_handle *dev, u32 size)
681 {
682         int ret;
683
684         ret = increment_erase_cnt(dev);
685         if (ret < 0)
686                 fprintf(stderr, "warning: couldn't increase erase counter\n");
687
688         printf("erasing flash0, count=%u ...", ret);
689         fflush(stdout);
690
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");
704         return ret;
705 }
706
707 static 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
743 static 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
761 static 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) {
791                 fprintf(stderr, "failed to read file: %s", fname);
792                 perror("");
793                 goto fail;
794         }
795
796         *buff_out = data;
797         *size = file_size;
798         fclose(file);
799         return 0;
800
801 fail:
802         fclose(file);
803         return -1;
804 }
805
806 static 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
817         ret = fwrite(buff, 1, size, file);
818         if (ret != size) {
819                 fprintf(stderr, "write failed to %s", fname);
820                 perror("");
821         } else
822                 printf("saved to \"%s\".\n", fname);
823         fclose(file);
824         
825         return 0;
826 }
827
828 static 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
864 found:
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);
878                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
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
893 static void release_device(struct usb_dev_handle *device)
894 {
895         usb_release_interface(device, 0);
896         usb_close(device);
897 }
898
899 static 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"
905                 "%s [-i] [-g] [-e] [-r [file]] [-w <file>] ...\n"
906                 "  -i         print some info about connected device\n"
907                 "  -g         print some info about game ROM inside device\n"
908                 "  -e[1]      erase whole flash ROM in device, '1' uses different erase method\n"
909                 "  -m[1-3]    set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n"
910                 "  -f         skip file check\n"
911                 "  -r [file]  copy game image from device to file; can autodetect filename\n"
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",
917                 app_name);
918 }
919
920 int main(int argc, char *argv[])
921 {
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;
925         int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0;
926         int erase_method = 0, do_erase_size = 0;
927         int w_fsize = 0, sw_fsize = 0;
928         struct usb_dev_handle *device;
929         char fname_buff[65];
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;
946                         if (argv[i][2] == '1')
947                                 erase_method = 1;
948                         break;
949                 case 'f':
950                         do_check = 0;
951                         break;
952                 case 'v':
953                         do_verify = 1;
954                         break;
955                 case 'm':
956                         mx_mode = argv[i][2];
957                         break;
958                 case 'r':
959                         do_read = 1;
960                         if (argv[i+1] && argv[i+1][0] != '-')
961                                 r_fname = argv[++i];
962                         break;
963                 case 'w':
964                         if (argv[i+1] && argv[i+1][0] != '-')
965                                 w_fname = argv[++i];
966                         else
967                                 goto breakloop;
968                         break;
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:
986                                 goto breakloop;
987                         }
988                         break;
989                 default:
990                         goto breakloop;
991                 }
992         }
993
994 breakloop:
995         if (i <= 1 || i < argc) {
996                 usage(argv[0]);
997                 return 1;
998         }
999
1000         /* preparations */
1001         if (w_fname != NULL) {
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 &&
1007                                 strcasecmp(&w_fname[ret - 4], ".bin") != 0 &&
1008                                 strcasecmp(&w_fname[ret - 4], ".32x") != 0) {
1009                         fprintf(stderr, "\"%s\" doesn't look like a game ROM, aborting "
1010                                         "(use -f to disable this check)\n", w_fname);
1011                         return 1;
1012                 }
1013
1014                 ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000);
1015                 if (ret < 0)
1016                         return 1;
1017
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
1031                 if (do_erase_size < w_fsize)
1032                         do_erase_size = w_fsize;
1033         }
1034         if (sw_fname != NULL) {
1035                 ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2);
1036                 if (ret < 0)
1037                         return 1;
1038         }
1039         if (sw_fdata != NULL || do_clear_ram) {
1040                 if (sw_fsize < 0x8000*2) {
1041                         sw_fdata = realloc(sw_fdata, 0x8000*2);
1042                         if (sw_fdata == NULL) {
1043                                 fprintf(stderr, "low mem\n");
1044                                 return 1;
1045                         }
1046                         memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize);
1047                 }
1048                 sw_fsize = 0x8000*2;
1049         }
1050         if (w_fname == NULL && sw_fname == NULL && do_verify) {
1051                 fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n");
1052                 do_verify = 0;
1053         }
1054
1055         /* init */
1056         usb_init();
1057
1058         device = get_device();
1059         if (device == NULL)
1060                 return 1;
1061
1062         /* info */
1063         if (pr_dev_info) {
1064                 ret = print_device_info(device);
1065                 if (ret < 0)
1066                         goto end;
1067         }
1068
1069         if (pr_rom_info) {
1070                 ret = print_game_info(device);
1071                 if (ret < 0)
1072                         goto end;
1073         }
1074
1075         /* set mode */
1076         if (mx_mode || w_fsize > 0x200000) {
1077                 if (mx_mode == 0)
1078                         mx_mode = '3';
1079                 printf("MX mode set to ");
1080                 switch (mx_mode) {
1081                 case '1':
1082                         printf("2M with RAM.\n");
1083                         mx_mode = C_MODE_2M_RAM;
1084                         break;
1085                 case '2':
1086                         printf("4M, no RAM.\n");
1087                         mx_mode = C_MODE_4M_NORAM;
1088                         break;
1089                 default:
1090                         printf("4M with RAM.\n");
1091                         mx_mode = C_MODE_4M_RAM;
1092                         break;
1093                 }
1094                 set_ram_mode(device, mx_mode);
1095         }
1096
1097         /* erase */
1098         if (do_erase_size != 0) {
1099                 if (erase_method)
1100                         ret = erase_all(device, do_erase_size);
1101                 else
1102                         ret = erase_seq(device, do_erase_size);
1103                 if (ret < 0)
1104                         goto end;
1105         }
1106
1107         /* write flash */
1108         if (w_fdata != NULL) {
1109                 char *p;
1110
1111                 ret = read_write_rom(device, 0, w_fdata, w_fsize, 1);
1112                 if (ret < 0)
1113                         goto end;
1114
1115                 p = strrchr(w_fname, '/');
1116                 p = (p == NULL) ? w_fname : p + 1;
1117
1118                 ret = write_filename(device, p, FILENAME_ROM0);
1119                 if (ret < 0)
1120                         fprintf(stderr, "warning: failed to save ROM filename\n");
1121         }
1122
1123         /* write ram */
1124         if (sw_fdata != NULL) {
1125                 char *p, *t;
1126
1127                 ret = read_write_ram(device, sw_fdata, sw_fsize, 1);
1128                 if (ret < 0)
1129                         goto end;
1130
1131                 memset(fname_buff, 0, sizeof(fname_buff));
1132                 p = fname_buff;
1133                 if (sw_fname != NULL) {
1134                         p = strrchr(sw_fname, '/');
1135                         p = (p == NULL) ? sw_fname : p + 1;
1136                 } else if (w_fname != NULL) {
1137                         t = strrchr(w_fname, '/');
1138                         t = (t == NULL) ? w_fname : t + 1;
1139
1140                         strncpy(fname_buff, t, sizeof(fname_buff));
1141                         fname_buff[sizeof(fname_buff) - 1] = 0;
1142                         ret = strlen(fname_buff);
1143                         if (ret > 4 && fname_buff[ret - 4] == '.')
1144                                 strcpy(&fname_buff[ret - 4], ".srm");
1145                 }
1146
1147                 ret = write_filename(device, p, FILENAME_RAM);
1148                 if (ret < 0)
1149                         fprintf(stderr, "warning: failed to save RAM filename\n");
1150         }
1151
1152         /* read flash */
1153         if (do_read && r_fname == NULL) {
1154                 ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0);
1155                 if (ret < 0)
1156                         return ret;
1157                 r_fname = fname_buff;
1158                 if (r_fname[0] == 0)
1159                         r_fname = "rom.gen";
1160         }
1161
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
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";
1185         }
1186
1187         if (sr_fname != NULL || do_verify) {
1188                 sr_fdata = malloc(0x8000*2);
1189                 if (sr_fdata == NULL) {
1190                         fprintf(stderr, "low mem\n");
1191                         goto end;
1192                 }
1193
1194                 ret = read_write_ram(device, sr_fdata, 0x8000*2, 0);
1195                 if (ret < 0)
1196                         goto end;
1197         }
1198
1199         if (sr_fname != NULL)
1200                 write_file(sr_fname, sr_fdata, 0x8000*2);
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) {
1212                 ret = memcmp(sw_fdata, sr_fdata, 0x8000*2);
1213                 if (ret == 0)
1214                         printf("RAM verification passed.\n");
1215                 else
1216                         printf("RAM verification FAILED!\n");
1217         }
1218
1219         printf("all done.\n");
1220         ret = 0;
1221
1222 end:
1223         if (w_fdata != NULL)
1224                 free(w_fdata);
1225         if (r_fdata != NULL)
1226                 free(r_fdata);
1227
1228         release_device(device);
1229
1230         return ret;
1231 }
1232