working read function
[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 /*****************************************************************************/
23
24 #define CMD_ATM_READY           0x22
25 #define CMD_SEC_GET_NAME        'G'     /* filename r/w */
26 #define CMD_SEC_PUT_NAME        'P'
27 #define CMD_SEC_DEVID           'L'     /* read flash device ID */
28 #define CMD_SEC_ERASE           'E'
29 #define CMD_SEC_READY           'C'     /* is flash ready? */
30 #define CMD_SEC_READ            'R'
31
32 /* bus controllers */
33 #define CTL_DATA_BUS    0x55
34 #define CTL_ADDR_BUS    0xAA
35
36 #define W_COUNTER       0xA0
37 #define W_CNT_WRITE     0x01
38 #define W_CNT_READ      0x00
39
40 #define FILENAME_ROM0   0
41 #define FILENAME_ROM1   1
42 #define FILENAME_RAM    2
43
44 typedef struct {
45         u8 magic[4];
46         u8 reserved[8];
47         u8 write_flag;
48         u8 reserved2[2];
49         u8 magic2;
50         u8 mx_cmd;
51         union {                         /* 0x11 */
52                 struct {
53                         u8 which_device;
54                 } dev_info;
55                 struct {
56                         u8 addrb2;      /* most significant */
57                         u8 addrb1;
58                         u8 addrb0;
59                         u8 packets;     /* 64 byte usb packets */
60                 } rom_rw;
61                 struct {
62                         u8 which;
63                 } filename;
64                 struct {
65                         u8 cmd;
66                         u8 action;
67                         u8 b0;
68                         u8 b1;
69                         u8 b2;
70                         u8 b3;
71                 } write_cnt;
72                 struct {
73                         u8 which;
74                         u8 dev_id;
75                 } rom_id;
76         };
77         u8 pad[8];
78 } dev_cmd_t;
79
80 typedef struct {
81         u8 firmware_ver[4];
82         u8 bootloader_ver[4];
83         char names[56];
84 } dev_info_t;
85
86 typedef struct {
87         u32 start_addr;
88         u32 end_addr;
89         u32 page_size;
90 } page_table_t;
91
92 static const page_table_t p_AM29LV320DB[] =
93 {
94         { 0x000000, 0x00ffff, 0x002000 },
95         { 0x010000, 0x3fffff, 0x010000 },
96         { 0x000000, 0x000000, 0x000000 },
97 };
98
99 static const page_table_t p_AM29LV320DT[] =
100 {
101         { 0x000000, 0x3effff, 0x010000 },
102         { 0x3f0000, 0x3fffff, 0x002000 },
103         { 0x000000, 0x000000, 0x000000 },
104 };
105
106 static const page_table_t p_2x_16[] =
107 {
108         { 0x000000, 0x003fff, 0x004000 },
109         { 0x004000, 0x007fff, 0x002000 },
110         { 0x008000, 0x00ffff, 0x008000 },
111         { 0x010000, 0x1fffff, 0x010000 },
112         { 0x200000, 0x203fff, 0x004000 },
113         { 0x204000, 0x207fff, 0x002000 },
114         { 0x208000, 0x20ffff, 0x008000 },
115         { 0x210000, 0x3fffff, 0x010000 },
116         { 0x000000, 0x000000, 0x000000 },
117 };
118
119 /*****************************************************************************/
120
121 static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd)
122 {
123         memset(dev_cmd, 0, sizeof(*dev_cmd));
124
125         memcpy(dev_cmd->magic, "USBC", 4);
126         dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
127         dev_cmd->mx_cmd = cmd;
128 }
129
130 static int write_data(struct usb_dev_handle *dev, void *data, int len)
131 {
132         int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
133         if (ret < 0) {
134                 fprintf(stderr, "failed to write:\n");
135                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
136         } else if (ret != len)
137                 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
138         
139         return ret;
140 }
141
142 static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
143 {
144         return write_data(dev, cmd, sizeof(*cmd));
145 }
146
147 static int read_data(struct usb_dev_handle *dev, void *buff, int size)
148 {
149         int ret = usb_bulk_read(dev, 0x82, buff, size, 2000);
150         if (ret < 0) {
151                 fprintf(stderr, "failed to read:\n");
152                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
153         } else if (ret != size)
154                 printf("read_data: read only %d of %d bytes\n", ret, size);
155
156         return ret;
157 }
158
159 static int read_info(struct usb_dev_handle *device, u8 ctl_id, dev_info_t *info)
160 {
161         dev_cmd_t cmd;
162         int ret;
163
164         prepare_cmd(&cmd, CMD_ATM_READY);
165         cmd.dev_info.which_device = ctl_id;
166         memset(info, 0, sizeof(*info));
167
168         ret = write_cmd(device, &cmd);
169         if (ret < 0)
170                 return ret;
171
172         ret = read_data(device, info, sizeof(*info));
173         if (ret < 0)
174                 return ret;
175         
176         return 0;
177 }
178
179 static void printf_info(dev_info_t *info)
180 {
181         printf(" firmware version:   %X.%X.%X%c\n", info->firmware_ver[0],
182                 info->firmware_ver[1], info->firmware_ver[2], info->firmware_ver[3]);
183         printf(" bootloader version: %X.%X.%X%c\n", info->bootloader_ver[0],
184                 info->bootloader_ver[1], info->bootloader_ver[2], info->bootloader_ver[3]);
185         info->names[sizeof(info->names) - 1] = 0;
186         printf(" device name:        %s\n", info->names);
187 }
188
189 static void print_progress(u32 done, u32 total)
190 {
191         int i, step;
192
193         printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
194         printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); /* 20 */
195         printf("\b\b\b\b\b\b");
196         printf("%06x/%06x |", done, total);
197
198         step = total / 20;
199         for (i = step; i <= total; i += step)
200                 printf("%c", done >= i ? '=' : '-');
201         printf("| %3d%%", done * 100 / total);
202         fflush(stdout);
203 }
204
205 static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
206 {
207         char buff[65];
208         dev_cmd_t cmd;
209         int ret;
210
211         prepare_cmd(&cmd, CMD_SEC_GET_NAME);
212         cmd.filename.which = which;
213         memset(buff, 0, sizeof(buff));
214
215         ret = write_cmd(dev, &cmd);
216         if (ret < 0)
217                 return ret;
218
219         ret = read_data(dev, buff, 64);
220         if (ret < 0)
221                 return ret;
222
223         strncpy(dst, buff, len);
224         dst[len - 1] = 0;
225
226         return 0;
227 }
228
229 static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which)
230 {
231         dev_cmd_t cmd;
232         char buff[64];
233         int ret, len;
234
235         len = strlen(fname);
236         if (len > 63)
237                 len = 63;
238         strncpy(buff, fname, len);
239         buff[len] = 0;
240
241         prepare_cmd(&cmd, CMD_SEC_PUT_NAME);
242         cmd.filename.which = which;
243
244         ret = write_cmd(dev, &cmd);
245         if (ret < 0)
246                 return ret;
247
248         return write_data(dev, buff, len + 1);
249 }
250
251 static int read_w_counter(struct usb_dev_handle *dev, u32 *val)
252 {
253         dev_info_t dummy_info;
254         dev_cmd_t cmd;
255         u8 buff[4];
256         int ret;
257
258         /* must perform dummy info read here,
259          * or else device hangs after close (firmware bug?) */
260         ret = read_info(dev, CTL_DATA_BUS, &dummy_info);
261         if (ret < 0)
262                 return ret;
263
264         prepare_cmd(&cmd, CMD_ATM_READY);
265         cmd.write_cnt.cmd = W_COUNTER;
266         cmd.write_cnt.action = W_CNT_READ;
267
268         ret = write_cmd(dev, &cmd);
269         if (ret < 0)
270                 return ret;
271
272         ret = read_data(dev, buff, sizeof(buff));
273         if (ret < 0)
274                 return ret;
275
276         *val = *(u32 *)buff;
277         return 0;
278 }
279
280 static int read_flash_rom_id(struct usb_dev_handle *dev, int is_second, u32 *val)
281 {
282         dev_cmd_t cmd;
283         u8 buff[2];
284         int ret;
285
286         prepare_cmd(&cmd, CMD_SEC_DEVID);
287         cmd.rom_id.which = is_second ? 0x10 : 0;
288         cmd.rom_id.dev_id = 0;
289
290         ret = write_cmd(dev, &cmd);
291         if (ret < 0)
292                 return ret;
293
294         ret = read_data(dev, buff, sizeof(buff));
295         if (ret < 0)
296                 return ret;
297
298         *val = *(u16 *)buff << 16;
299
300         cmd.rom_id.dev_id = 1;
301         ret = write_cmd(dev, &cmd);
302         if (ret < 0)
303                 return ret;
304
305         ret = read_data(dev, buff, sizeof(buff));
306         if (ret < 0)
307                 return ret;
308         
309         *val |= *(u16 *)buff;
310         return 0;
311 }
312
313 static const page_table_t *get_page_table(u32 rom_id)
314 {
315         switch (rom_id) {
316         case 0x0100F922:
317                 return p_AM29LV320DB;
318         case 0x0100F422:
319                 return p_AM29LV320DT;
320         case 0x01004922:
321         case 0xC2004922:
322                 return p_2x_16;
323         default:
324                 fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
325         }
326
327         return NULL;
328 }
329
330 static int get_page_size(const page_table_t *table, u32 addr, u32 *size)
331 {
332         const page_table_t *t;
333         
334         for (t = table; t->end_addr != 0; t++) {
335                 if (addr >= t->start_addr && addr <= t->end_addr) {
336                         *size = t->page_size;
337                         return 0;
338                 }
339         }
340
341         if (addr == t[-1].end_addr + 1)
342                 return 1;       /* last */
343         
344         fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
345         return -1;
346 }
347
348 static int erase_page(struct usb_dev_handle *dev, u32 addr)
349 {
350         dev_cmd_t cmd;
351         u8 buff[10];
352         int i, ret;
353
354         prepare_cmd(&cmd, CMD_SEC_ERASE);
355         cmd.write_flag = 1;
356         cmd.rom_rw.addrb2 = addr >> 16;
357         cmd.rom_rw.addrb1 = addr >> 8;
358         cmd.rom_rw.addrb0 = addr;
359
360         ret = write_cmd(dev, &cmd);
361         if (ret < 0)
362                 return ret;
363
364         ret = read_data(dev, buff, sizeof(buff));
365         if (ret < 0)
366                 return ret;
367         
368         prepare_cmd(&cmd, CMD_SEC_READY);
369         cmd.rom_rw.addrb2 = addr >> 16;
370         cmd.rom_rw.addrb1 = addr >> 8;
371         cmd.rom_rw.addrb0 = addr;
372
373         for (i = 0; i < 100; i++) {
374                 ret = write_cmd(dev, &cmd);
375                 if (ret < 0)
376                         return ret;
377
378                 ret = read_data(dev, buff, sizeof(buff));
379                 if (ret < 0)
380                         return ret;
381
382                 if (ret > 4 && buff[4] == 1)
383                         break;
384
385                 usleep(50);
386         }
387
388         printf("i = %d\n", i);
389         return 0;
390 }
391
392 /* limitations:
393  * - bytes must be multiple of 64
394  * - bytes must be less than 16k
395  * - must perform even number of reads (firmware bug?) */
396 static int read_rom_block(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes)
397 {
398         dev_cmd_t cmd;
399         int ret;
400
401         prepare_cmd(&cmd, CMD_SEC_READ);
402         cmd.rom_rw.addrb2 = addr >> (16 + 1);
403         cmd.rom_rw.addrb1 = addr >> (8 + 1);
404         cmd.rom_rw.addrb0 = addr >> 1;
405         cmd.rom_rw.packets = bytes / 64;
406
407         ret = write_cmd(dev, &cmd);
408         if (ret < 0)
409                 return ret;
410
411         bytes &= ~63;
412         ret = read_data(dev, buffer, bytes);
413         if (ret < 0)
414                 return ret;
415         if (ret != bytes)
416                 fprintf(stderr, "read_rom_block warning: read only %d/%d bytes\n", ret, bytes);
417
418         return ret;
419 }
420
421 #define READ_BLK_SIZE (0x2000)  /* 8K */
422
423 static int read_rom(struct usb_dev_handle *dev, u32 addr, void *buffer, int bytes)
424 {
425         int total_bytes = bytes;
426         u8 *buff = buffer;
427         u8 dummy[64 * 4];
428         int count, ret;
429
430         if (addr & 1)
431                 fprintf(stderr, "read_rom: can't handle odd address %06x, "
432                                 "LSb will be ignored\n", addr);
433         if (bytes & 63)
434                 fprintf(stderr, "read_rom: byte count must be multiple of 64, "
435                                 "last %d bytes will not be read\n", bytes & 63);
436
437         printf("reading flash ROM...\n");
438
439         /* read in blocks */
440         for (count = 0; bytes >= READ_BLK_SIZE; count++) {
441                 print_progress(buff - (u8 *)buffer, total_bytes);
442
443                 ret = read_rom_block(dev, addr, buff, READ_BLK_SIZE);
444                 if (ret < 0)
445                         return ret;
446                 buff += READ_BLK_SIZE;
447                 addr += READ_BLK_SIZE;
448                 bytes -= READ_BLK_SIZE;
449         }
450         print_progress(buff - (u8 *)buffer, total_bytes);
451
452         ret = 0;
453         if (bytes != 0) {
454                 ret = read_rom_block(dev, addr, buff, bytes);
455                 count++;
456                 print_progress(total_bytes, total_bytes);
457         }
458
459         if (count & 1)
460                 /* work around read_rom_block() limitation 3 */
461                 read_rom_block(dev, 0, dummy, sizeof(dummy));
462
463         printf("\n");
464         return ret;
465 }
466
467 static usb_dev_handle *get_device(void)
468 {
469         struct usb_dev_handle *handle;
470         struct usb_device *dev;
471         struct usb_bus *bus;
472         int i, ret;
473
474         ret = usb_find_busses();
475         if (ret <= 0) {
476                 fprintf(stderr, "Can't find USB busses\n");
477                 return NULL;
478         }
479
480         ret = usb_find_devices();
481         if (ret <= 0) {
482                 fprintf(stderr, "Can't find USB devices\n");
483                 return NULL;
484         }
485
486         bus = usb_get_busses();
487         for (; bus; bus = bus->next)
488         {
489                 for (dev = bus->devices; dev; dev = dev->next)
490                 {
491                         for (i = 0; i < array_size(g_devices); i++)
492                         {
493                                 if (dev->descriptor.idVendor == g_devices[i].vendor &&
494                                                 dev->descriptor.idProduct == g_devices[i].product)
495                                         goto found;
496                         }
497                 }
498         }
499
500         fprintf(stderr, "device not found.\n");
501         return NULL;
502
503 found:
504         printf("found %s.\n", g_devices[i].name);
505
506         handle = usb_open(dev);
507         if (handle == NULL) {
508                 fprintf(stderr, "failed to open device:\n");
509                 fprintf(stderr, "%s\n", usb_strerror());
510                 return NULL;
511         }
512
513         ret = usb_set_configuration(handle, 1);
514         if (ret != 0) {
515                 fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n",
516                         bus->dirname, dev->filename);
517                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
518                 return NULL;
519         }
520
521         ret = usb_claim_interface(handle, 0);
522         if (ret != 0) {
523                 fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n",
524                         bus->dirname, dev->filename);
525                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
526                 return NULL;
527         }
528
529         return handle;
530 }
531
532 static void release_device(struct usb_dev_handle *device)
533 {
534         usb_release_interface(device, 0);
535         usb_close(device);
536 }
537
538 int main(int argc, char *argv[])
539 {
540         struct usb_dev_handle *device;
541         char fname[65];
542         u32 counter, rom0_id, rom1_id;
543         dev_info_t info;
544         char *buff;
545         int ret;
546
547         usb_init();
548
549         device = get_device();
550         if (device == NULL)
551                 return 1;
552
553         printf("data bus controller:\n");
554         ret = read_info(device, CTL_DATA_BUS, &info);
555         if (ret < 0)
556                 goto end;
557         printf_info(&info);
558
559         printf("address bus controller:\n");
560         ret = read_info(device, CTL_ADDR_BUS, &info);
561         if (ret < 0)
562                 goto end;
563         printf_info(&info);
564
565         ret = read_filename(device, fname, sizeof(fname), FILENAME_ROM0);
566         if (ret < 0)
567                 goto end;
568         printf("ROM filename:  %s\n", fname);
569
570         ret = read_filename(device, fname, sizeof(fname), FILENAME_RAM);
571         if (ret < 0)
572                 goto end;
573         printf("SRAM filename: %s\n", fname);
574
575         ret = read_w_counter(device, &counter);
576         if (ret < 0)
577                 goto end;
578         printf("flash writes:  %u\n", counter);
579
580         ret = read_flash_rom_id(device, 0, &rom0_id);
581         if (ret < 0)
582                 goto end;
583         printf("flash rom0 id: %08x\n", rom0_id);
584
585         ret = read_flash_rom_id(device, 1, &rom1_id);
586         if (ret < 0)
587                 goto end;
588         printf("flash rom1 id: %08x\n", rom1_id);
589
590         if (rom0_id != rom1_id)
591                 fprintf(stderr, "Warning: flash ROM ids differ: %08x %08x\n",
592                         rom0_id, rom1_id);
593  
594 #define XSZ (0x400000)
595         buff = malloc(XSZ);
596         ret = read_rom(device, 0, buff, XSZ);
597         if (ret < 0)
598                 goto end;
599         {
600                 FILE *f = fopen("dump", "wb");
601                 fwrite(buff, 1, XSZ, f);
602                 fclose(f);
603         }
604
605
606 end:
607         release_device(device);
608
609         return ret;
610 }
611