2 * Tool for USB communication with Mega Everdrive
3 * Copyright (c) 2013,2014 notaz
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 #include <sys/types.h>
34 #include <arpa/inet.h> // hton
38 static int setup(int fd)
43 memset(&tty, 0, sizeof(tty));
45 ret = tcgetattr(fd, &tty);
52 tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
53 | INLCR | IGNCR | ICRNL | IXON);
54 tty.c_oflag &= ~OPOST;
55 tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
56 tty.c_cflag &= ~(CSIZE | PARENB);
60 //tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
62 ret = tcsetattr(fd, TCSANOW, &tty);
71 static int write_to_cart(int fd, const void *data, size_t size)
75 ret = write(fd, data, size);
77 fprintf(stderr, "write %d/%zd: ", ret, size);
86 static int read_from_cart(int fd, void *data, size_t size)
92 ret = read(fd, (char *)data + got, size - got);
94 fprintf(stderr, "read %d %zd/%zd: ",
106 #define send_cmd(fd, cmd) \
107 write_to_cart(fd, cmd, strlen(cmd))
109 static int read_check_byte(int fd, char expect)
114 ret = read_from_cart(fd, &r, 1);
116 fprintf(stderr, "missing response, need '%c'\n", expect);
121 fprintf(stderr, "unexpected response: '%c', need '%c'\n",
129 static int write_with_check(int fd, const void *data, size_t size, char chk)
133 ret = write_to_cart(fd, data, size);
137 ret = read_check_byte(fd, chk);
140 fprintf(stderr, "data sent: '%16s'\n",
149 #define send_cmd_check_k(fd, cmd) \
150 write_with_check(fd, cmd, strlen(cmd), 'k')
152 static int send_file(int fd, const char *fname, const char *cmd)
163 f = fopen(fname, "rb");
165 fprintf(stderr, "fopen %s: ", fname);
170 fseek(f, 0, SEEK_END);
172 fseek(f, 0, SEEK_SET);
173 if (size > 0xf00000) {
174 fprintf(stderr, "size too large: %zd\n", size);
181 blocksz = sizeof(buf);
183 blocks = (size + blocksz - 1) / blocksz;
186 ret = write_with_check(fd, &blocks, 1, 'k');
190 // at this point, 'd' will arrive even if we don't
191 // write any more data, what's the point of that?
192 // probably a timeout?
194 for (i = 0; i < blocks; i++) {
195 ret = fread(buf, 1, blocksz, f);
196 if (i != blocks - 1 && ret != blocksz) {
197 fprintf(stderr, "failed to read block %d/%d\n",
201 memset(buf + ret, 0, blocksz - ret);
203 write_to_cart(fd, buf, blocksz);
206 ret = read_check_byte(fd, 'd');
218 static int recv_file(int fd, const char *fname, unsigned int addr,
230 f = fopen(fname, "wb");
232 fprintf(stderr, "fopen %s: ", fname);
239 fprintf(stderr, "OOM?\n");
245 addr_size.addr = htonl(addr);
246 addr_size.size = htonl(size);
247 ret = write_with_check(fd, &addr_size, sizeof(addr_size), 'k');
251 ret = read_from_cart(fd, buf, size);
255 ret = fwrite(buf, 1, size, f);
257 fprintf(stderr, "fwrite %d/%d: ", ret, size);
271 static void usage(const char *argv0)
274 "%s [-d <ttydevice>] [-f <file>] command(s)\n"
275 "known commands for ED OS:\n"
276 " *g - upload game\n"
277 " *w - upload and start OS\n"
278 " *o - upload and start OS\n"
279 " *f - upload (and start?) FPGA firmware\n"
280 " *s - start last ROM (same as pressing start in menu)\n"
281 " *r<x> - run SDRAM contents as mapper x:\n"
282 " s - sms, m - md, o - OS app, c - cd BIOS, M - md10m\n"
283 "upload commands must be followed by -f <file>\n"
284 "custom OS commands:\n"
285 " *xd <addr> <size> <file> - download memory\n"
290 static void invarg(int argc, char *argv[], int arg)
293 fprintf(stderr, "invalid arg %d: \"%s\"\n", arg, argv[arg]);
295 fprintf(stderr, "missing required argument %d\n", arg);
299 int main(int argc, char *argv[])
301 const char *portname = "/dev/ttyUSB0";
302 const char *pending_cmd = NULL;
307 if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
310 if (!strcmp(argv[arg], "-d")) {
312 if (argv[arg] != NULL)
313 portname = argv[arg];
315 invarg(argc, argv, arg);
319 fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
321 fprintf(stderr, "open %s: ", portname);
328 send_cmd_check_k(fd, " *T");
330 for (; arg < argc; arg++) {
331 if (!strcmp(argv[arg], "-f")) {
333 if (argv[arg] == NULL)
334 invarg(argc, argv, argc);
335 if (pending_cmd == NULL)
336 // assume game upload
339 ret = send_file(fd, argv[arg], pending_cmd);
346 if (argv[arg + 1] && !strcmp(argv[arg + 1], "-f")) {
347 /* we'll avoid sending command if there are
348 * problems with specified file */
349 pending_cmd = argv[arg];
352 /* custom OS commands */
353 if (!strcmp(argv[arg], "*xd")) {
354 unsigned int addr, size;
356 invarg(argc, argv, argc);
357 addr = strtoul(argv[++arg], NULL, 0);
358 size = strtoul(argv[++arg], NULL, 0);
359 ret = recv_file(fd, argv[++arg], addr, size);
367 ret = send_cmd_check_k(fd, argv[arg]);