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