more commands
[megadrive.git] / mx / linux / main.c
CommitLineData
8c8e818c 1#include <stdio.h>
726b85c8 2#include <string.h>
8c8e818c 3#include <usb.h>
4
5
6typedef unsigned char u8;
7typedef unsigned short u16;
8typedef unsigned int u32;
9#define array_size(x) (sizeof(x) / sizeof(x[0]))
10
11static 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
fb4ee110 24#define CMD_ATM_READY 0x22
a35471cd 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? */
726b85c8 30
fb4ee110 31/* bus controllers */
32#define CTL_DATA_BUS 0x55
33#define CTL_ADDR_BUS 0xAA
34
a35471cd 35#define W_COUNTER 0xA0
36#define W_CNT_WRITE 0x01
37#define W_CNT_READ 0x00
38
fb4ee110 39#define FILENAME_ROM0 0
40#define FILENAME_ROM1 1
41#define FILENAME_RAM 2
726b85c8 42
43typedef struct {
8c8e818c 44 u8 magic[4];
a35471cd 45 u8 reserved[8];
46 u8 write_flag;
47 u8 reserved2[2];
8c8e818c 48 u8 magic2;
49 u8 mx_cmd;
50 union {
51 struct {
52 u8 which_device;
8c8e818c 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 {
fb4ee110 61 u8 which;
8c8e818c 62 } filename;
63 struct {
a35471cd 64 u8 cmd;
8c8e818c 65 u8 action;
a35471cd 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;
8c8e818c 75 };
76 u8 pad[8];
726b85c8 77} dev_cmd_t;
78
79typedef struct {
80 u8 firmware_ver[4];
81 u8 bootloader_ver[4];
82 char names[56];
83} dev_info_t;
84
a35471cd 85typedef struct {
86 u32 start_addr;
87 u32 end_addr;
88 u32 page_size;
89} page_table_t;
90
91static const page_table_t p_AM29LV320DB[] =
92{
93 { 0x000000, 0x00ffff, 0x002000 },
94 { 0x010000, 0x3fffff, 0x010000 },
95 { 0x000000, 0x000000, 0x000000 },
96};
97
98static const page_table_t p_AM29LV320DT[] =
99{
100 { 0x000000, 0x3effff, 0x010000 },
101 { 0x3f0000, 0x3fffff, 0x002000 },
102 { 0x000000, 0x000000, 0x000000 },
103};
104
105/*****************************************************************************/
106
726b85c8 107static 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);
fb4ee110 112 dev_cmd->magic2 = 0x67; /* MySCSICommand, EXCOMMAND */
726b85c8 113 dev_cmd->mx_cmd = cmd;
114}
115
a35471cd 116static int write_data(struct usb_dev_handle *dev, void *data, int len)
726b85c8 117{
a35471cd 118 int ret = usb_bulk_write(dev, 0x03, data, len, 2000);
726b85c8 119 if (ret < 0) {
120 fprintf(stderr, "failed to write:\n");
121 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
a35471cd 122 } else if (ret != len)
123 printf("write_cmd: wrote only %d of %d bytes\n", ret, len);
726b85c8 124
125 return ret;
126}
127
a35471cd 128static int write_cmd(struct usb_dev_handle *dev, dev_cmd_t *cmd)
129{
130 return write_data(dev, cmd, sizeof(*cmd));
131}
132
133static int read_data(struct usb_dev_handle *dev, void *buff, int size)
726b85c8 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)
a35471cd 140 printf("read_data: read only %d of %d bytes\n", ret, size);
8c8e818c 141
726b85c8 142 return ret;
143}
8c8e818c 144
fb4ee110 145static 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
a35471cd 159 ret = read_data(device, &info, sizeof(info));
fb4ee110 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
a35471cd 173static int read_filename(struct usb_dev_handle *dev, char *dst, int len, u8 which)
fb4ee110 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
a35471cd 187 ret = read_data(dev, buff, 64);
fb4ee110 188 if (ret < 0)
189 return ret;
190
191 strncpy(dst, buff, len);
192 dst[len - 1] = 0;
193
194 return 0;
195}
196
a35471cd 197static 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
219static 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
241static 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
275static 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
289static 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
307static 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
8c8e818c 351static 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
387found:
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);
726b85c8 401 fprintf(stderr, "%s (%d)\n", usb_strerror(), ret);
8c8e818c 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
416static void release_device(struct usb_dev_handle *device)
417{
418 usb_release_interface(device, 0);
419 usb_close(device);
420}
421
422int main(int argc, char *argv[])
423{
424 struct usb_dev_handle *device;
fb4ee110 425 char fname[65];
a35471cd 426 u32 counter, rom_id;
726b85c8 427 int ret;
8c8e818c 428
429 usb_init();
430
431 device = get_device();
432 if (device == NULL)
433 return 1;
434
726b85c8 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;
8c8e818c 444
a35471cd 445 ret = read_filename(device, fname, sizeof(fname), FILENAME_ROM0);
fb4ee110 446 if (ret < 0)
447 goto end;
448 printf("ROM filename: %s\n", fname);
449
a35471cd 450 ret = read_filename(device, fname, sizeof(fname), FILENAME_RAM);
fb4ee110 451 if (ret < 0)
452 goto end;
453 printf("SRAM filename: %s\n", fname);
454
a35471cd 455 ret = read_w_counter(device, &counter);
456 if (ret < 0)
457 goto end;
458 printf("flash writes: %u\n", counter);
fb4ee110 459
a35471cd 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);
8c8e818c 464
726b85c8 465end:
8c8e818c 466 release_device(device);
467
726b85c8 468 return ret;
8c8e818c 469}
470