7565f5c6711e7efe2b726b14fe6fc9c867917e53
[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
31 /* bus controllers */
32 #define CTL_DATA_BUS    0x55
33 #define CTL_ADDR_BUS    0xAA
34
35 #define W_COUNTER       0xA0
36 #define W_CNT_WRITE     0x01
37 #define W_CNT_READ      0x00
38
39 #define FILENAME_ROM0   0
40 #define FILENAME_ROM1   1
41 #define FILENAME_RAM    2
42
43 typedef struct {
44         u8 magic[4];
45         u8 reserved[8];
46         u8 write_flag;
47         u8 reserved2[2];
48         u8 magic2;
49         u8 mx_cmd;
50         union {
51                 struct {
52                         u8 which_device;
53                 } dev_info;
54                 struct {
55                         u8 addrb2;      /* most significant */
56                         u8 addrb1;
57                         u8 addrb0;
58                         u8 num_pages;
59                 } rom_rw;
60                 struct {
61                         u8 which;
62                 } filename;
63                 struct {
64                         u8 cmd;
65                         u8 action;
66                         u8 b0;
67                         u8 b1;
68                         u8 b2;
69                         u8 b3;
70                 } write_cnt;
71                 struct {
72                         u8 which;
73                         u8 dev_id;
74                 } rom_id;
75         };
76         u8 pad[8];
77 } dev_cmd_t;
78
79 typedef struct {
80         u8 firmware_ver[4];
81         u8 bootloader_ver[4];
82         char names[56];
83 } dev_info_t;
84
85 typedef struct {
86         u32 start_addr;
87         u32 end_addr;
88         u32 page_size;
89 } page_table_t;
90
91 static const page_table_t p_AM29LV320DB[] =
92 {
93         { 0x000000, 0x00ffff, 0x002000 },
94         { 0x010000, 0x3fffff, 0x010000 },
95         { 0x000000, 0x000000, 0x000000 },
96 };
97
98 static const page_table_t p_AM29LV320DT[] =
99 {
100         { 0x000000, 0x3effff, 0x010000 },
101         { 0x3f0000, 0x3fffff, 0x002000 },
102         { 0x000000, 0x000000, 0x000000 },
103 };
104
105 /*****************************************************************************/
106
107 static void prepare_cmd(dev_cmd_t *dev_cmd, u8 cmd)
108 {
109         memset(dev_cmd, 0, sizeof(*dev_cmd));
110
111         memcpy(dev_cmd->magic, "USBC", 4);
112         dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
113         dev_cmd->mx_cmd = cmd;
114 }
115
116 static int write_data(struct usb_dev_handle *dev, void *data, int len)
117 {
118         int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
119         if (ret < 0) {
120                 fprintf(stderr, "failed to write:\n");
121                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
122         } else if (ret != len)
123                 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
124         
125         return ret;
126 }
127
128 static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
129 {
130         return write_data(dev, cmd, sizeof(*cmd));
131 }
132
133 static int read_data(struct usb_dev_handle *dev, void *buff, int size)
134 {
135         int ret = usb_bulk_read(dev, 0x82, buff, size, 2000);
136         if (ret < 0) {
137                 fprintf(stderr, "failed to read:\n");
138                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
139         } else if (ret != size)
140                 printf("read_data: read only %d of %d bytes\n", ret, size);
141
142         return ret;
143 }
144
145 static int read_info(struct usb_dev_handle *device, u8 ctl_id)
146 {
147         dev_cmd_t cmd;
148         dev_info_t info;
149         int ret;
150
151         prepare_cmd(&cmd, CMD_ATM_READY);
152         cmd.dev_info.which_device = ctl_id;
153         memset(&info, 0, sizeof(info));
154
155         ret = write_cmd(device, &cmd);
156         if (ret < 0)
157                 return ret;
158
159         ret = read_data(device, &info, sizeof(info));
160         if (ret < 0)
161                 return ret;
162         
163         printf(" firmware version:   %X.%X.%X%c\n", info.firmware_ver[0],
164                 info.firmware_ver[1], info.firmware_ver[2], info.firmware_ver[3]);
165         printf(" bootloader version: %X.%X.%X%c\n", info.bootloader_ver[0],
166                 info.bootloader_ver[1], info.bootloader_ver[2], info.bootloader_ver[3]);
167         info.names[sizeof(info.names) - 1] = 0;
168         printf(" device name:        %s\n", info.names);
169
170         return 0;
171 }
172
173 static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
174 {
175         char buff[65];
176         dev_cmd_t cmd;
177         int ret;
178
179         prepare_cmd(&cmd, CMD_SEC_GET_NAME);
180         cmd.filename.which = which;
181         memset(buff, 0, sizeof(buff));
182
183         ret = write_cmd(dev, &cmd);
184         if (ret < 0)
185                 return ret;
186
187         ret = read_data(dev, buff, 64);
188         if (ret < 0)
189                 return ret;
190
191         strncpy(dst, buff, len);
192         dst[len - 1] = 0;
193
194         return 0;
195 }
196
197 static int write_filename(struct usb_dev_handle *dev, const char *fname, u8 which)
198 {
199         dev_cmd_t cmd;
200         char buff[64];
201         int ret, len;
202
203         len = strlen(fname);
204         if (len > 63)
205                 len = 63;
206         strncpy(buff, fname, len);
207         buff[len] = 0;
208
209         prepare_cmd(&cmd, CMD_SEC_PUT_NAME);
210         cmd.filename.which = which;
211
212         ret = write_cmd(dev, &cmd);
213         if (ret < 0)
214                 return ret;
215
216         return write_data(dev, buff, len + 1);
217 }
218
219 static int read_w_counter(struct usb_dev_handle *dev, u32 *val)
220 {
221         dev_cmd_t cmd;
222         u8 buff[16];
223         int ret;
224
225         prepare_cmd(&cmd, CMD_ATM_READY);
226         cmd.write_cnt.cmd = W_COUNTER;
227         cmd.write_cnt.action = W_CNT_READ;
228
229         ret = write_cmd(dev, &cmd);
230         if (ret < 0)
231                 return ret;
232
233         ret = read_data(dev, buff, sizeof(buff));
234         if (ret < 0)
235                 return ret;
236         
237         *val = *(u32 *)buff;
238         return 0;
239 }
240
241 static int read_flash_rom_id(struct usb_dev_handle *dev, u32 *val)
242 {
243         dev_cmd_t cmd;
244         u8 buff[2];
245         int ret;
246
247         prepare_cmd(&cmd, CMD_SEC_DEVID);
248         cmd.write_flag = 1;                     /* XXX why? */
249         cmd.rom_id.dev_id = 1;
250         cmd.rom_id.which = 0;
251
252         ret = write_cmd(dev, &cmd);
253         if (ret < 0)
254                 return ret;
255
256         ret = read_data(dev, buff, sizeof(buff));
257         if (ret < 0)
258                 return ret;
259
260         *val = *(u16 *)buff << 16;
261
262         cmd.rom_id.which = 0;
263         ret = write_cmd(dev, &cmd);
264         if (ret < 0)
265                 return ret;
266
267         ret = read_data(dev, buff, sizeof(buff));
268         if (ret < 0)
269                 return ret;
270         
271         *val |= *(u16 *)buff;
272         return 0;
273 }
274
275 static const page_table_t *get_page_table(u32 rom_id)
276 {
277         switch (rom_id) {
278         case 0x0100F922:
279                 return p_AM29LV320DB;
280         case 0x0100F422:
281                 return p_AM29LV320DT;
282         default:
283                 fprintf(stderr, "unrecognized ROM id: %08x\n", rom_id);
284         }
285
286         return NULL;
287 }
288
289 static int get_page_size(const page_table_t *table, u32 addr, u32 *size)
290 {
291         const page_table_t *t;
292         
293         for (t = table; t->end_addr != 0; t++) {
294                 if (addr >= t->start_addr && addr <= t->end_addr) {
295                         *size = t->page_size;
296                         return 0;
297                 }
298         }
299
300         if (addr == t[-1].end_addr + 1)
301                 return 1;       /* last */
302         
303         fprintf(stderr, "get_page_size: failed on addr %06x\n", addr);
304         return -1;
305 }
306
307 static int erase_sector(struct usb_dev_handle *dev, u32 addr)
308 {
309         dev_cmd_t cmd;
310         u8 buff[10];
311         int i, ret;
312
313         prepare_cmd(&cmd, CMD_SEC_ERASE);
314         cmd.write_flag = 1;
315         cmd.rom_rw.addrb2 = addr >> 16;
316         cmd.rom_rw.addrb1 = addr >> 8;
317         cmd.rom_rw.addrb0 = addr;
318
319         ret = write_cmd(dev, &cmd);
320         if (ret < 0)
321                 return ret;
322
323         ret = read_data(dev, buff, sizeof(buff));
324         if (ret < 0)
325                 return ret;
326         
327         prepare_cmd(&cmd, CMD_SEC_READY);
328         cmd.rom_rw.addrb2 = addr >> 16;
329         cmd.rom_rw.addrb1 = addr >> 8;
330         cmd.rom_rw.addrb0 = addr;
331
332         for (i = 0; i < 100; i++) {
333                 ret = write_cmd(dev, &cmd);
334                 if (ret < 0)
335                         return ret;
336
337                 ret = read_data(dev, buff, sizeof(buff));
338                 if (ret < 0)
339                         return ret;
340
341                 if (ret > 4 && buff[4] == 1)
342                         break;
343
344                 usleep(50);
345         }
346
347         printf("i = %d\n", i);
348         return 0;
349 }
350
351 static usb_dev_handle *get_device(void)
352 {
353         struct usb_dev_handle *handle;
354         struct usb_device *dev;
355         struct usb_bus *bus;
356         int i, ret;
357
358         ret = usb_find_busses();
359         if (ret <= 0) {
360                 fprintf(stderr, "Can't find USB busses\n");
361                 return NULL;
362         }
363
364         ret = usb_find_devices();
365         if (ret <= 0) {
366                 fprintf(stderr, "Can't find USB devices\n");
367                 return NULL;
368         }
369
370         bus = usb_get_busses();
371         for (; bus; bus = bus->next)
372         {
373                 for (dev = bus->devices; dev; dev = dev->next)
374                 {
375                         for (i = 0; i < array_size(g_devices); i++)
376                         {
377                                 if (dev->descriptor.idVendor == g_devices[i].vendor &&
378                                                 dev->descriptor.idProduct == g_devices[i].product)
379                                         goto found;
380                         }
381                 }
382         }
383
384         fprintf(stderr, "device not found.\n");
385         return NULL;
386
387 found:
388         printf("found %s.\n", g_devices[i].name);
389
390         handle = usb_open(dev);
391         if (handle == NULL) {
392                 fprintf(stderr, "failed to open device:\n");
393                 fprintf(stderr, "%s\n", usb_strerror());
394                 return NULL;
395         }
396
397         ret = usb_set_configuration(handle, 1);
398         if (ret != 0) {
399                 fprintf(stderr, "couldn't set configuration for /*/bus/usb/%s/%s:\n",
400                         bus->dirname, dev->filename);
401                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
402                 return NULL;
403         }
404
405         ret = usb_claim_interface(handle, 0);
406         if (ret != 0) {
407                 fprintf(stderr, "couldn't claim /*/bus/usb/%s/%s:\n",
408                         bus->dirname, dev->filename);
409                 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
410                 return NULL;
411         }
412
413         return handle;
414 }
415
416 static void release_device(struct usb_dev_handle *device)
417 {
418         usb_release_interface(device, 0);
419         usb_close(device);
420 }
421
422 int main(int argc, char *argv[])
423 {
424         struct usb_dev_handle *device;
425         char fname[65];
426         u32 counter, rom_id;
427         int ret;
428
429         usb_init();
430
431         device = get_device();
432         if (device == NULL)
433                 return 1;
434
435         printf("data bus controller:\n");
436         ret = read_info(device, CTL_DATA_BUS);
437         if (ret < 0)
438                 goto end;
439
440         printf("address bus controller:\n");
441         ret = read_info(device, CTL_ADDR_BUS);
442         if (ret < 0)
443                 goto end;
444
445         ret = read_filename(device, fname, sizeof(fname), FILENAME_ROM0);
446         if (ret < 0)
447                 goto end;
448         printf("ROM filename:  %s\n", fname);
449
450         ret = read_filename(device, fname, sizeof(fname), FILENAME_RAM);
451         if (ret < 0)
452                 goto end;
453         printf("SRAM filename: %s\n", fname);
454
455         ret = read_w_counter(device, &counter);
456         if (ret < 0)
457                 goto end;
458         printf("flash writes:  %u\n", counter);
459
460         ret = read_flash_rom_id(device, &rom_id);
461         if (ret < 0)
462                 goto end;
463         printf("flash rom id:  %08x\n", rom_id);
464
465 end:
466         release_device(device);
467
468         return ret;
469 }
470