fix license text, add gitignore
[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 PROJECT AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
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  */
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 */
51 #define IO_RAM_BLK_SIZE         256
52
53 #define CMD_ATM_READY           0x22
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? */
59 #define CMD_SEC_READ            'R'
60 #define CMD_SEC_WRITE           'W'
61 #define CMD_SEC_RAM_READ        'D'     /* not implemented? */
62 #define CMD_SEC_RAM_WRITE       'U'
63 #define CMD_SEC_COMPAT          '$'     /* set RAM mode */
64
65 /* bus controllers */
66 #define CTL_DATA_BUS    0x55
67 #define CTL_ADDR_BUS    0xAA
68
69 #define W_COUNTER       0xA0
70 #define W_CNT_WRITE     0x01
71 #define W_CNT_READ      0x00
72
73 #define FILENAME_ROM0   0
74 #define FILENAME_ROM1   1
75 #define FILENAME_RAM    2
76
77 /* windows app sets to 0x80 on init
78  * checkboxes use 0x41 0x42 0x43 (?)
79  * r,w Ram/ROM uses 0x23/0x21
80  */
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
84 #define C_RAM_TMP_OFF   0x21
85 #define C_RAM_TMP_ON    0x23
86
87 typedef struct {
88         u8 magic[4];
89         u8 reserved[8];
90         u8 write_flag;
91         u8 reserved2[2];
92         u8 magic2;
93         u8 mx_cmd;
94         union {                         /* 0x11 */
95                 struct {
96                         u8 which_device;
97                 } dev_info;
98                 struct {
99                         u8 addrb2;      /* most significant (BE) */
100                         u8 addrb1;
101                         u8 addrb0;
102                         u8 param;       /* 64 byte usb packets for i/o */
103                         u8 param2;
104                 } rom_rw;
105                 struct {
106                         u8 which;
107                 } filename, mode;
108                 struct {
109                         u8 cmd;
110                         u8 action;
111                         u8 b0;          /* LE */
112                         u8 b1;
113                         u8 b2;
114                         u8 b3;
115                 } write_cnt;
116                 struct {
117                         u8 which;
118                         u8 dev_id;
119                 } rom_id;
120         };
121         u8 pad[8];
122 } dev_cmd_t;
123
124 typedef struct {
125         u8 firmware_ver[4];
126         u8 bootloader_ver[4];
127         char names[56];
128 } dev_info_t;
129
130 typedef struct {
131         u32 start_addr;
132         u32 end_addr;
133         u32 page_size;
134 } page_table_t;
135
136 static const page_table_t p_AM29LV320DB[] =
137 {
138         { 0x000000, 0x00ffff, 0x002000 },
139         { 0x010000, 0x3fffff, 0x010000 },
140         { 0x000000, 0x000000, 0x000000 },
141 };
142
143 static const page_table_t p_AM29LV320DT[] =
144 {
145         { 0x000000, 0x3effff, 0x010000 },
146         { 0x3f0000, 0x3fffff, 0x002000 },
147         { 0x000000, 0x000000, 0x000000 },
148 };
149
150 static 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
163 /*****************************************************************************/
164
165 static 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);
170         dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
171         dev_cmd->mx_cmd = cmd;
172 }
173
174 static int write_data(struct usb_dev_handle *dev, void *data, int len)
175 {
176         int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
177         if (ret < 0) {
178                 fprintf(stderr, "failed to write:\n");
179                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
180         } else if (ret != len)
181                 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
182         
183         return ret;
184 }
185
186 static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
187 {
188         return write_data(dev, cmd, sizeof(*cmd));
189 }
190
191 static int read_data(struct usb_dev_handle *dev, void *buff, int size)
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);
197         }
198 /*
199         else if (ret != size)
200                 printf("read_data: read only %d of %d bytes\n", ret, size);
201 */
202         return ret;
203 }
204
205 static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info)
206 {
207         dev_cmd_t cmd;
208         int ret;
209
210         prepare_cmd(&cmd, CMD_ATM_READY);
211         cmd.dev_info.which_device = ctl_id;
212         memset(info, 0, sizeof(*info));
213
214         ret = write_cmd(device, &cmd);
215         if (ret < 0)
216                 return ret;
217
218         ret = read_data(device, info, sizeof(*info));
219         if (ret < 0)
220                 return ret;
221         
222         return 0;
223 }
224
225 static 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
235 static 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
251 static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
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
265         ret = read_data(dev, buff, 64);
266         if (ret < 0)
267                 return ret;
268
269         strncpy(dst, buff, len);
270         dst[len - 1] = 0;
271
272         return 0;
273 }
274
275 static 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
297 static int read_erase_counter(struct usb_dev_handle *dev, u32 *val)
298 {
299         dev_info_t dummy_info;
300         dev_cmd_t cmd;
301         u8 buff[4];
302         int ret;
303
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
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;
321
322         *val = *(u32 *)buff;
323         return 0;
324 }
325
326 static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val)
327 {
328         dev_cmd_t cmd;
329         u8 buff[2];
330         int ret;
331
332         prepare_cmd(&cmd, CMD_SEC_DEVID);
333         cmd.rom_id.which = is_second ? 0x10 : 0;
334         cmd.rom_id.dev_id = 0;
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
346         cmd.rom_id.dev_id = 1;
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
359 static 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;
366         case 0x01004922:
367         case 0xC2004922:
368                 return p_2x_16;
369         default:
370                 fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
371         }
372
373         return NULL;
374 }
375
376 static 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)
388                 return 1;       /* no more */
389         
390         fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
391         return -1;
392 }
393
394 static 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
410 end:
411         if (ret < 0)
412                 fprintf(stderr, "warning: failed to set RAM mode\n");
413         return ret;
414 }
415
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?) */
420 static int rw_dev_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int mx_cmd)
421 {
422         dev_cmd_t cmd;
423         int ret;
424
425         prepare_cmd(&cmd, mx_cmd);
426         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
427                 cmd.write_flag = 1;
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;
432         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
433                 cmd.rom_rw.param2 = 1; /* ? */
434
435         ret = write_cmd(dev, &cmd);
436         if (ret < 0)
437                 return ret;
438
439         bytes &= ~63;
440
441         if (mx_cmd == CMD_SEC_WRITE || mx_cmd == CMD_SEC_RAM_WRITE)
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)
449                 fprintf(stderr, "rw_dev_block warning: done only %d/%d bytes\n", ret, bytes);
450
451         return ret;
452 }
453
454 static int read_write_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes, int is_write)
455 {
456         int mx_cmd = is_write ? CMD_SEC_WRITE : CMD_SEC_READ;
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
469         set_ram_mode(dev, C_RAM_TMP_OFF);
470
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
477                 ret = rw_dev_block(dev, addr, buff, IO_BLK_SIZE, mx_cmd);
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) {
488                 ret = rw_dev_block(dev, addr, buff, bytes, mx_cmd);
489                 count++;
490                 print_progress(total_bytes, total_bytes);
491         }
492
493         if ((count & 1) && !is_write)
494                 /* work around rw_dev_block() limitation 3 (works for reads only?) */
495                 rw_dev_block(dev, 0, dummy, sizeof(dummy), 0);
496
497         printf("\n");
498         return ret;
499 }
500
501 static int read_write_ram(struct usb_dev_handle *dev, void *buffer, int bytes, int is_write)
502 {
503         int mx_cmd = is_write ? CMD_SEC_RAM_WRITE : CMD_SEC_READ;
504         int total_bytes = bytes;
505         u8 *buff = buffer;
506         u32 addr = 0x200000;
507         int i, ret = 0;
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
514         set_ram_mode(dev, C_RAM_TMP_ON);
515
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
531         /* only D0-D7 connected.. */
532         for (i = 0; i < total_bytes; i += 2)
533                 ((u8 *)buffer)[i] = 0;
534
535         printf("\n");
536         return ret;
537
538 }
539
540 static 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
575         return cnt;
576 }
577
578 static int erase_page(struct usb_dev_handle *dev, u32 addr, int whole)
579 {
580         dev_cmd_t cmd;
581         u8 buff[5];
582         int i, ret;
583
584         prepare_cmd(&cmd, CMD_SEC_ERASE);
585         cmd.write_flag = 1;
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;
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);
600         cmd.rom_rw.addrb2 = addr >> (16 + 1);
601         cmd.rom_rw.addrb1 = addr >> (8 + 1);
602         cmd.rom_rw.addrb0 = addr >> 1;
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
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;
622         }
623
624         return 0;
625 }
626
627 static int erase_seq(struct usb_dev_handle *dev, u32 size)
628 {
629         const page_table_t *table;
630         u32 addr, page_size = 0;
631         u32 rom0_id, rom1_id;
632         int count, ret;
633
634         ret = read_flash_rom_id(dev, 0, &rom0_id);
635         if (ret < 0)
636                 return ret;
637
638         ret = read_flash_rom_id(dev, 1, &rom1_id);
639         if (ret < 0)
640                 return ret;
641
642         if (rom0_id != rom1_id)
643                 fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n",
644                         rom0_id, rom1_id);
645
646         table = get_page_table(rom0_id);
647         if (table == NULL)
648                 return -1;
649
650         ret = increment_erase_cnt(dev);
651         if (ret < 0)
652                 fprintf(stderr, "warning: coun't increase erase counter\n");
653
654         printf("erasing flash... (erase count=%u)\n", ret);
655
656         for (addr = 0, count = 0; addr < size; addr += page_size, count++) {
657                 print_progress(addr, size);
658
659                 ret = erase_page(dev, addr, 0);
660                 if (ret < 0)
661                         return ret;
662
663                 ret = get_page_size(table, addr, &page_size);
664                 if (ret != 0)
665                         break;
666         }
667
668         if (count & 1)
669                 /* ??? */
670                 /* must submit even number of erase commands (fw bug?) */
671                 erase_page(dev, 0, 0);
672
673         print_progress(addr, size);
674         printf("\n");
675
676         return ret;
677 }
678
679 static int erase_all(struct usb_dev_handle *dev, u32 size)
680 {
681         int ret;
682
683         ret = increment_erase_cnt(dev);
684         if (ret < 0)
685                 fprintf(stderr, "warning: couldn't increase erase counter\n");
686
687         printf("erasing flash0, count=%u ...", ret);
688         fflush(stdout);
689
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");
703         return ret;
704 }
705
706 static 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
742 static 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
760 static 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) {
790                 fprintf(stderr, "failed to read file: %s", fname);
791                 perror("");
792                 goto fail;
793         }
794
795         *buff_out = data;
796         *size = file_size;
797         fclose(file);
798         return 0;
799
800 fail:
801         fclose(file);
802         return -1;
803 }
804
805 static 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
816         ret = fwrite(buff, 1, size, file);
817         if (ret != size) {
818                 fprintf(stderr, "write failed to %s", fname);
819                 perror("");
820         } else
821                 printf("saved to \"%s\".\n", fname);
822         fclose(file);
823         
824         return 0;
825 }
826
827 static 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
863 found:
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);
877                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
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
892 static void release_device(struct usb_dev_handle *device)
893 {
894         usb_release_interface(device, 0);
895         usb_close(device);
896 }
897
898 static 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"
904                 "%s [-i] [-g] [-e] [-r [file]] [-w <file>] ...\n"
905                 "  -i         print some info about connected device\n"
906                 "  -g         print some info about game ROM inside device\n"
907                 "  -e[1]      erase whole flash ROM in device, '1' uses different erase method\n"
908                 "  -m[1-3]    set MX mode: 2M+RAM, 4M no RAM, 4M+RAM\n"
909                 "  -f         skip file check\n"
910                 "  -r [file]  copy game image from device to file; can autodetect filename\n"
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",
916                 app_name);
917 }
918
919 int main(int argc, char *argv[])
920 {
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;
924         int pr_dev_info = 0, pr_rom_info = 0, do_read = 0, mx_mode = 0;
925         int erase_method = 0, do_erase_size = 0;
926         int w_fsize = 0, sw_fsize = 0;
927         struct usb_dev_handle *device;
928         char fname_buff[65];
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;
945                         if (argv[i][2] == '1')
946                                 erase_method = 1;
947                         break;
948                 case 'f':
949                         do_check = 0;
950                         break;
951                 case 'v':
952                         do_verify = 1;
953                         break;
954                 case 'm':
955                         mx_mode = argv[i][2];
956                         break;
957                 case 'r':
958                         do_read = 1;
959                         if (argv[i+1] && argv[i+1][0] != '-')
960                                 r_fname = argv[++i];
961                         break;
962                 case 'w':
963                         if (argv[i+1] && argv[i+1][0] != '-')
964                                 w_fname = argv[++i];
965                         else
966                                 goto breakloop;
967                         break;
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:
985                                 goto breakloop;
986                         }
987                         break;
988                 default:
989                         goto breakloop;
990                 }
991         }
992
993 breakloop:
994         if (i <= 1 || i < argc) {
995                 usage(argv[0]);
996                 return 1;
997         }
998
999         /* preparations */
1000         if (w_fname != NULL) {
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);
1009                         return 1;
1010                 }
1011
1012                 ret = read_file(w_fname, &w_fdata, &w_fsize, 0x400000);
1013                 if (ret < 0)
1014                         return 1;
1015
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
1029                 if (do_erase_size < w_fsize)
1030                         do_erase_size = w_fsize;
1031         }
1032         if (sw_fname != NULL) {
1033                 ret = read_file(sw_fname, &sw_fdata, &sw_fsize, 0x8000*2);
1034                 if (ret < 0)
1035                         return 1;
1036         }
1037         if (sw_fdata != NULL || do_clear_ram) {
1038                 if (sw_fsize < 0x8000*2) {
1039                         sw_fdata = realloc(sw_fdata, 0x8000*2);
1040                         if (sw_fdata == NULL) {
1041                                 fprintf(stderr, "low mem\n");
1042                                 return 1;
1043                         }
1044                         memset((u8 *)sw_fdata + sw_fsize, 0, 0x8000*2 - sw_fsize);
1045                 }
1046                 sw_fsize = 0x8000*2;
1047         }
1048         if (w_fname == NULL && sw_fname == NULL && do_verify) {
1049                 fprintf(stderr, "warning: -w or -sw not specified, -v ignored.\n");
1050                 do_verify = 0;
1051         }
1052
1053         /* init */
1054         usb_init();
1055
1056         device = get_device();
1057         if (device == NULL)
1058                 return 1;
1059
1060         /* info */
1061         if (pr_dev_info) {
1062                 ret = print_device_info(device);
1063                 if (ret < 0)
1064                         goto end;
1065         }
1066
1067         if (pr_rom_info) {
1068                 ret = print_game_info(device);
1069                 if (ret < 0)
1070                         goto end;
1071         }
1072
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
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         }
1104
1105         /* write flash */
1106         if (w_fdata != NULL) {
1107                 char *p;
1108
1109                 ret = read_write_rom(device, 0, w_fdata, w_fsize, 1);
1110                 if (ret < 0)
1111                         goto end;
1112
1113                 p = strrchr(w_fname, '/');
1114                 p = (p == NULL) ? w_fname : p + 1;
1115
1116                 ret = write_filename(device, p, FILENAME_ROM0);
1117                 if (ret < 0)
1118                         fprintf(stderr, "warning: failed to save ROM filename\n");
1119         }
1120
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 */
1151         if (do_read && r_fname == NULL) {
1152                 ret = read_filename(device, fname_buff, sizeof(fname_buff), FILENAME_ROM0);
1153                 if (ret < 0)
1154                         return ret;
1155                 r_fname = fname_buff;
1156                 if (r_fname[0] == 0)
1157                         r_fname = "rom.gen";
1158         }
1159
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
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";
1183         }
1184
1185         if (sr_fname != NULL || do_verify) {
1186                 sr_fdata = malloc(0x8000*2);
1187                 if (sr_fdata == NULL) {
1188                         fprintf(stderr, "low mem\n");
1189                         goto end;
1190                 }
1191
1192                 ret = read_write_ram(device, sr_fdata, 0x8000*2, 0);
1193                 if (ret < 0)
1194                         goto end;
1195         }
1196
1197         if (sr_fname != NULL)
1198                 write_file(sr_fname, sr_fdata, 0x8000*2);
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) {
1210                 ret = memcmp(sw_fdata, sr_fdata, 0x8000*2);
1211                 if (ret == 0)
1212                         printf("RAM verification passed.\n");
1213                 else
1214                         printf("RAM verification FAILED!\n");
1215         }
1216
1217         printf("all done.\n");
1218         ret = 0;
1219
1220 end:
1221         if (w_fdata != NULL)
1222                 free(w_fdata);
1223         if (r_fdata != NULL)
1224                 free(r_fdata);
1225
1226         release_device(device);
1227
1228         return ret;
1229 }
1230