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