From 0a613c3dc3eb62b88fd4b6822310334f44154b90 Mon Sep 17 00:00:00 2001 From: notaz Date: Fri, 19 Sep 2014 03:51:15 +0300 Subject: [PATCH] mega-usb: allow sending any commands --- mega-usb/Makefile | 5 +- mega-usb/mega-usb.c | 204 +++++++++++++++++++++++++++++++++----------- 2 files changed, 160 insertions(+), 49 deletions(-) diff --git a/mega-usb/Makefile b/mega-usb/Makefile index 5c7aec3..8d5879e 100644 --- a/mega-usb/Makefile +++ b/mega-usb/Makefile @@ -1,4 +1,7 @@ -CFLAGS += -Wall -ggdb -O2 +CFLAGS += -Wall -ggdb +ifndef DEBUG +CFLAGS += -O2 +endif all: mega-usb diff --git a/mega-usb/mega-usb.c b/mega-usb/mega-usb.c index 7217080..affa5c2 100644 --- a/mega-usb/mega-usb.c +++ b/mega-usb/mega-usb.c @@ -1,3 +1,28 @@ +/* + * Tool for USB communication with Mega Everdrive + * Copyright (c) 2013,2014 notaz + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + #define _BSD_SOURCE #include #include @@ -11,7 +36,6 @@ static int setup(int fd) { - speed_t ispeed, ospeed; struct termios tty; int ret; @@ -72,7 +96,7 @@ static int read_from_cart(int fd, void *data, size_t size) } #define send_cmd(fd, cmd) \ - write_to_cart(fd, cmd, sizeof(cmd) - 1) + write_to_cart(fd, cmd, strlen(cmd)) static int read_check_byte(int fd, char expect) { @@ -115,72 +139,156 @@ static int write_with_check(int fd, const void *data, size_t size, char chk) } #define send_cmd_check_k(fd, cmd) \ - write_with_check(fd, cmd, sizeof(cmd) - 1, 'k') + write_with_check(fd, cmd, strlen(cmd), 'k') -int main(int argc, char *argv[]) +static int send_file(int fd, const char *fname, const char *cmd) { - const char *portname = "/dev/ttyUSB0"; char buf[0x10000]; + int retval = -1; + FILE *f = NULL; + size_t blocksz; size_t size; int blocks; - FILE *f; int ret; - int fd; int i; - fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); - if (fd < 0) { - perror("open"); - return 1; + f = fopen(fname, "rb"); + if (f == NULL) + { + fprintf(stderr, "fopen %s: ", fname); + return -1; } - setup(fd); + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + if (size > 0xf00000) { + fprintf(stderr, "size too large: %zd\n", size); + goto out; + } - send_cmd_check_k(fd, " *T"); + if (cmd[1] == 'f') + blocksz = 1024; + else + blocksz = sizeof(buf); - if (argv[1] != NULL) - { - f = fopen(argv[1], "rb"); - if (f == NULL) - { - perror("fopen"); - return 1; - } - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - if (size > 0xf00000) { - fprintf(stderr, "size too large: %zd\n", size); - return 1; + blocks = (size + blocksz - 1) / blocksz; + + send_cmd(fd, cmd); + ret = write_with_check(fd, &blocks, 1, 'k'); + if (ret) + return ret; + + // at this point, 'd' will arrive even if we don't + // write any more data, what's the point of that? + // probably a timeout? + + for (i = 0; i < blocks; i++) { + ret = fread(buf, 1, blocksz, f); + if (i != blocks - 1 && ret != blocksz) { + fprintf(stderr, "failed to read block %d/%d\n", + i, blocks); } + if (ret < blocksz) + memset(buf + ret, 0, blocksz - ret); + + write_to_cart(fd, buf, blocksz); + } - blocks = (size + 0xffff) >> 16; - send_cmd(fd, "*g"); - write_with_check(fd, &blocks, 1, 'k'); + ret = read_check_byte(fd, 'd'); + if (ret) + goto out; - // at this point, 'd' will arrive even if we don't - // write any more data, what's the point of that? + retval = 0; +out: + if (f != NULL) + fclose(f); - for (i = 0; i < blocks; i++) { - ret = fread(buf, 1, sizeof(buf), f); - if (i != blocks - 1 && ret != sizeof(buf)) { - fprintf(stderr, "failed to read block %d/%d\n", - i, blocks); - } - if (ret < sizeof(buf)) - memset(buf + ret, 0, sizeof(buf) - ret); + return retval; +} - write_to_cart(fd, buf, sizeof(buf)); - } +static void usage(const char *argv0) +{ + printf("usage:\n" + "%s [-d ] [-f ] command(s)\n" + "known commands for ED OS:\n" + " *g - upload game\n" + " *w - upload and start OS\n" + " *o - upload and start OS\n" + " *f - upload (and start?) FPGA firmware\n" + " *s - start last ROM (same as pressing start in menu)\n" + " *r - run SDRAM contents as mapper x:\n" + " s - sms, m - md, o - OS app, c - cd BIOS, M - md10m\n" + "upload commands must be followed by -f \n" + , argv0); + exit(1); +} + +static void invarg(int argc, char *argv[], int arg) +{ + if (arg < argc) + fprintf(stderr, "invalid arg %d: \"%s\"\n", arg, argv[arg]); + else + fprintf(stderr, "missing required argument %d\n", arg); + exit(1); +} + +int main(int argc, char *argv[]) +{ + const char *portname = "/dev/ttyUSB0"; + const char *pending_cmd = NULL; + int ret = -1; + int arg = 1; + int fd; + + if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) + usage(argv[0]); - ret = read_check_byte(fd, 'd'); - if (ret) - return 1; + if (!strcmp(argv[arg], "-d")) { + arg++; + if (argv[arg] != NULL) + portname = argv[arg]; + else + invarg(argc, argv, arg); + arg++; + } - send_cmd_check_k(fd, "*rm"); + fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); + if (fd < 0) { + fprintf(stderr, "open %s: ", portname); + perror(""); + return 1; } - printf("all ok\n"); + setup(fd); - return 0; + send_cmd_check_k(fd, " *T"); + + for (; arg < argc; arg++) { + if (!strcmp(argv[arg], "-f")) { + arg++; + if (argv[arg] == NULL) + invarg(argc, argv, argc); + if (pending_cmd == NULL) + // assume game upload + pending_cmd = "*g"; + + ret = send_file(fd, argv[arg], pending_cmd); + if (ret) + return ret; + + pending_cmd = NULL; + continue; + } + if (argv[arg + 1] && !strcmp(argv[arg + 1], "-f")) { + /* we'll avoid sending command if there are + * problems with specified file */ + pending_cmd = argv[arg]; + continue; + } + + ret = send_cmd_check_k(fd, argv[arg]); + } + + return ret; } -- 2.39.2