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