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